1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sf.magicproject.stack;
23
24 import static net.sf.magicproject.token.IdConst.IMAGES_DIR;
25
26 import java.awt.Color;
27 import java.awt.Dimension;
28 import java.awt.Graphics;
29 import java.awt.Graphics2D;
30 import java.awt.Image;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseListener;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36
37 import javax.swing.JCheckBoxMenuItem;
38 import javax.swing.JPanel;
39 import javax.swing.JPopupMenu;
40 import javax.swing.border.EtchedBorder;
41
42 import net.sf.magicproject.network.ConnectionManager;
43 import net.sf.magicproject.stack.phasetype.PhaseType;
44 import net.sf.magicproject.tools.Configuration;
45 import net.sf.magicproject.tools.Picture;
46 import net.sf.magicproject.ui.MagicUIComponents;
47 import net.sf.magicproject.ui.i18n.LanguageManagerMDB;
48
49 /***
50 * Represents a phase of turn of one player. Severals breakpoint flags can be
51 * attached to a phase to control the turn flow.
52 *
53 * @author Fabrice Daugan
54 * @since 0.21 a graphical representation of phase
55 * @since 0.31 a graphical representation for each players
56 * @since 0.4 phase settings are saved.
57 * @since 0.80 medium skip flag added.
58 */
59 public class MPhase extends JPanel implements MouseListener {
60
61 /***
62 * The phase picture width
63 */
64 private static final int PHASE_STD_WIDTH = 40;
65
66 /***
67 * The phase picture height
68 */
69 private static final int PHASE_STD_HEIGHT = 22;
70
71 /***
72 * Mask used to indicate if this phase has the option "breakpoint to this
73 * phase" if any ability is activated during this phase, even if the option
74 * "skippAll" is set in the following phases.
75 *
76 * @see MPhase#breakpoint()
77 * @see net.sf.magicproject.Magic#manualSkip()
78 */
79 private static final int MASK_BREAKPOINT = 0x01;
80
81 /***
82 * Mask used to indicate if this phase has the option Set if this phase has
83 * the option "decline response to my effects until this phase".
84 *
85 * @see MPhase#declineResponseMe()
86 * @see MPhase#setSkipAll(boolean)
87 * @see net.sf.magicproject.Magic#manualSkip()
88 */
89 private static final int MASK_SKIP_ALL = 0x0002;
90
91 /***
92 * Mask used to indicate if this phase has the option Set if this phase has
93 * the option "decline response to my effects until this phase". This option
94 * will be disabled arriving to this phase.
95 *
96 * @see MPhase#declineResponseMe()
97 * @see MPhase#setSkipAllTmp(boolean)
98 */
99 private static final int MASK_TMP_SKIP_ALL = 0x0004;
100
101 /***
102 * Mask used to indicate if this phase has the option "decline response to all
103 * effects until this phase".
104 *
105 * @see MPhase#declineResponseOpponent()
106 * @see MPhase#setSkipAllVery(boolean)
107 */
108 private static final int MASK_SKIP_ALL_VERY = 0x0008;
109
110 /***
111 * Mask used to indicate if this phase has the option "decline response to all
112 * effects until this phase". This option will be disabled arriving to this
113 * phase.
114 *
115 * @see MPhase#declineResponseOpponent()
116 * @see MPhase#setSkipAllVeryTmp(boolean)
117 */
118 private static final int MASK_TMP_SKIP_ALL_VERY = 0x0010;
119
120 /***
121 * Mask used to indicate if this phase has the option "decline response to all
122 * opponent's effects until this phase".
123 *
124 * @see MPhase#declineResponseOpponent()
125 * @see MPhase#setSkipMedium(boolean)
126 */
127 private static final int MASK_SKIP_ALL_MEDIUM = 0x0020;
128
129 /***
130 * Mask used to indicate if this phase has the option "decline response to all
131 * opponent's effects until this phase".This option will be disabled arriving
132 * to this phase.
133 *
134 * @see MPhase#declineResponseOpponent()
135 * @see MPhase#setSkipMediumTmp(boolean)
136 */
137 private static final int MASK_TMP_SKIP_ALL_MEDIUM = 0x0040;
138
139 /***
140 * Create a new instance of MPhase
141 *
142 * @param phaseType
143 * is the phase type associated to this phase
144 * @param idPlayer
145 * is the player ownig this phase
146 * @param settingFile
147 * the setting file where phase settings would be read
148 * @throws IOException
149 * if error occurred while reading settings from settingFile
150 */
151 public MPhase(PhaseType phaseType, int idPlayer, InputStream settingFile)
152 throws IOException {
153 super();
154 setMinimumSize(new Dimension(PHASE_STD_WIDTH, PHASE_STD_HEIGHT));
155 setPreferredSize(new Dimension(PHASE_STD_WIDTH, PHASE_STD_HEIGHT));
156 this.phaseType = phaseType;
157 this.idPlayer = idPlayer;
158 if (popupImg == null) {
159 popupImg = Picture.loadImage(IMAGES_DIR + "popup.gif");
160 breakpointImg = Picture.loadImage(IMAGES_DIR + "smlbreak.gif");
161 skipAllImg = Picture.loadImage(IMAGES_DIR + "smlskip1.gif");
162 skipAllOnceImg = Picture.loadImage(IMAGES_DIR + "smlskip2.gif");
163 skipAllVeryImg = Picture.loadImage(IMAGES_DIR + "smlskip3.gif");
164 skipAllOnceVeryImg = Picture.loadImage(IMAGES_DIR + "smlskip4.gif");
165 skipAllMediumImg = Picture.loadImage(IMAGES_DIR + "smlskip5.gif");
166 skipAllMediumOnceImg = Picture.loadImage(IMAGES_DIR + "smlskip4.gif");
167 }
168 mask = settingFile.read();
169 setBorder(new EtchedBorder());
170 setToolTipText(LanguageManagerMDB.getString(phaseType.phaseName));
171 addMouseListener(this);
172 reset();
173 }
174
175 /***
176 * Update the backgroung following the active player
177 *
178 * @param currentPhase
179 * if true, set this phase as activated
180 * @param activePlayer
181 * if true, set this phase with normal backgroung, otherwise it's
182 * backgroung is darker as normal
183 */
184 void setActive(boolean currentPhase, boolean activePlayer) {
185 if (currentPhase != currentPhase || activePlayer != activePlayer) {
186 this.currentPhase = currentPhase;
187 }
188 if (currentPhase) {
189 if (activePlayer) {
190 setBackground(Color.RED);
191 } else {
192 setBackground(Color.RED.darker());
193 }
194 } else if (activePlayer) {
195 setBackground(null);
196 } else {
197 setBackground(Color.DARK_GRAY);
198 }
199 }
200
201 /***
202 * update this component
203 *
204 * @param g
205 * the graphics of this component
206 */
207 @Override
208 public void paint(Graphics g) {
209 final Graphics2D g2D = (Graphics2D) g;
210 super.paint(g);
211 if (idPlayer == 1 && Configuration.getBoolean("reverseSide", false)) {
212 g2D.translate(PHASE_STD_WIDTH - 1, PHASE_STD_HEIGHT - 1);
213 g2D.rotate(Math.PI);
214 }
215
216 if (currentPhase) {
217 g2D.drawImage(phaseType.highLightedIcon, 2, 2, 16, 16, null);
218 } else {
219 g2D.drawImage(phaseType.normalIcon, 2, 2, 16, 16, null);
220 }
221
222
223 if (activatedPopup) {
224
225 g2D.drawImage(popupImg, 28, 12, 9, 8, null);
226 }
227
228
229 if (breakpoint()) {
230
231 g2D.drawImage(breakpointImg, 19, 2, 8, 8, null);
232 }
233
234
235 if (hasMaskSkipAllVery()) {
236
237 g2D.drawImage(skipAllVeryImg, 26, 2, 8, 8, null);
238 } else if (hasMaskTmpSkipAllVery()) {
239
240 g2D.drawImage(skipAllOnceVeryImg, 26, 2, 8, 8, null);
241 } else if (hasMaskSkipAllMedium()) {
242
243 g2D.drawImage(skipAllMediumImg, 26, 2, 8, 8, null);
244 } else if (hasMaskTmpSkipAllMedium()) {
245
246 g2D.drawImage(skipAllMediumOnceImg, 26, 2, 8, 8, null);
247 } else if (hasMaskSkipAll()) {
248
249 g2D.drawImage(skipAllImg, 26, 2, 8, 8, null);
250 } else if (hasMaskTmpSkipAll()) {
251
252 g2D.drawImage(skipAllOnceImg, 26, 2, 8, 8, null);
253 }
254 }
255
256 /***
257 * Save settings of this phase to the specified output stream
258 *
259 * @param out
260 * is output stream where settings of this phase would be saved
261 * @throws IOException
262 * if error occurred while writting settings to settingFile
263 */
264 public void saveSettings(FileOutputStream out) throws IOException {
265 out.write(mask);
266 }
267
268 /***
269 * Load settings of this phase from the specified input stream
270 *
271 * @param input
272 * is input stream where settings of this phase is saved
273 * @throws IOException
274 * if error occurred while reading settings from settingFile
275 */
276 public void loadSettings(InputStream input) throws IOException {
277 mask = input.read();
278 }
279
280 /***
281 * remove all breakpoints and options of this phase
282 */
283 public void reset() {
284 activatedPopup = false;
285 setOpaque(true);
286 }
287
288 /***
289 * Tell if this phase has the option "breapoint to this phase"
290 *
291 * @return true if there is a breakpoint on this phase
292 * @see MPhase#MASK_BREAKPOINT
293 * @see net.sf.magicproject.Magic#manualSkip()
294 */
295 public boolean breakpoint() {
296 return (mask & MASK_BREAKPOINT) == MASK_BREAKPOINT;
297 }
298
299 /***
300 * Set if this phase has the option "breapoint to this phase"
301 *
302 * @param really
303 * indication if we set or unset this option
304 * @see MPhase#MASK_BREAKPOINT
305 */
306 void setBreakpoint(boolean really) {
307 if (really) {
308 mask |= MASK_BREAKPOINT;
309 } else {
310 mask &= ~MASK_BREAKPOINT;
311 }
312 }
313
314 /***
315 * Indicates wether this phase has the option "decline response to my effects
316 * until this phase".
317 *
318 * @return true if there is a 'skip all' on this phase
319 * @see MPhase#MASK_SKIP_ALL
320 * @see MPhase#MASK_TMP_SKIP_ALL
321 * @see MPhase#MASK_SKIP_ALL_VERY
322 * @see MPhase#MASK_TMP_SKIP_ALL_VERY
323 * @see net.sf.magicproject.Magic#manualSkip()
324 */
325 public boolean declineResponseMe() {
326 return hasMaskSkipAllVery() || hasMaskTmpSkipAllVery() || hasMaskSkipAll()
327 || hasMaskTmpSkipAll();
328 }
329
330 /***
331 * Set if this phase has the option "decline response to all effects until
332 * this phase".
333 *
334 * @param really
335 * indication if we set or unset this option
336 * @see MPhase#MASK_BREAKPOINT
337 */
338 void setSkipAll(boolean really) {
339 if (really) {
340 mask |= MASK_SKIP_ALL;
341 } else {
342 mask &= ~MASK_SKIP_ALL;
343 }
344 }
345
346 /***
347 * Set if this phase has the option "decline response to my effects until this
348 * phase". This option will be disabled arriving to this phase.
349 *
350 * @param really
351 * indication if we set or unset this option
352 * @see MPhase#MASK_TMP_SKIP_ALL
353 */
354 void setSkipAllTmp(boolean really) {
355 if (really) {
356 mask |= MASK_TMP_SKIP_ALL;
357 } else {
358 mask &= ~MASK_TMP_SKIP_ALL;
359 }
360 }
361
362 /***
363 * Indicates wether this phase has the option "decline response to opponent's
364 * effects until this phase".
365 *
366 * @return true if this phase has the option "decline response to opponent's
367 * effects until this phase".
368 * @see MPhase#MASK_SKIP_ALL_VERY
369 * @see MPhase#MASK_TMP_SKIP_ALL_VERY
370 * @see MPhase#MASK_SKIP_ALL_MEDIUM
371 * @see MPhase#MASK_TMP_SKIP_ALL_MEDIUM
372 * @see net.sf.magicproject.Magic#manualSkip()
373 */
374 public boolean declineResponseOpponent() {
375 return hasMaskSkipAllVery() || hasMaskTmpSkipAllVery()
376 || hasMaskTmpSkipAllMedium() || hasMaskSkipAllMedium();
377 }
378
379 /***
380 * Set if this phase has the option "decline response to all opponent's
381 * effects until this phase".
382 *
383 * @param really
384 * indication if we set or unset this option
385 * @see MPhase#MASK_SKIP_ALL_MEDIUM
386 */
387 void setSkipMedium(boolean really) {
388 if (really) {
389 mask |= MASK_SKIP_ALL_MEDIUM;
390 } else {
391 mask &= ~MASK_SKIP_ALL_MEDIUM;
392 }
393 }
394
395 /***
396 * Set if this phase has the option "decline response to all opponent's
397 * effects until this phase". This option will be disabled arriving to this
398 * phase.
399 *
400 * @param really
401 * indication if we set or unset this option
402 * @see MPhase#MASK_TMP_SKIP_ALL_MEDIUM
403 */
404 void setSkipMediumTmp(boolean really) {
405 if (really) {
406 mask |= MASK_TMP_SKIP_ALL_MEDIUM;
407 } else {
408 mask &= ~MASK_TMP_SKIP_ALL_MEDIUM;
409 }
410 }
411
412 /***
413 * Set if this phase has the option "breapoint to this phase"
414 *
415 * @param really
416 * indication if we set or unset this option
417 * @see MPhase#MASK_BREAKPOINT
418 */
419 void setSkipAllVery(boolean really) {
420 if (really) {
421 mask |= MASK_SKIP_ALL_VERY;
422 } else {
423 mask &= ~MASK_SKIP_ALL_VERY;
424 }
425 }
426
427 /***
428 * Set if this phase has the option "decline response to all effects until
429 * this phase". This option will be disabled arriving to this phase.
430 *
431 * @param really
432 * indication if we set or unset this option
433 * @see MPhase#MASK_BREAKPOINT
434 */
435 void setSkipAllVeryTmp(boolean really) {
436 if (really) {
437 mask |= MASK_TMP_SKIP_ALL_VERY;
438 } else {
439 mask &= ~MASK_TMP_SKIP_ALL_VERY;
440 }
441 }
442
443 /***
444 * is called when you click on me
445 *
446 * @param e
447 * is the mouse event
448 */
449 public void mouseClicked(MouseEvent e) {
450 StackManager.noReplayToken.take();
451 try {
452 if (ConnectionManager.isConnected()) {
453 if (e.getButton() != MouseEvent.BUTTON1) {
454
455
456
457
458
459 triggerPhase = this;
460 ((JCheckBoxMenuItem) optionsMenu.getComponent(0))
461 .setSelected(breakpoint());
462 ((JCheckBoxMenuItem) optionsMenu.getComponent(1))
463 .setSelected(hasMaskSkipAll());
464 ((JCheckBoxMenuItem) optionsMenu.getComponent(2))
465 .setSelected(hasMaskTmpSkipAll());
466 ((JCheckBoxMenuItem) optionsMenu.getComponent(3))
467 .setSelected(hasMaskSkipAllMedium());
468 ((JCheckBoxMenuItem) optionsMenu.getComponent(4))
469 .setSelected(hasMaskTmpSkipAllMedium());
470 ((JCheckBoxMenuItem) optionsMenu.getComponent(5))
471 .setSelected(hasMaskSkipAllVery());
472 ((JCheckBoxMenuItem) optionsMenu.getComponent(6))
473 .setSelected(hasMaskTmpSkipAllVery());
474
475 optionsMenu.show(e.getComponent(), e.getX(), e.getY());
476 } else {
477
478 if (EventManager.currentPhase() == this && activatedPopup
479 && e.getX() >= 13 && e.getY() >= 8) {
480
481 popupMenu.show(e.getComponent(), e.getX(), e.getY());
482 } else {
483
484 setSkipAllTmp(true);
485 repaint();
486 if (StackManager.idHandedPlayer == 0
487 && this != EventManager.currentPhase()) {
488 MagicUIComponents.magicForm.manualSkip();
489 }
490 }
491 }
492 }
493 } catch (Throwable t) {
494 t.printStackTrace();
495 } finally {
496 StackManager.noReplayToken.release();
497 }
498 }
499
500 private boolean hasMaskTmpSkipAllVery() {
501 return (mask & MASK_TMP_SKIP_ALL_VERY) == MASK_TMP_SKIP_ALL_VERY;
502 }
503
504 private boolean hasMaskSkipAllMedium() {
505 return (mask & MASK_SKIP_ALL_MEDIUM) == MASK_SKIP_ALL_MEDIUM;
506 }
507
508 private boolean hasMaskSkipAllVery() {
509 return (mask & MASK_SKIP_ALL_VERY) == MASK_SKIP_ALL_VERY;
510 }
511
512 private boolean hasMaskTmpSkipAllMedium() {
513 return (mask & MASK_TMP_SKIP_ALL_MEDIUM) == MASK_TMP_SKIP_ALL_MEDIUM;
514 }
515
516 private boolean hasMaskTmpSkipAll() {
517 return (mask & MASK_TMP_SKIP_ALL) == MASK_TMP_SKIP_ALL;
518 }
519
520 private boolean hasMaskSkipAll() {
521 return (mask & MASK_SKIP_ALL) == MASK_SKIP_ALL;
522 }
523
524 public void mousePressed(MouseEvent e) {
525
526 }
527
528 public void mouseReleased(MouseEvent e) {
529
530 }
531
532 public void mouseEntered(MouseEvent e) {
533
534 }
535
536 public void mouseExited(MouseEvent e) {
537
538 }
539
540 /***
541 * is the popupMenu displayable when click to see hystory of stack
542 */
543 public static JPopupMenu popupMenu;
544
545 /***
546 * is the popupMenu displayable when you right-click to see options of this
547 * phase.
548 */
549 public static JPopupMenu optionsMenu;
550
551 /***
552 * image for litle popupMenu's button
553 */
554 private static Image popupImg;
555
556 /***
557 * image for litle bookmark button
558 */
559 private static Image breakpointImg;
560
561 /***
562 * image for litle skipAll button
563 */
564 private static Image skipAllImg;
565
566 /***
567 * image for litle skipAll (once) button
568 */
569 private static Image skipAllOnceImg;
570
571 /***
572 * image for litle skipAllVery button
573 */
574 private static Image skipAllVeryImg;
575
576 /***
577 * image for litle skipAllVery button (once)
578 */
579 private static Image skipAllOnceVeryImg;
580
581 /***
582 * image for litle skipAllMedium button
583 */
584 private static Image skipAllMediumOnceImg;
585
586 /***
587 * image for litle skipAllMedium (once) button
588 */
589 private static Image skipAllMediumImg;
590
591 /***
592 * is the popupMenu's button is visible
593 */
594 private static boolean activatedPopup = false;
595
596 /***
597 * the last phase where popup trigger has been recorded
598 */
599 public static MPhase triggerPhase;
600
601 /***
602 * will contain all MPhase object of players
603 */
604 public static MPhase[][] phases = null;
605
606 /***
607 * Indicates if this phase is the current one or not
608 */
609 private boolean currentPhase = false;
610
611 /***
612 * Mask used for skip options
613 */
614 private int mask;
615
616 /***
617 * idPlayer of this player
618 */
619 private int idPlayer;
620
621 /***
622 * Phase type associated to this phase component
623 */
624 public PhaseType phaseType;
625
626 /***
627 * Indicates if this phase has to be skipped. The beginning_of_... and
628 * phase_... events would not be raised. Nevertheless, the before_phase_...
629 * trigger the current phase, the the awakened abilities should be mana source
630 * and played in the background as abstract abilities.
631 */
632 public boolean skipThisPhase;
633
634 }