Actions.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. #from __future__ import unicode_literals
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. from PyQt4.QtCore import Qt, QLineF, QPointF, QRectF, SIGNAL
  5. from PyQt4.QtGui import QPixmap, QCursor, QToolButton, QIcon, QGraphicsLineItem, \
  6. QPen, QColor, QGraphicsEllipseItem, QGraphicsPolygonItem, QPolygonF, QDialog, \
  7. QApplication
  8. import AEtoile
  9. from lib.dialogues import dmVol
  10. from lib.ui.ecran_attaqueZone import Ui_zone_fenetre
  11. import regles
  12. class Action(object):
  13. """action effectuee par un combattant sur le plateau de jeu"""
  14. def __init__(self):
  15. self.plateau = None
  16. self._num = None #no du pion actif
  17. self._nom = "Action"
  18. self._coordCible = None #coord de la case ciblee par le curseur
  19. self._cible = None #cible (case ou pion)
  20. self._sourceCurseur = ""
  21. self._nomBouton = ""
  22. self._enCours = False
  23. self._desactivationDemandee = False
  24. #decorateur
  25. def autorise(f):
  26. def _autorise(self, *args):
  27. def fVide(*args):
  28. pass
  29. retour = fVide
  30. if not self._desactivationDemandee:
  31. retour = f
  32. retour(self, *args)
  33. return _autorise
  34. def nom(self):
  35. return self._nom
  36. def typeAtt(self):
  37. return ""
  38. def description(self):
  39. """description de l'action en cours, pour le panneau d'action"""
  40. return ""
  41. def activer(self, plateau, numPion):
  42. self.plateau = plateau
  43. self._num = numPion
  44. self.activerCurseur()
  45. self.creerItemsGraphiques()
  46. self._enCours = True
  47. self.majPanneauAction()
  48. def majCoordCible(self, coord):
  49. """met a jour les coordonnees de la cible,
  50. cad la case actuellement survolee par la souris"""
  51. if self.plateau.geo.coordonneesValides(coord):
  52. self._coordCible = coord
  53. self.maj()
  54. def desactiver(self):
  55. self._desactivationDemandee = True
  56. self.afficherCibles(False)
  57. self.detruireItemsGraphiques()
  58. self.desactiverCurseur()
  59. self._enCours = False
  60. self.majPanneauAction()
  61. def enCours(self):
  62. return self._enCours
  63. def valider(self):
  64. #envoyer signal
  65. self.envoiSignal()
  66. self.desactiver()
  67. def estValide(self):
  68. return True
  69. def maj(self):
  70. pass
  71. def acteur(self):
  72. return self.plateau.pions[self._num]
  73. def coordActeur(self):
  74. return self.acteur().position
  75. def activerCurseur(self):
  76. if len(self._sourceCurseur) > 0:
  77. curseurPix = QPixmap(self._sourceCurseur)
  78. if not curseurPix.isNull():
  79. curseur = QCursor(curseurPix, 0, curseurPix.height())
  80. self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)
  81. def desactiverCurseur(self):
  82. self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  83. def majPanneauAction(self):
  84. for bouton in self.plateau.fenetre.ui.page_act.findChildren(QToolButton):
  85. if self._enCours:
  86. if bouton.objectName() == self._nomBouton:
  87. bouton.setChecked(True)
  88. else:
  89. bouton.setVisible(False)
  90. else:
  91. bouton.setVisible(True)
  92. bouton.setChecked(False)
  93. self.plateau.fenetre.ui.act_description.setVisible(self._enCours)
  94. self.plateau.fenetre.ui.act_valider.setVisible(self._enCours)
  95. if self._enCours:
  96. self.plateau.fenetre.ui.act_description.majTexte(self.description())
  97. #manipulation des items graphiques
  98. def creerItemsGraphiques(self):
  99. pass
  100. def majItemsGraphiques(self):
  101. pass
  102. def detruireItemsGraphiques(self):
  103. pass
  104. #affichage des cibles
  105. def afficherCibles(self, actif):
  106. pass
  107. #envoi du signal en cas de validation
  108. def envoiSignal(self):
  109. pass
  110. def pivoter(self, modRotation):
  111. pass
  112. class Deplacement(Action):
  113. ### a completer avec des icones de deplacement,
  114. #la prise en compte de la nage et de l'escalade
  115. #et le calcul du cout de deplacement
  116. def __init__(self):
  117. super(Deplacement, self).__init__()
  118. self._nom = "Deplacement"
  119. self._chemin = [] #liste des coord des cases a traverser
  120. self._chercheurChemin = None
  121. self._cout = 0 #cout en points de dep
  122. self._zCible = 0
  123. self.cible_aConfirmer = None
  124. self._sourceCurseur = ""
  125. self._nomBouton = "act_deplacement"
  126. def typeAtt(self):
  127. return "dep"
  128. def description(self):
  129. txt = " - {} - \n".format(self.nom().upper())
  130. if not self.cible_aConfirmer:
  131. txt += " Cliquez sur la case de destination\n"
  132. txt += " (Maintenez [MAJ] pour changer l'altitude cible)\n"
  133. txt += " (Maintenez [MAJ] pour changer l'altitude cible)\n"
  134. txt += " (Maintenez [MAJ] pour changer l'altitude cible)\n"
  135. else:
  136. txt += " Destination: {}\n".format(self.plateau.proj.coord())
  137. if self._zCible != 0: txt += " Altitude de destination: {}\n".format(self._zCible)
  138. txt += self.decrireChemin()
  139. return txt
  140. def activer(self, plateau, numPion):
  141. super(Deplacement, self).activer(plateau, numPion)
  142. self.plateau.proj.creer(self.acteur())
  143. def desactiver(self):
  144. self.plateau.proj.desactiver()
  145. if self._chercheurChemin:
  146. self._chercheurChemin.arreter()
  147. self._chercheurChemin = None
  148. super(Deplacement, self).desactiver()
  149. def valider(self):
  150. if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:
  151. self.cible_aConfirmer = self._coordCible
  152. self.recupZCible()
  153. self.creerChemin()
  154. else:
  155. if self.estValide() and self.plateau.proj.valide():
  156. self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
  157. self.acteur().majZ(self._zCible)
  158. super(Deplacement, self).valider()
  159. def estValide(self):
  160. return len(self._chemin) > 0
  161. def majCoordCible(self, coord):
  162. if coord != self.coordActeur():
  163. super(Deplacement, self).majCoordCible(coord)
  164. def maj(self):
  165. self.plateau.proj.majCoord(self._coordCible)
  166. def pivoter(self, modRotation):
  167. self.plateau.proj.majRotation(modRotation)
  168. def creerChemin(self):
  169. self.afficherCibles(False)
  170. self._chemin = []
  171. self._cout = 0
  172. if self._chercheurChemin:
  173. self._chercheurChemin.arreter()
  174. self._chercheurChemin = None
  175. if self.plateau.cases[self._coordCible].terrain.franchissable and not (self.plateau.cases[self._coordCible].occupant() > 0):
  176. self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible, self.acteur().zR, self._zCible)
  177. self._chemin = self._chercheurChemin.liste()
  178. self.afficherCibles(True)
  179. def decrireChemin(self):
  180. """decrit le chemin emprunte"""
  181. return ""
  182. def afficherCibles(self, actif):
  183. compte = 0 ; coutTotal = 0 ; valide = True
  184. z = self.plateau.cases[self.acteur().position].z1()
  185. for coord, cout in self._chemin:
  186. compte += 1 ; coutTotal += cout
  187. if actif:
  188. if int(coutTotal) > self.acteur().pM(): valide = False
  189. dz = self.plateau.cases[coord].z1() - z
  190. self.plateau.cases[coord].majAffichageDeplacement(compte, valide, dz)
  191. else:
  192. self.plateau.cases[coord].majAffichageDeplacement(0)
  193. z = self.plateau.cases[coord].z1()
  194. def envoiSignal(self):
  195. coutTotal = 0
  196. for coord, cout in self._chemin:
  197. coutTotal += cout
  198. print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
  199. def recupZCible(self):
  200. self._zCible = self.acteur().zR
  201. class Vol(Deplacement):
  202. """idem que Deplacement, mais affiche en plus la boite de dialogue Vol
  203. (et n'utilise pas le meme algo de deplacement?)"""
  204. def __init__(self):
  205. super(Vol, self).__init__()
  206. self._nom = "Deplacement (vol)"
  207. self._zCible = 0
  208. self._nomBouton = "pi_vol"
  209. def description(self):
  210. txt = " - {} - \n".format(self.nom().upper())
  211. return txt
  212. def typeAtt(self):
  213. return "vol"
  214. def recupZCible(self):
  215. maxi = ((self.plateau.zP - self.acteur().h) if self.plateau.zP else None)
  216. nouveauZ = dmVol(self.acteur().zR, maxi)
  217. self._zCible = nouveauZ
  218. class Attaque(Action):
  219. """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
  220. def __init__(self):
  221. super(Attaque, self).__init__()
  222. self._nom = "Attaque"
  223. self._icone = ""
  224. self._portee = 1 #portee max en cases
  225. self._rayon = 0
  226. self._pionCible = None
  227. self._attributs = regles.listeAttributsAttaques()
  228. self._notes = ""
  229. def typeAtt(self):
  230. return "att"
  231. def description(self):
  232. return ""
  233. def nom(self):
  234. return self._nom
  235. def majNom(self, nom):
  236. if len(str(nom)) > 0:
  237. self._nom = nom
  238. def portee(self):
  239. return self._portee
  240. def majPortee(self, portee):
  241. try:
  242. ent = int(portee)
  243. if ent > 0:
  244. if ent >= 1000: ent = 999
  245. self._portee = ent
  246. except:
  247. pass
  248. def rayon(self):
  249. return self._rayon
  250. def modifierRayon(self, val):
  251. if self._rayon < 30: rayon = self._rayon + val
  252. self.majRayon(rayon)
  253. def majRayon(self, rayon):
  254. try:
  255. ent = int(rayon)
  256. if ent > 0:
  257. if ent >= 100: ent = 99
  258. self._rayon = ent
  259. except:
  260. pass
  261. def majAttribut(self, nom, nouvelleVal):
  262. if nom in self._attributs:
  263. if regles.attributAttaque(nom).controler(nouvelleVal):
  264. self._attributs[nom] = nouvelleVal
  265. def majAttributs(self, dicoAttributs):
  266. self._attributs = dicoAttributs
  267. def attributs(self):
  268. return self._attributs
  269. def notes(self):
  270. return self._notes
  271. def majNotes(self, notes):
  272. #on limite a 400 le nombre de caracteres
  273. notes = str(notes)
  274. self._notes = notes[0:400]
  275. def icone(self):
  276. return QIcon(self._icone)
  277. def ldmValide(self):
  278. x0, y0 = self.acteur().position
  279. z0 = self.acteur().zA() + self.acteur().h
  280. origine = (x0,y0,z0)
  281. #on essaie de cibler toutes les cases de la hauteur de la cible si c'est un pion
  282. cibles = []
  283. x1, y1 = self._coordCible
  284. if self._pionCible:
  285. for zA in self.plateau.cases[self._coordCible].hOcc(self._pionCible.numero):
  286. cibles.append( (x1, y1, zA) )
  287. else:
  288. cibles = [(x1, y1, self.plateau.cases[self._coordCible].z0)]
  289. for cible in cibles:
  290. if self.plateau.ldmValide(origine, cible): return True
  291. return False
  292. class Cac(Attaque):
  293. """attaque au corps a corps"""
  294. def __init__(self):
  295. super(Cac, self).__init__()
  296. self._nom = "Attaque au corps-à-corps"
  297. self._sourceCurseur = ""
  298. self._nomBouton = "act_attaqueCac"
  299. self._icone = "img\\curseurEpee.png"
  300. def typeAtt(self):
  301. return "cac"
  302. def desactiver(self):
  303. self.afficherCibles(False)
  304. super(Cac, self).desactiver()
  305. def description(self):
  306. txt = " - {} - \n".format(self.nom().upper())
  307. txt += " Cliquez sur une cible a portee"
  308. return txt
  309. def valider(self):
  310. if self.estValide() and self._pionCible:
  311. super(Cac, self).valider()
  312. def maj(self):
  313. self.afficherCibles(False)
  314. pionCible = self.plateau.pions[self.plateau.cases[self._coordCible].occupant()]
  315. if pionCible != None and pionCible != self.plateau.pionSelectionne():
  316. self._pionCible = pionCible
  317. else:
  318. self._pionCible = None
  319. self.afficherCibles(True)
  320. def estValide(self):
  321. return (self._coordCible in self.plateau.geo.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True))
  322. def afficherCibles(self, actif):
  323. if self._pionCible:
  324. self._pionCible.estCibleAttaque(actif, self.estValide())
  325. def envoiSignal(self):
  326. print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId())
  327. class Distance(Attaque):
  328. """attaque a distance"""
  329. def __init__(self):
  330. super(Distance, self).__init__()
  331. self._nom = "Attaque à distance"
  332. self._itemLigne = None
  333. self._sourceCurseur = ""
  334. self._nomBouton = "act_attaqueDist"
  335. self._icone = ":/interface/16/ressource/arc_16.png"
  336. def typeAtt(self):
  337. return "dist"
  338. def description(self):
  339. txt = " - {} - \n".format(self.nom().upper())
  340. txt += " Cliquez sur une cible visible"
  341. return txt
  342. def majCoordCible(self, coord):
  343. if self._pionCible:
  344. self._pionCible.estCibleAttaque(False, self.estValide())
  345. if self._coordCible in self.plateau.cases:
  346. self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
  347. super(Distance, self).majCoordCible(coord)
  348. def valider(self):
  349. if self.estValide() and self._pionCible != None:
  350. super(Distance, self).valider()
  351. def maj(self):
  352. """met a jour la ligne de mire representant l'attaque a distance"""
  353. self.afficherCibles(False)
  354. numCible = self.plateau.cases[self._coordCible].occupant()
  355. pionCible = self.plateau.pions[numCible]
  356. self.majItemsGraphiques()
  357. if pionCible != None and pionCible != self.plateau.pionSelectionne():
  358. self._pionCible = pionCible
  359. else:
  360. self._pionCible = None
  361. self.afficherCibles(True)
  362. def estValide(self):
  363. return self.ldmValide()
  364. def afficherCibles(self, actif):
  365. valide = self.estValide() if actif else True
  366. if self._pionCible:
  367. self._pionCible.estCibleAttaque(actif, valide)
  368. else:
  369. #si pas de pion vise, on affiche la case cible comme visee
  370. self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, valide)
  371. def creerItemsGraphiques(self):
  372. self._itemLigne = itemLdm()
  373. self._itemLigne.prepareGeometryChange()
  374. self.plateau.addItem(self._itemLigne)
  375. def majItemsGraphiques(self):
  376. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  377. self.plateau.cases[self._coordCible].centreGraphique))
  378. def detruireItemsGraphiques(self):
  379. if self._itemLigne != None:
  380. self._itemLigne.prepareGeometryChange()
  381. self.plateau.removeItem(self._itemLigne)
  382. self._itemLigne = None
  383. def envoiSignal(self):
  384. print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId())
  385. class Zone(Attaque):
  386. """attaque de zone de base"""
  387. def __init__(self):
  388. super(Zone, self).__init__()
  389. self._nom = "Attaque de zone"
  390. self._itemLigne = None
  391. self._itemCible = None
  392. self._casesCibles = []
  393. self._sourceCurseur = ""
  394. self._nomBouton = "act_attaqueZone"
  395. self._icone = ":/interface/16/ressource/baguette_16.png"
  396. def typeAtt(self):
  397. return "zone"
  398. def valider(self):
  399. if self.estValide() and len(self._casesCibles) > 0:
  400. super(Zone, self).valider()
  401. # def desactiver(self):
  402. # self.detruireItemsGraphiques()
  403. # super(Zone, self).desactiver()
  404. def description(self):
  405. txt = " - {} - \n".format(self.nom().upper())
  406. txt += " Cliquez sur une cible visible"
  407. return txt
  408. def maj(self):
  409. """maj la forme de l'attaque de zone et les items cibles"""
  410. self.afficherCibles(False)
  411. self.majItemsGraphiques()
  412. self.majCibles()
  413. self.afficherCibles(True)
  414. def afficherCibles(self, actif):
  415. for coord in self._casesCibles:
  416. x = coord[0] ; y = coord[1]
  417. zA = 0 if len(coord) == 2 else coord[2]
  418. occupant = self.plateau.cases[(x, y)].occupant(zA)
  419. if occupant:
  420. pion = self.plateau.pions[occupant]
  421. pion.estCibleAttaque(actif)
  422. else:
  423. self.plateau.cases[(x, y)].majEstCibleCurseur(actif)
  424. def listePionsCibles(self):
  425. retour = []
  426. for coord in self._casesCibles:
  427. z = 0 if len(coord) == 2 else coord[2]
  428. if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
  429. pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
  430. if not pion in retour:
  431. retour.append(pion)
  432. return retour
  433. def creerItemsGraphiques(self):
  434. self._itemLigne = QGraphicsLineItem()
  435. self._itemLigne.setPen(QPen(QColor("black")))
  436. self._itemLigne.prepareGeometryChange()
  437. self.plateau.addItem(self._itemLigne)
  438. self._itemCible = QGraphicsEllipseItem()
  439. self._itemCible.setPen(QPen(QColor("black")))
  440. self._itemCible.prepareGeometryChange()
  441. self.plateau.addItem(self._itemCible)
  442. def detruireItemsGraphiques(self):
  443. if self._itemCible != None:
  444. self._itemCible.prepareGeometryChange()
  445. self.plateau.removeItem(self._itemCible)
  446. self._itemCible = None
  447. if self._itemLigne != None:
  448. self._itemLigne.prepareGeometryChange()
  449. self.plateau.removeItem(self._itemLigne)
  450. self._itemLigne = None
  451. def envoiSignal(self):
  452. touches = ""
  453. for pion in self.listePionsCibles():
  454. touches += "{}, ".format(pion.txtId())
  455. touches = touches[:-2]
  456. print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
  457. class Ligne(Zone):
  458. """attaque de zone de forme lineaire"""
  459. def __init__(self):
  460. super(Ligne, self).__init__()
  461. self._nom = "Attaque de zone: ligne"
  462. def typeAttZone(self):
  463. return "ligne"
  464. def majItemsGraphiques(self):
  465. if not self._desactivationDemandee:
  466. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  467. self.plateau.cases[self._coordCible].centreGraphique))
  468. def majCibles(self):
  469. """met a jour la liste des cases cibles"""
  470. if not self._desactivationDemandee:
  471. self._casesCibles = []
  472. x1, y1 = self.acteur().position
  473. z1 = self.acteur().zA() + self.acteur().h
  474. x2, y2 = self._coordCible
  475. occupant = self.plateau.cases[(x2, y2)].occupant()
  476. z2 = self.plateau.cases[(x2, y2)].zA(occupant) if occupant else self.plateau.cases[(x2, y2)].z0
  477. for coord in self.plateau.geo.ligne((x1, y1, z1), (x2, y2, z2)):
  478. if coord != (x1, y1, z1):
  479. self._casesCibles.append(coord)
  480. if not self.estValide(): self._casesCibles = []
  481. def estValide(self):
  482. """la ligne est valide si toutes les cases cibles ne sont pas occupees par autre chose que des combattants"""
  483. for x, y, zA in self._casesCibles:
  484. occupant = self.plateau.cases[(x, y)].occupant(zA)
  485. if occupant:
  486. if occupant <= 0: return False
  487. return True
  488. class Disque(Zone):
  489. """attaque de zone de forme circulaire"""
  490. def __init__(self):
  491. super(Disque, self).__init__()
  492. self._nom = "Attaque de zone (disque)"
  493. #decorateur
  494. def autorise(f):
  495. def _autorise(self, *args):
  496. def fVide(*args):
  497. pass
  498. retour = fVide
  499. if not self._desactivationDemandee:
  500. retour = f
  501. retour(self, *args)
  502. return _autorise
  503. def typeAttZone(self):
  504. return "disque"
  505. def activer(self, plateau, numPion):
  506. super(Disque, self).activer(plateau, numPion)
  507. @autorise
  508. def majCoordCible(self, coord):
  509. if self._coordCible in self.plateau.cases:
  510. self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
  511. super(Disque, self).majCoordCible(coord)
  512. @autorise
  513. def majCibles(self):
  514. occupant = self.plateau.cases[self._coordCible].occupant()
  515. x, y = self._coordCible
  516. z = self.plateau.pions[occupant].zA() if occupant else self.plateau.cases[self._coordCible].z0
  517. self._casesCibles = self.plateau.geo.zone3d( (x, y, z) , self._rayon)
  518. def afficherCibles(self, actif):
  519. if self.estValide():
  520. super(Disque, self).afficherCibles(actif)
  521. else:
  522. super(Disque, self).afficherCibles(False)
  523. self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
  524. @autorise
  525. def majRayon(self, val):
  526. self._rayon = val
  527. if self.plateau: self.maj()
  528. @autorise
  529. def majItemsGraphiques(self):
  530. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  531. self.plateau.cases[self._coordCible].centreGraphique))
  532. if self.estValide():
  533. rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self._rayon)
  534. if rect != None:
  535. self._itemCible.setRect(rect)
  536. self._itemCible.setVisible(self.estValide() and rect != None)
  537. def estValide(self):
  538. return self.ldmValide()
  539. @autorise
  540. def rectEllipseCirculaire(self, centre, rayon):
  541. """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
  542. attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
  543. verticalement le nombre de cases demandees"""
  544. rect = None
  545. if rayon > 0:
  546. p1 = QPointF((centre.x() - (rayon * self.plateau.hCase)), (centre.y() - (rayon * self.plateau.hCase)))
  547. p2 = QPointF((centre.x() + (rayon * self.plateau.hCase)), (centre.y() + (rayon * self.plateau.hCase)))
  548. if p1 != p2:
  549. rect = QRectF()
  550. rect.setTopLeft(p1)
  551. rect.setBottomRight(p2)
  552. return rect
  553. class Cone(Zone):
  554. """attaque de zone de forme conique"""
  555. def __init__(self):
  556. super(Cone, self).__init__()
  557. self._nom = "Attaque de zone: cône"
  558. def typeAttZone(self):
  559. return "cone"
  560. def description(self):
  561. return "Attaque à de zone (cone)"
  562. def majCibles(self):
  563. x0, y0 = self.acteur().position
  564. z0 = self.acteur().zA() + self.acteur().h
  565. x1, y1 = self._coordCible
  566. occupant = self.plateau.cases[self._coordCible].occupant()
  567. z1 = self.plateau.pions[occupant].zA() if occupant else self.plateau.cases[self._coordCible].z0
  568. cone = self.plateau.geo.cone3d( (x0, y0, z0), (x1, y1, z1) )
  569. if (x0, y0, z0) in cone: cone.remove((x0, y0, z0))
  570. self._casesCibles = cone
  571. def creerItemsGraphiques(self):
  572. self._itemCible = QGraphicsPolygonItem()
  573. self._itemCible.setPen(QPen(QColor("black")))
  574. self._itemCible.prepareGeometryChange()
  575. self.plateau.addItem(self._itemCible)
  576. def majItemsGraphiques(self):
  577. self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  578. self.plateau.cases[self._coordCible].centreGraphique))
  579. def polygoneCone(self, point1, point2):
  580. """renvoie le polygone du cone defini par les deux points (origine, distance)"""
  581. ligne1 = QLineF(point1, point2)
  582. longueur = ligne1.length()
  583. ligne1.setAngle(ligne1.angle() + 22.5)
  584. ligne1.setLength(1.1547*longueur)
  585. ligne2 = QLineF(point1, point2)
  586. ligne2.setAngle(ligne2.angle() - 22.5)
  587. ligne2.setLength(1.1547*longueur)
  588. polygone = QPolygonF()
  589. polygone.append(point1)
  590. polygone.append(ligne1.p2())
  591. polygone.append(ligne2.p2())
  592. return polygone
  593. def itemLdm():
  594. """retourne l'item graphique utilise pour les lignes de mire"""
  595. item = QGraphicsLineItem()
  596. item.setZValue(100)
  597. pinceau = QPen()
  598. pinceau.setColor(QColor(249, 249, 249))
  599. pinceau.setStyle(Qt.DashDotLine)
  600. pinceau.setWidth(6)
  601. item.setPen(pinceau)
  602. return item
  603. def choisirAttaqueZone():
  604. """affiche la boite de dialogue permettant un choix de la forme de l'attaque de zone"""
  605. fen = EcranAttaqueZone()
  606. fen.show()
  607. r = fen.exec_()
  608. return fen.resultat() if r == 1 else None
  609. class EcranAttaqueZone(QDialog):
  610. """boite de dialogue de parametrage de l'attaque de zone"""
  611. def __init__(self, parent=None):
  612. super (EcranAttaqueZone, self).__init__()
  613. self.createWidgets()
  614. def createWidgets(self):
  615. """construction de l'interface"""
  616. self.ui = Ui_zone_fenetre()
  617. self.ui.setupUi(self)
  618. self.connect(self.ui.zone_ligne, SIGNAL("clicked()"), self.ligne, Qt.UniqueConnection)
  619. self.connect(self.ui.zone_disque, SIGNAL("clicked()"), self.disque, Qt.UniqueConnection)
  620. self.connect(self.ui.zone_cone, SIGNAL("clicked()"), self.cone, Qt.UniqueConnection)
  621. self.setStyleSheet("DmLabel:hover {background: rgb(255, 255, 255)};")
  622. def resultat(self):
  623. return self._resultat
  624. def ligne(self):
  625. self._resultat = Ligne
  626. self.done(1)
  627. def disque(self):
  628. self._resultat = Disque
  629. self.done(1)
  630. def cone(self):
  631. self._resultat = Cone
  632. self.done(1)
  633. if __name__ == "__main__":
  634. app = QApplication(sys.argv)
  635. res = choisirAttaqueZone()
  636. print res
  637. exit()