Modes.py 21 KB

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