Actions.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  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. import br
  10. from lib.dialogues import dmVol
  11. from lib.ui.ecran_attaqueZone import Ui_zne_fenetre
  12. import regles
  13. class Action(object):
  14. """action effectuee par un combattant sur le plateau de jeu"""
  15. def __init__(self):
  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.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._attributs = regles.listeAttributsAttaques()
  227. self._notes = ""
  228. def typeAtt(self):
  229. return "att"
  230. def description(self):
  231. return ""
  232. def nom(self):
  233. return self._nom
  234. def majNom(self, nom):
  235. if len(str(nom)) > 0:
  236. self._nom = nom
  237. def portee(self):
  238. return self._portee
  239. def majPortee(self, portee):
  240. try:
  241. ent = int(portee)
  242. if ent > 0:
  243. if ent >= 1000: ent = 999
  244. self._portee = ent
  245. except:
  246. pass
  247. def rayon(self):
  248. return self._rayon
  249. def majRayon(self, rayon):
  250. try:
  251. ent = int(rayon)
  252. if ent > 0:
  253. if ent >= 100: ent = 99
  254. self._rayon = ent
  255. except:
  256. pass
  257. def majAttribut(self, nom, nouvelleVal):
  258. if nom in self._attributs:
  259. if regles.attributAttaque(nom).controler(nouvelleVal):
  260. self._attributs[nom] = nouvelleVal
  261. def majAttributs(self, dicoAttributs):
  262. self._attributs = dicoAttributs
  263. def attributs(self):
  264. return self._attributs
  265. def notes(self):
  266. return self._notes
  267. def majNotes(self, notes):
  268. #on limite a 400 le nombre de caracteres
  269. notes = str(notes)
  270. self._notes = notes[0:400]
  271. def icone(self):
  272. return QIcon(self._icone)
  273. def ldmValide(self):
  274. x0, y0 = self.acteur().position
  275. z0 = self.plateau.cases[self.acteur().position].zA(self._num) + self.acteur().h
  276. origine = (x0,y0,z0)
  277. #on essaie de cibler toutes les cases de la hauteur de la cible si c'est un pion
  278. cibles = []
  279. x1, y1 = self._coordCible
  280. if self._pionCible:
  281. for zA in self.plateau.cases[self._coordCible].hOcc(self._pionCible.numero):
  282. cibles.append( (x1, y1, zA) )
  283. else:
  284. cibles = [(x1, y1, self.plateau.cases[self._coordCible].z0)]
  285. for cible in cibles:
  286. if self.plateau.ldmValide(origine, cible): return True
  287. return False
  288. class Cac(Attaque):
  289. """attaque au corps a corps"""
  290. def __init__(self):
  291. super(Cac, self).__init__()
  292. self._nom = "Attaque au corps-à-corps"
  293. self._pionCible = None
  294. self._sourceCurseur = ""
  295. self._nomBouton = "act_attaqueCac"
  296. self._icone = "img\\curseurEpee.png"
  297. def typeAtt(self):
  298. return "cac"
  299. def desactiver(self):
  300. self.afficherCibles(False)
  301. super(Cac, self).desactiver()
  302. def description(self):
  303. txt = " - {} - \n".format(self.nom().upper())
  304. txt += " Cliquez sur une cible a portee"
  305. return txt
  306. def valider(self):
  307. if self.estValide() and self._pionCible:
  308. super(Cac, self).valider()
  309. def maj(self):
  310. self.afficherCibles(False)
  311. pionCible = self.plateau.cases[self._coordCible].occupant()
  312. if pionCible != None and pionCible != self.plateau.pionSelectionne():
  313. self._pionCible = pionCible
  314. else:
  315. self._pionCible = None
  316. self.afficherCibles(True)
  317. def estValide(self):
  318. return (self._coordCible in self.plateau.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True))
  319. def afficherCibles(self, actif):
  320. if self._pionCible:
  321. self._pionCible.estCibleAttaque(actif, self.estValide())
  322. def envoiSignal(self):
  323. print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId())
  324. class Distance(Attaque):
  325. """attaque a distance"""
  326. def __init__(self):
  327. super(Distance, self).__init__()
  328. self._nom = "Attaque à distance"
  329. self._itemLigne = None
  330. self._pionCible = None
  331. self._sourceCurseur = ""
  332. self._nomBouton = "act_attaqueDist"
  333. self._icone = ":/interface/16/ressource/arc_16.png"
  334. def typeAtt(self):
  335. return "dist"
  336. def description(self):
  337. txt = " - {} - \n".format(self.nom().upper())
  338. txt += " Cliquez sur une cible visible"
  339. return txt
  340. def majCoordCible(self, coord):
  341. if self._pionCible:
  342. self._pionCible.estCibleAttaque(False, self.estValide())
  343. if self._coordCible in self.plateau.cases:
  344. self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
  345. super(Distance, self).majCoordCible(coord)
  346. def valider(self):
  347. if self.estValide() and self._pionCible != None:
  348. super(Distance, self).valider()
  349. def maj(self):
  350. """met a jour la ligne de mire representant l'attaque a distance"""
  351. self.afficherCibles(False)
  352. numCible = self.plateau.cases[self._coordCible].occupant()
  353. pionCible = self.plateau.pions[numCible]
  354. self.majItemsGraphiques()
  355. if pionCible != None and pionCible != self.plateau.pionSelectionne():
  356. self._pionCible = pionCible
  357. else:
  358. self._pionCible = None
  359. self.afficherCibles(True)
  360. def estValide(self):
  361. return self.ldmValide()
  362. def afficherCibles(self, actif):
  363. valide = self.estValide() if actif else True
  364. if self._pionCible:
  365. self._pionCible.estCibleAttaque(actif, valide)
  366. else:
  367. #si pas de pion vise, on affiche la case cible comme visee
  368. self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, valide)
  369. def creerItemsGraphiques(self):
  370. self._itemLigne = itemLdm()
  371. self._itemLigne.prepareGeometryChange()
  372. self.plateau.addItem(self._itemLigne)
  373. def majItemsGraphiques(self):
  374. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  375. self.plateau.cases[self._coordCible].centreGraphique))
  376. def detruireItemsGraphiques(self):
  377. if self._itemLigne != None:
  378. self._itemLigne.prepareGeometryChange()
  379. self.plateau.removeItem(self._itemLigne)
  380. self._itemLigne = None
  381. def envoiSignal(self):
  382. print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId())
  383. class Zone(Attaque):
  384. """attaque de zone de base"""
  385. def __init__(self):
  386. super(Zone, self).__init__()
  387. self._nom = "Attaque de zone"
  388. self._itemLigne = None
  389. self._itemCible = None
  390. self._casesCibles = []
  391. self._sourceCurseur = ""
  392. self._nomBouton = "act_attaqueZone"
  393. self._icone = ":/interface/16/ressource/baguette_16.png"
  394. def typeAtt(self):
  395. return "zone"
  396. def valider(self):
  397. if self.estValide() and len(self._casesCibles) > 0:
  398. super(Zone, self).valider()
  399. # def desactiver(self):
  400. # self.detruireItemsGraphiques()
  401. # super(Zone, self).desactiver()
  402. def description(self):
  403. txt = " - {} - \n".format(self.nom().upper())
  404. txt += " Cliquez sur une cible visible"
  405. return txt
  406. def maj(self):
  407. """maj la forme de l'attaque de zone et les items cibles"""
  408. self.afficherCibles(False)
  409. self.majItemsGraphiques()
  410. self.majCibles()
  411. self.afficherCibles(True)
  412. def afficherCibles(self, actif):
  413. for coord in self._casesCibles:
  414. self.plateau.cases[(coord[0], coord[1])].majEstCibleCurseur(actif)
  415. z = 0 if len(coord) == 2 else coord[2]
  416. if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
  417. pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
  418. pion.estCibleAttaque(actif)
  419. def listePionsCibles(self):
  420. retour = []
  421. for coord in self._casesCibles:
  422. z = 0 if len(coord) == 2 else coord[2]
  423. if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
  424. pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
  425. if not pion in retour:
  426. retour.append(pion)
  427. return retour
  428. def creerItemsGraphiques(self):
  429. self._itemLigne = QGraphicsLineItem()
  430. self._itemLigne.setPen(QPen(QColor("black")))
  431. self._itemLigne.prepareGeometryChange()
  432. self.plateau.addItem(self._itemLigne)
  433. self._itemCible = QGraphicsEllipseItem()
  434. self._itemCible.setPen(QPen(QColor("black")))
  435. self._itemCible.prepareGeometryChange()
  436. self.plateau.addItem(self._itemCible)
  437. def detruireItemsGraphiques(self):
  438. if self._itemCible != None:
  439. self._itemCible.prepareGeometryChange()
  440. self.plateau.removeItem(self._itemCible)
  441. self._itemCible = None
  442. if self._itemLigne != None:
  443. self._itemLigne.prepareGeometryChange()
  444. self.plateau.removeItem(self._itemLigne)
  445. self._itemLigne = None
  446. def envoiSignal(self):
  447. touches = ""
  448. for pion in self.listePionsCibles():
  449. touches += "{}, ".format(pion.txtId())
  450. touches = touches[:-2]
  451. print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
  452. class Ligne(Zone):
  453. """attaque de zone de forme lineaire"""
  454. def __init__(self):
  455. super(Ligne, self).__init__()
  456. self._nom = "Attaque de zone: ligne"
  457. def typeAttZone(self):
  458. return "ligne"
  459. def majItemsGraphiques(self):
  460. if not self._desactivationDemandee:
  461. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  462. self.plateau.cases[self._coordCible].centreGraphique))
  463. def majCibles(self):
  464. """met a jour la liste des cases cibles"""
  465. if not self._desactivationDemandee:
  466. self._casesCibles = []
  467. x1, y1 = self.acteur().position
  468. z1 = self.acteur().zA() + self.acteur().h
  469. x2, y2 = self._coordCible
  470. if self.plateau.cases[(x2, y2)].estOccupee():
  471. z2 = self.plateau.cases[(x2, y2)].occupant().zA()
  472. else:
  473. z2 = self.plateau.cases[(x2, y2)].z0
  474. for coord in br.ligne((x1, y1, z1), (x2, y2, z2)):
  475. if coord != (x1, y1, z1):
  476. self._casesCibles.append(coord)
  477. if not self.estValide(): self._casesCibles = []
  478. def estValide(self):
  479. """la ligne est valide si toutes les cases cibles ne sont pas occupees par autre chose que des combattants"""
  480. for x, y, zA in self._casesCibles:
  481. if self.plateau.cases[(x, y)].occupant(zA) <= 0: return False
  482. return True
  483. class Disque(Zone):
  484. """attaque de zone de forme circulaire"""
  485. def __init__(self):
  486. super(Disque, self).__init__()
  487. self._nom = "Attaque de zone (disque)"
  488. #decorateur
  489. def autorise(f):
  490. def _autorise(self, *args):
  491. def fVide(*args):
  492. pass
  493. retour = fVide
  494. if not self._desactivationDemandee:
  495. retour = f
  496. retour(self, *args)
  497. return _autorise
  498. def typeAttZone(self):
  499. return "disque"
  500. def activer(self, plateau, numPion):
  501. super(Disque, self).activer(plateau, numPion)
  502. @autorise
  503. def majCoordCible(self, coord):
  504. if self._coordCible in self.plateau.cases:
  505. self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
  506. super(Disque, self).majCoordCible(coord)
  507. @autorise
  508. def majCibles(self):
  509. if self.plateau.cases[self._coordCible].estOccupee():
  510. zCible = self.plateau.cases[self._coordCible].occupant().zA()
  511. else:
  512. zCible = self.plateau.cases[self._coordCible].z0
  513. self._casesCibles = self.plateau.zone3d(self._coordCible, self._rayon, zCible)
  514. def afficherCibles(self, actif):
  515. if self.estValide():
  516. super(Disque, self).afficherCibles(actif)
  517. else:
  518. super(Disque, self).afficherCibles(False)
  519. self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
  520. @autorise
  521. def majRayon(self, val):
  522. self._rayon = val
  523. self.maj()
  524. @autorise
  525. def majItemsGraphiques(self):
  526. self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  527. self.plateau.cases[self._coordCible].centreGraphique))
  528. if self.estValide():
  529. rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self._rayon)
  530. if rect != None:
  531. self._itemCible.setRect(rect)
  532. self._itemCible.setVisible(self.estValide() and rect != None)
  533. def estValide(self):
  534. return self.ldmValide()
  535. @autorise
  536. def rectEllipseCirculaire(self, centre, rayon):
  537. """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
  538. attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
  539. verticalement le nombre de cases demandees"""
  540. rect = None
  541. if rayon > 0:
  542. p1 = QPointF((centre.x() - (rayon * self.plateau.hCase)), (centre.y() - (rayon * self.plateau.hCase)))
  543. p2 = QPointF((centre.x() + (rayon * self.plateau.hCase)), (centre.y() + (rayon * self.plateau.hCase)))
  544. if p1 != p2:
  545. rect = QRectF()
  546. rect.setTopLeft(p1)
  547. rect.setBottomRight(p2)
  548. return rect
  549. class Cone(Zone):
  550. """attaque de zone de forme conique"""
  551. def __init__(self):
  552. super(Cone, self).__init__()
  553. self._nom = "Attaque de zone: cône"
  554. def typeAttZone(self):
  555. return "cone"
  556. def description(self):
  557. return "Attaque à de zone (cone)"
  558. def majCibles(self):
  559. if self.plateau.cases[self._coordCible].estOccupee():
  560. zCible = self.plateau.cases[self._coordCible].occupant().zA()
  561. else:
  562. zCible = self.plateau.cases[self._coordCible].z0
  563. self._casesCibles = self.plateau.cone3d(self.acteur().position, self._coordCible, \
  564. (self.acteur().zR + self.acteur().h), zCible)
  565. def creerItemsGraphiques(self):
  566. self._itemCible = QGraphicsPolygonItem()
  567. self._itemCible.setPen(QPen(QColor("black")))
  568. self._itemCible.prepareGeometryChange()
  569. self.plateau.addItem(self._itemCible)
  570. def majItemsGraphiques(self):
  571. self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
  572. self.plateau.cases[self._coordCible].centreGraphique))
  573. def polygoneCone(self, point1, point2):
  574. """renvoie le polygone du cone defini par les deux points (origine, distance)"""
  575. ligne1 = QLineF(point1, point2)
  576. longueur = ligne1.length()
  577. ligne1.setAngle(ligne1.angle() + 22.5)
  578. ligne1.setLength(1.1547*longueur)
  579. ligne2 = QLineF(point1, point2)
  580. ligne2.setAngle(ligne2.angle() - 22.5)
  581. ligne2.setLength(1.1547*longueur)
  582. polygone = QPolygonF()
  583. polygone.append(point1)
  584. polygone.append(ligne1.p2())
  585. polygone.append(ligne2.p2())
  586. return polygone
  587. class EcranAttaqueZone(QDialog):
  588. """boite de dialogue de parametrage de l'attaque de zone"""
  589. def __init__(self, parent=None):
  590. super (EcranAttaqueZone, self).__init__()
  591. self.createWidgets()
  592. def createWidgets(self):
  593. """construction de l'interface"""
  594. self.ui = Ui_zne_fenetre()
  595. self.ui.setupUi(self)
  596. self.connect(self.ui.zne_forme, SIGNAL("currentIndexChanged(int)"), self.majAffichage, Qt.UniqueConnection)
  597. self.connect(self.ui.zne_valider, SIGNAL("clicked()"), self.ok, Qt.UniqueConnection)
  598. self.connect(self.ui.zne_annuler, SIGNAL("clicked()"), self.ok, Qt.UniqueConnection)
  599. self.ui.zne_valider.setShortcut("Enter")
  600. self.majAffichage(self.ui.zne_forme.currentIndex())
  601. def majAffichage(self, index):
  602. self.ui.zne_rayon.setVisible((index == 1))
  603. self.ui.zne_rayon_lbl.setVisible((index == 1))
  604. def resultat(self):
  605. if self.ui.zne_forme.currentIndex() == 0:
  606. attaque = Ligne()
  607. elif self.ui.zne_forme.currentIndex() == 1:
  608. attaque = Disque()
  609. attaque.majRayon(int(self.ui.zne_rayon.value()))
  610. elif self.ui.zne_forme.currentIndex() == 2:
  611. attaque = Cone()
  612. attaque.majPortee(int(self.ui.zne_portee.value()))
  613. return attaque
  614. def ok(self):
  615. self.done(1)
  616. def annuler(self):
  617. self.done(0)
  618. def itemLdm():
  619. """retourne l'item graphique utilise pour les lignes de mire"""
  620. item = QGraphicsLineItem()
  621. item.setZValue(100)
  622. pinceau = QPen()
  623. pinceau.setColor(QColor(249, 249, 249))
  624. pinceau.setStyle(Qt.DashDotLine)
  625. pinceau.setWidth(6)
  626. item.setPen(pinceau)
  627. return item
  628. if __name__ == "__main__":
  629. app = QApplication(sys.argv)
  630. ecran = EcranAttaqueZone()
  631. ecran.show()
  632. r = app.exec_()
  633. att = ecran.resultat()
  634. print att.typeAtt(), att.portee()
  635. exit(r)