Modes.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #from __future__ import unicode_literals
  2. # -*- coding: utf-8 -*-
  3. """les modes d'interaction permettent l'interaction
  4. entre l'interface (l'utilisateur) et le plateau de combat.
  5. Un seul mode ne peut etre actif a la fois
  6. Cette classe doit permettre de recevoir les commandes de l'utilisateur
  7. de maniere a produire un resultat unique (cases peintes, pion deplace...)"""
  8. from PyQt4.QtCore import *
  9. from PyQt4.QtGui import *
  10. from EntreeSortie import EntreeSortie
  11. import Actions
  12. import regles
  13. from Pion import Pion
  14. from Combattant import Combattant
  15. from Decor import Decor
  16. class ModeBase(object):
  17. """mode de base: tous les modes heritent de cette classe"""
  18. def __init__(self, plateau):
  19. self.plateau = plateau
  20. #le mode est il active
  21. self._actif = False
  22. #le dragmode est il active sur la QGraphicsView
  23. self._activerDragMode = 0
  24. #curseur de la QGraphicsView
  25. self._sourceCurseur = ""
  26. #met le focus sur la QGraphicsView a l'activation
  27. self._focus = False
  28. def nom(self):
  29. return self.__class__.__name__
  30. def activer(self, param = None):
  31. """active le mode"""
  32. self.activerCurseur()
  33. if self._focus:
  34. self.plateau.fenetre.ui.cbt_vue.setFocus()
  35. self._actif = True
  36. def desactiver(self):
  37. """desactive le mode"""
  38. self.desactiverCurseur()
  39. self.plateau.fenetre.ui.cbt_vue.setDragMode(1)
  40. self._actif = False
  41. def reinit(self):
  42. """remet les variables a 0 et reactive le mode"""
  43. pass
  44. def activerCurseur(self):
  45. self.plateau.fenetre.ui.cbt_vue.setDragMode(self._activerDragMode)
  46. curseurPix = QPixmap(self._sourceCurseur)
  47. if not curseurPix.isNull():
  48. curseur = QCursor(curseurPix, 0, curseurPix.height())
  49. self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)
  50. def desactiverCurseur(self):
  51. self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  52. ### gestion des evenements souris
  53. # clic gauche
  54. def clic_combattant(self, num):
  55. pass
  56. def clic_decor(self, num):
  57. pass
  58. def clic_case(self, coord):
  59. pass
  60. def clic_es(self, es):
  61. #clic sur une entree/sortie
  62. pass
  63. #double clic gauche
  64. def doubleClic_combattant(self, num):
  65. pass
  66. def doubleClic_decor(self, num):
  67. pass
  68. def doubleClic_case(self, coord):
  69. pass
  70. #survol de la souris (entree)
  71. def survol_combattant(self, num):
  72. pass
  73. def survol_decor(self, num):
  74. pass
  75. def survol_case(self, coord):
  76. pass
  77. #survol de la souris (sortie)
  78. def finSurvol_combattant(self, num):
  79. pass
  80. def finSurvol_decor(self, num):
  81. pass
  82. def finSurvol_case(self, coord):
  83. pass
  84. #survol de la souris avec clic gauche enfonce (entree)
  85. def survolClic_combattant(self, event):
  86. pass
  87. def survolClic_decor(self, event):
  88. pass
  89. def survolClic_case(self, coord):
  90. pass
  91. #autre
  92. def clicGauche(self, event):
  93. pass
  94. def finClicGauche(self, event):
  95. pass
  96. def mouvementSouris(self, event):
  97. pass
  98. def toucheClavier(self, event):
  99. pass
  100. def clicDroit(self, event):
  101. pass
  102. class ModeBaseCp(ModeBase):
  103. """mode servant de base a tous les modes lies a la creation de plateau"""
  104. def __init__(self, plateau):
  105. super(ModeBaseCp, self).__init__(plateau)
  106. self.type = "cp"
  107. def activer(self, param = None):
  108. self.plateau.fenetre.ui.cbt_modeCreation.setChecked(True)
  109. super(ModeBaseCp, self).activer(param)
  110. def desactiver(self):
  111. self.plateau.fenetre.ui.cbt_modeCreation.setChecked(False)
  112. super(ModeBaseCp, self).desactiver()
  113. def clicDroit(self, event):
  114. self.plateau.activerMode(StandardCp)
  115. class ModeBasePi(ModeBase):
  116. """mode servant de base a tous les modes lies aux actions des combattants"""
  117. def __init__(self, plateau):
  118. super(ModeBasePi, self).__init__(plateau)
  119. self.type = "pi"
  120. def activer(self, param = None):
  121. self.plateau.fenetre.ui.cbt_modeCombat.setChecked(True)
  122. super(ModeBasePi, self).activer(param)
  123. def desactiver(self):
  124. self.plateau.fenetre.ui.cbt_modeCombat.setChecked(False)
  125. super(ModeBasePi, self).desactiver()
  126. def clicDroit(self, event):
  127. self.plateau.activerMode(StandardPi)
  128. ### --------------------------------------- ####
  129. class StandardCp(ModeBaseCp):
  130. """mode standard en creation de plateau"""
  131. def __init__(self, plateau):
  132. super(StandardCp, self).__init__(plateau)
  133. self._sourceCurseur = ""
  134. self._focus = False
  135. self._activerDragMode = True
  136. def activer(self, param):
  137. """active le mode"""
  138. self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(1)
  139. if len(self.plateau.caches) > 0:
  140. for coord in self.plateau.cases:
  141. self.plateau.cases[coord].majCache()
  142. super(StandardCp, self).activer()
  143. def clic_combattant(self, num):
  144. self.plateau.activerMode(DeplacementPion, num)
  145. def clic_decor(self, num):
  146. self.plateau.activerMode(DeplacementPion, num)
  147. def clic_es(self, es):
  148. self.plateau.activerMode(EditionEntreeSortie, es)
  149. class MajCases(ModeBaseCp):
  150. """mode de mise a jour des cases (terrain, couleur, effet special)"""
  151. def __init__(self, plateau):
  152. super(MajCases, self).__init__(plateau)
  153. self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
  154. self._focus = True
  155. self._param = None #parametre avec lequel on mettra a jour la case
  156. self._caseSurvolee = None
  157. def activer(self, param):
  158. """active le mode"""
  159. self.majParam(param)
  160. super(MajCases, self).activer()
  161. def desactiver(self):
  162. """desactive le mode"""
  163. self.plateau.pinceau.reinit()
  164. super(MajCases, self).desactiver()
  165. def majParam(self, param):
  166. self._param = param
  167. def param(self):
  168. return self._param
  169. def clic_case(self, coord):
  170. #demarre une operation de peinture des cases
  171. self.plateau.pinceau.demarrer(coord)
  172. def survolClic_case(self, coord):
  173. if coord != self._caseSurvolee:
  174. self.plateau.pinceau.maj(coord)
  175. def finClicGauche(self, event):
  176. if self.plateau.pinceau.estActif():
  177. for coord in self.plateau.pinceau.selection():
  178. self.plateau.cases[coord].majTerrain(self._param)
  179. self.plateau.pinceau.reinit()
  180. self.reinit()
  181. def toucheClavier(self, event):
  182. if event.key() == Qt.Key_Up:
  183. self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()+1)
  184. elif event.key() == Qt.Key_Down:
  185. self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()-1)
  186. class MajCasesEffet(MajCases):
  187. """mode de mise a jour des cases (effets speciaux)"""
  188. def __init__(self, plateau):
  189. super(MajCasesEffet, self).__init__(plateau)
  190. self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
  191. def finClicGauche(self, event):
  192. if self.plateau.pinceau.estActif():
  193. for coord in self.plateau.pinceau.selection():
  194. self.plateau.cases[coord].majEffet(self._param)
  195. self.plateau.pinceau.reinit()
  196. self.reinit()
  197. class Pipette(ModeBaseCp):
  198. """mode pipette: on preleve la couleur ou le terrain d'une case"""
  199. def __init__(self, plateau):
  200. super(Pipette, self).__init__(plateau)
  201. self._sourceCurseur = ":/interface/16/ressource/seringue_16.png"
  202. def activerCurseur(self):
  203. super(Pipette, self).activerCurseur()
  204. def clic_case(self, coord):
  205. self.plateau.activerMode(MajCases, self.plateau.cases[coord].terrain)
  206. class ZonePlacement(ModeBaseCp):
  207. """mode de definition de la/les zones de placement des joueurs"""
  208. def __init__(self, plateau):
  209. super(ZonePlacement, self).__init__(plateau)
  210. self._sourceCurseur = ":/interface/16/ressource/pinceau.png"
  211. self._focus = True
  212. def activerCurseur(self):
  213. super(ZonePlacement, self).activerCurseur()
  214. def activer(self, param = None):
  215. self.plateau.pinceau.majForme("rectP")
  216. self.plateau.pinceau.verrouillerForme(True)
  217. super(ZonePlacement, self).activer()
  218. def desactiver(self):
  219. self.plateau.pinceau.reinit()
  220. super(ZonePlacement, self).desactiver()
  221. def clic_case(self, coord):
  222. #demarre une operation de peinture des cases
  223. self.plateau.pinceau.demarrer(coord)
  224. def survolClic_case(self, coord):
  225. self.plateau.pinceau.maj(coord)
  226. def finClicGauche(self, coord):
  227. if self.plateau.pinceau.estActif():
  228. if len(self.plateau.pinceau.selection()) > 0:
  229. self.plateau.majZonePlacement(self.plateau.pinceau.selection())
  230. class EditerCaches(ModeBaseCp):
  231. """mode de creation/ edition des caches"""
  232. def __init__(self, plateau):
  233. super(EditerCaches, self).__init__(plateau)
  234. self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
  235. self._focus = True
  236. self._numCache = None
  237. def activer(self, param = None):
  238. self._numCache = param
  239. self.plateau.pinceau.majForme("rectP")
  240. super(EditerCaches, self).activer()
  241. def desactiver(self):
  242. self.plateau.pinceau.reinit()
  243. super(EditerCaches, self).desactiver()
  244. def clic_case(self, coord):
  245. self.plateau.pinceau.demarrer(coord)
  246. def survolClic_case(self, coord):
  247. self.plateau.pinceau.maj(coord)
  248. def finClicGauche(self, coord):
  249. if self.plateau.pinceau.estActif():
  250. if len(self.plateau.pinceau.selection()) > 0:
  251. if self._numCache != None:
  252. self.plateau.editerFormeCache(self._numCache, self.plateau.pinceau.selection())
  253. else:
  254. self.plateau.nouveauCache(self.plateau.pinceau.selection())
  255. self.plateau.activerMode(StandardCp)
  256. class EntreeSortieBase(ModeBaseCp):
  257. """mode de base de la gestion des entrees et sorties du plateau"""
  258. def __init__(self, plateau):
  259. super(EntreeSortieBase, self).__init__(plateau)
  260. self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
  261. self._focus = True
  262. def activerCurseur(self):
  263. super(EntreeSortieBase, self).activerCurseur()
  264. def activer(self, param):
  265. self.es = param
  266. self.es.saisir()
  267. super(EntreeSortieBase, self).activer()
  268. def desactiver(self):
  269. if not self.es.estPositionne:
  270. self.es.prepareGeometryChange()
  271. self.es.plateau = None
  272. self.plateau.removeItem(self.es)
  273. if self.es in self.plateau.entreesSorties:
  274. self.plateau.entreesSorties.remove(self.es)
  275. super(EntreeSortieBase, self).desactiver()
  276. def mouvementSouris(self, event):
  277. if event.buttons() != Qt.LeftButton:
  278. if not self.es.estPositionne:
  279. self.es.majProjection(event.scenePos())
  280. def toucheClavier(self, event):
  281. if event.key() == Qt.Key_Delete:
  282. self.es.supprimer()
  283. if self.es in self.plateau.entreesSorties:
  284. self.plateau.entreesSorties.remove(self.es)
  285. self.plateau.activerMode(StandardCp)
  286. elif event.key() == Qt.Key_Right:
  287. self.es.nbRotations += 1
  288. self.es.majProjection()
  289. elif event.key() == Qt.Key_Left:
  290. self.es.nbRotations -= 1
  291. self.es.majProjection()
  292. class CreationEntreeSortie(EntreeSortieBase):
  293. """mode de creation des entrees / sorties"""
  294. def __init__(self, plateau):
  295. super(CreationEntreeSortie, self).__init__(plateau)
  296. def activer(self, typeES):
  297. self.plateau.fenetre.ui.cbt_vue.fitInView(self.plateau.sceneRect(), Qt.KeepAspectRatio)
  298. param = EntreeSortie(self.plateau, typeES)
  299. param.creerForme()
  300. super(CreationEntreeSortie, self).activer(param)
  301. def clicGauche(self, event):
  302. self.es.positionner()
  303. self.plateau.entreesSorties.append(self.es)
  304. self.plateau.activerMode(StandardCp)
  305. class EditionEntreeSortie(EntreeSortieBase):
  306. """mode d'edition des entrees / sorties"""
  307. def __init__(self, plateau):
  308. super(EditionEntreeSortie, self).__init__(plateau)
  309. def clicGauche(self, event):
  310. if not event.isAccepted():
  311. self.es.positionner()
  312. self.plateau.activerMode(StandardCp)
  313. class CreationPion(ModeBaseCp):
  314. """mode de creation de pions (combattant ou decor)"""
  315. def __init__(self, plateau):
  316. super(CreationPion, self).__init__(plateau)
  317. self._focus = True
  318. self._pion = None
  319. def activer(self, pion):
  320. self._pion = pion
  321. self.plateau.proj.creer(self._pion)
  322. super(CreationPion, self).activer()
  323. def desactiver(self):
  324. self.plateau.proj.desactiver()
  325. self._pion = None
  326. super(CreationPion, self).desactiver()
  327. def survol_case(self, coord):
  328. if self._pion:
  329. self.plateau.proj.majCoord(coord)
  330. def clic_case(self, coord):
  331. if self._pion:
  332. if not self.plateau.cases[coord].pionOccupant():
  333. self.plateau.creerPion(self._pion)
  334. def toucheClavier(self, event):
  335. if self._pion:
  336. if event.key() == Qt.Key_Right:
  337. self.plateau.proj.majRotation(1)
  338. elif event.key() == Qt.Key_Left:
  339. self.plateau.proj.majRotation(-1)
  340. class SuppressionPion(ModeBaseCp):
  341. """mode de suppression de pions (combattant ou decor)"""
  342. def __init__(self, plateau):
  343. super(SuppressionPion, self).__init__(plateau)
  344. self._sourceCurseur = ":/interface/16/ressource/gomme_16.png"
  345. self._enSurbrillance = []
  346. self._focus = True
  347. self._cible = ""
  348. def activer(self, cible = Pion):
  349. #cible est le nom de la classe des objets a supprimer
  350. self._cible = cible
  351. super(SuppressionPion, self).activer()
  352. def desactiver(self):
  353. for num in self._enSurbrillance:
  354. if num >= 10000:
  355. if num in self.plateau.decors:
  356. self.plateau.decors[num].surbrillance(False)
  357. else:
  358. if num in self.plateau.combattants:
  359. self.plateau.combattants[num].surbrillance(False)
  360. super(SuppressionPion, self).desactiver()
  361. def clicGauche(self, event):
  362. """supprime le pion sous le clic. S'il y en a plusieurs,
  363. supprime le premier de la pile"""
  364. num = None
  365. item = self.plateau.itemAt(event.scenePos())
  366. if isinstance(item.parentItem(), self._cible):
  367. num = item.parentItem().numero
  368. elif isinstance(item.parentItem().parentItem(), self._cible):
  369. num = item.parentItem().parentItem().numero
  370. if num:
  371. self.plateau.pionSupprimer(num)
  372. def survol_combattant(self, num):
  373. if self._cible == Combattant:
  374. self.plateau.combattants[num].surbrillance(True, 0.4)
  375. self._enSurbrillance.append(num)
  376. def finSurvol_combattant(self, num):
  377. if self._cible == Combattant:
  378. self.plateau.combattants[num].surbrillance(False)
  379. def survol_decor(self, num):
  380. if self._cible == Decor:
  381. self.plateau.decors[num].surbrillance(True, 0.4)
  382. self._enSurbrillance.append(num)
  383. def finSurvol_decor(self, num):
  384. if self._cible == Decor:
  385. self.plateau.decors[num].surbrillance(False)
  386. class DeplacementPion(ModeBaseCp):
  387. """mode de deplacement de pions (combattant ou decor) en mode creation
  388. attention: different des actions de type deplacement qu'effectuent les pions en mode Combat"""
  389. def __init__(self, plateau):
  390. super(DeplacementPion, self).__init__(plateau)
  391. self._num = 0
  392. def activer(self, num):
  393. self._num = num
  394. if self._num < 10000:
  395. pion = self.plateau.combattants[self._num]
  396. else:
  397. pion = self.plateau.decors[self._num]
  398. self.plateau.proj.creer(pion)
  399. self.deplace = False
  400. super(DeplacementPion, self).activer()
  401. def desactiver(self):
  402. self.plateau.proj.desactiver()
  403. self._num = 0
  404. super(DeplacementPion, self).desactiver()
  405. def survol_case(self, coord):
  406. if self._num > 0:
  407. self.plateau.proj.majCoord(coord)
  408. self.deplace = True
  409. def clic_case(self, coord):
  410. if self._num > 0:
  411. if self.deplace:
  412. if self._num < 10000:
  413. pion = self.plateau.combattants[self._num]
  414. else:
  415. pion = self.plateau.decors[self._num]
  416. pion.majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
  417. def toucheClavier(self, event):
  418. if self._num > 0:
  419. if event.key() == Qt.Key_Right:
  420. self.plateau.proj.majRotation(1)
  421. self.deplace = True
  422. elif event.key() == Qt.Key_Left:
  423. self.plateau.proj.majRotation(-1)
  424. self.deplace = True
  425. #-----------------------------------------------
  426. #-----------------------------------------------
  427. class StandardPi(ModeBasePi):
  428. """mode standard de la manipulation de pion en combat"""
  429. def __init__(self, plateau):
  430. super(StandardPi, self).__init__(plateau)
  431. self._focus = False
  432. self._activerDragMode = True
  433. def activer(self, num):
  434. self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(3)
  435. if len(self.plateau.caches) > 0:
  436. for coord in self.plateau.cases:
  437. self.plateau.cases[coord].majCache()
  438. super(StandardPi, self).activer()
  439. def clic_combattant(self, num):
  440. self.plateau.activerMode(PionSelectionne, num)
  441. def clic_decor(self, num):
  442. self.plateau.activerMode(PionSelectionne, num)
  443. def nouvelleAction(self, action):
  444. pass
  445. class PionSelectionne(ModeBasePi):
  446. """mode active a la selection d'un pion combattant"""
  447. def __init__(self, plateau):
  448. super(PionSelectionne, self).__init__(plateau)
  449. self._focus = True
  450. self._num = None
  451. self._action = None
  452. def pion(self):
  453. """retourne la ref du pion actuellement selectionne"""
  454. retour = None
  455. if self._num in self.plateau.combattants:
  456. retour = self.plateau.combattants[self._num]
  457. elif self._num in self.plateau.decors:
  458. retour = self.plateau.decors[self._num]
  459. return retour
  460. def activer(self, num):
  461. self._num = num
  462. self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(2)
  463. self.pion().afficheOmbreSelection(True)
  464. self.plateau.majPanneauPi()
  465. super(PionSelectionne, self).activer()
  466. def desactiver(self):
  467. if self._action:
  468. self._action.desactiver()
  469. self._action = None
  470. self.pion().afficheOmbreSelection(False)
  471. self._num = None
  472. self.plateau.majPanneauPi()
  473. super(PionSelectionne, self).desactiver()
  474. def nouvelleAction(self, action):
  475. if self._action:
  476. self._action.desactiver()
  477. self._action = None
  478. self._action = action()
  479. self._action.activer(self.plateau, self._num)
  480. def action(self):
  481. return self._action
  482. def survol_case(self, coord):
  483. if self._action:
  484. self._action.majCoordCible(coord)
  485. def clic_case(self, coord):
  486. if self._action:
  487. terminee = self._action.valider()
  488. if not self._action.enCours(): self._action = None
  489. def clicDroit(self, event):
  490. if self._action != None:
  491. self._action.desactiver()
  492. self._action = None
  493. else:
  494. super(PionSelectionne, self).clicDroit(event)
  495. def toucheClavier(self, event):
  496. if self._num > 0:
  497. if event.key() == Qt.Key_Right:
  498. self._action.pivoter(1)
  499. elif event.key() == Qt.Key_Left:
  500. self._action.pivoter(-1)