View Javadoc

1   /*
2    * Created on 22 octobre 2003, 12:15
3    *  
4    *   Magic-Project is a turn based strategy simulator
5    *   Copyright (C) 2003-2007 Fabrice Daugan
6    *
7    *   This program is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU General Public License as published by the Free 
9    * Software Foundation; either version 2 of the License, or (at your option) any
10   * later version.
11   *
12   *   This program is distributed in the hope that it will be useful, but WITHOUT 
13   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
15   * details.
16   *
17   *   You should have received a copy of the GNU General Public License along  
18   * with this program; if not, write to the Free Software Foundation, Inc., 
19   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   * 
21   */
22  package net.sf.magicproject.stack;
23  
24  import java.awt.event.ActionEvent;
25  import java.awt.event.ActionListener;
26  import java.io.FileInputStream;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.util.Arrays;
30  
31  import javax.swing.JCheckBoxMenuItem;
32  import javax.swing.JLabel;
33  import javax.swing.JOptionPane;
34  import javax.swing.JPopupMenu;
35  
36  import net.sf.magicproject.clickable.ability.AbilityFactory;
37  import net.sf.magicproject.clickable.ability.SystemAbility;
38  import net.sf.magicproject.clickable.targetable.card.SystemCard;
39  import net.sf.magicproject.event.MEventListener;
40  import net.sf.magicproject.event.phase.BeforePhase;
41  import net.sf.magicproject.event.phase.BeginningPhase;
42  import net.sf.magicproject.event.phase.EndOfPhase;
43  import net.sf.magicproject.modifier.ModifierFactory;
44  import net.sf.magicproject.modifier.StaticModifierModel;
45  import net.sf.magicproject.stack.phasetype.PhaseType;
46  import net.sf.magicproject.token.IdConst;
47  import net.sf.magicproject.token.IdTokens;
48  import net.sf.magicproject.token.MCommonVars;
49  import net.sf.magicproject.tools.Log;
50  import net.sf.magicproject.tools.MToolKit;
51  import net.sf.magicproject.ui.MagicUIComponents;
52  import net.sf.magicproject.ui.UIHelper;
53  import net.sf.magicproject.ui.i18n.LanguageManager;
54  import net.sf.magicproject.zone.ZoneManager;
55  
56  import org.apache.commons.io.IOUtils;
57  
58  /***
59   * This class manage the turn structure : phase order, loop and phase's UI
60   * manager(highlightment, breakpoints, pass)
61   * 
62   * @since 0.21 a graphical representation of phase
63   * @since 0.30 an option "auto play single "YOU MUST" ability is suported
64   * @since 0.30 an option "skip all" is suported
65   * @since 0.31 an option "skip all even opponent's spell" is suported
66   * @since 0.31 graphical representation of phases for both players
67   * @since 0.31 attack phase is suported
68   * @since 0.52 support option PLAYED_ONCE_BY_PHASE and AUTOMATICALLY_PLAYED
69   * @since 0.53 turns are counted
70   * @since 0.80 BEFORE_PHASE and END_OF_PHASE_... event can be replaced.
71   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
72   */
73  public final class EventManager {
74  
75  	private static final String TURN_STR = LanguageManager.getString("turnid")
76  			+ " : ";
77  
78  	/***
79  	 * Create a new instance of this class.
80  	 */
81  	private EventManager() {
82  		super();
83  	}
84  
85  	/***
86  	 * Create an instance of MEventManager by reading a file
87  	 * 
88  	 * @since 0.31 graphical representation of phases for both players
89  	 */
90  	public static void init() {
91  		MPhase.popupMenu = new JPopupMenu();
92  		MPhase.optionsMenu = new JPopupMenu();
93  		JCheckBoxMenuItem item = new JCheckBoxMenuItem(LanguageManager
94  				.getString("breakpoint"), new javax.swing.ImageIcon(IdConst.IMAGES_DIR
95  				+ "breakpoint.gif"));
96  		item.setFont(MToolKit.defaultFont);
97  		item.setToolTipText("<html>"
98  				+ LanguageManager.getString("breakpoint.tooltip"));
99  		item.setMnemonic('b');
100 		item.addActionListener(new ActionListener() {
101 			public void actionPerformed(ActionEvent evt) {
102 				MPhase.triggerPhase.setBreakpoint(((JCheckBoxMenuItem) evt.getSource())
103 						.isSelected());
104 				MPhase.triggerPhase.repaint();
105 			}
106 		});
107 		MPhase.optionsMenu.add(item);
108 		item = new JCheckBoxMenuItem(LanguageManager.getString("skipPhase"),
109 				UIHelper.getIcon("skipall1.gif"));
110 		item.setFont(MToolKit.defaultFont);
111 		item.setToolTipText("<html>"
112 				+ LanguageManager.getString("skipPhase.tooltip"));
113 		item.setMnemonic('l');
114 		item.addActionListener(new ActionListener() {
115 			public void actionPerformed(ActionEvent evt) {
116 				MPhase.triggerPhase.setSkipAll(((JCheckBoxMenuItem) evt.getSource())
117 						.isSelected());
118 				MPhase.triggerPhase.repaint();
119 			}
120 		});
121 		MPhase.optionsMenu.add(item);
122 		item = new JCheckBoxMenuItem(LanguageManager.getString("skipPhaseOnce"),
123 				UIHelper.getIcon("skipall2.gif"));
124 		item.setFont(MToolKit.defaultFont);
125 		item.setToolTipText("<html>"
126 				+ LanguageManager.getString("skipPhaseOnce.tooltip") + "<br><br>"
127 				+ MagicUIComponents.HTML_ICON_TIP
128 				+ LanguageManager.getString("skipPhaseOnceTTtip"));
129 		item.setMnemonic('o');
130 		item.addActionListener(new ActionListener() {
131 			public void actionPerformed(ActionEvent evt) {
132 				MPhase.triggerPhase.setSkipAllTmp(((JCheckBoxMenuItem) evt.getSource())
133 						.isSelected());
134 				MPhase.triggerPhase.repaint();
135 			}
136 		});
137 
138 		MPhase.optionsMenu.add(item);
139 		item = new JCheckBoxMenuItem(LanguageManager.getString("skipPhaseMedium"),
140 				UIHelper.getIcon("skipallm2.gif"));
141 		item.setFont(MToolKit.defaultFont);
142 		item.setToolTipText("<html>"
143 				+ LanguageManager.getString("skipPhaseMedium.tooltip") + "<br>"
144 				+ MagicUIComponents.HTML_ICON_WARNING
145 				+ LanguageManager.getString("skipPhaseAllTTwarn"));
146 		item.setMnemonic('m');
147 		item.addActionListener(new ActionListener() {
148 			public void actionPerformed(ActionEvent evt) {
149 				MPhase.triggerPhase.setSkipMedium(((JCheckBoxMenuItem) evt.getSource())
150 						.isSelected());
151 				MPhase.triggerPhase.repaint();
152 			}
153 		});
154 		MPhase.optionsMenu.add(item);
155 		item = new JCheckBoxMenuItem(LanguageManager
156 				.getString("skipPhaseMediumOnce"), UIHelper.getIcon("skipallm.gif"));
157 		item.setFont(MToolKit.defaultFont);
158 		item.setToolTipText("<html>"
159 				+ LanguageManager.getString("skipPhaseMediumOnce.tooltip") + "<br>"
160 				+ MagicUIComponents.HTML_ICON_WARNING
161 				+ LanguageManager.getString("skipPhaseAllTTwarn"));
162 		item.setMnemonic('p');
163 		item.addActionListener(new ActionListener() {
164 			public void actionPerformed(ActionEvent evt) {
165 				MPhase.triggerPhase.setSkipMediumTmp(((JCheckBoxMenuItem) evt
166 						.getSource()).isSelected());
167 				MPhase.triggerPhase.repaint();
168 			}
169 		});
170 
171 		MPhase.optionsMenu.add(item);
172 		item = new JCheckBoxMenuItem(LanguageManager.getString("skipPhaseAll"),
173 				UIHelper.getIcon("skipall3.gif"));
174 		item.setFont(MToolKit.defaultFont);
175 		item.setToolTipText("<html>"
176 				+ LanguageManager.getString("skipPhaseAll.tooltip") + "<br>"
177 				+ MagicUIComponents.HTML_ICON_WARNING
178 				+ LanguageManager.getString("skipPhaseAllTTwarn"));
179 		item.setMnemonic('u');
180 		item.addActionListener(new ActionListener() {
181 			public void actionPerformed(ActionEvent evt) {
182 				MPhase.triggerPhase
183 						.setSkipAllVery(((JCheckBoxMenuItem) evt.getSource()).isSelected());
184 				MPhase.triggerPhase.repaint();
185 			}
186 		});
187 		MPhase.optionsMenu.add(item);
188 		item = new JCheckBoxMenuItem(LanguageManager.getString("skipPhaseAllOnce"),
189 				UIHelper.getIcon("skipall4.gif"));
190 		item.setFont(MToolKit.defaultFont);
191 		item.setToolTipText("<html>"
192 				+ LanguageManager.getString("skipPhaseAllOnce.tooltip") + "<br>"
193 				+ MagicUIComponents.HTML_ICON_WARNING
194 				+ LanguageManager.getString("skipPhaseAllTTwarn"));
195 		item.setMnemonic('t');
196 		item.addActionListener(new ActionListener() {
197 			public void actionPerformed(ActionEvent evt) {
198 				MPhase.triggerPhase.setSkipAllVeryTmp(((JCheckBoxMenuItem) evt
199 						.getSource()).isSelected());
200 				MPhase.triggerPhase.repaint();
201 			}
202 		});
203 		MPhase.optionsMenu.add(item);
204 	}
205 
206 	/***
207 	 * remove all events in the stack of this phase, read new system abilities,
208 	 * turn structure and set the current phase.
209 	 * <ul>
210 	 * Structure of InputStream : Data[size]
211 	 * <li>number of phases type [1]</li>
212 	 * <li>phases type i [...]</li>
213 	 * <li>number of phases in one turn [1]</li>
214 	 * <li>phase identifiant i [1]</li>
215 	 * <li>phase index (not identifiant) for first turn [1]</li>
216 	 * <li>number of statebased ability of play [1]</li>
217 	 * <li>statebased ability i [...]</li>
218 	 * <li>number of static modifier of game [1]</li>
219 	 * <li>static modifier of game i [...]</li>
220 	 * </ul>
221 	 * 
222 	 * @param dbStream
223 	 *          the mdb file containing rules
224 	 * @param settingFile
225 	 *          setting file attached to this mdb
226 	 * @throws IOException
227 	 */
228 	public static void init(FileInputStream dbStream, String settingFile)
229 			throws IOException {
230 		nextCurrentPlayer = -1;
231 		nextPhaseIndex = -1;
232 		turnsLbl.setText(TURN_STR + MCommonVars.registers[IdTokens.TURN_ID]);
233 		MagicUIComponents.logListing.setText("");
234 
235 		// remove all event listener
236 		MEventListener.reset();
237 
238 		// read the different phase types
239 		int nbPhases = dbStream.read();
240 		PhaseType[] phaseTypes = new PhaseType[nbPhases];
241 		while (nbPhases-- > 0) {
242 			PhaseType phaseType = new PhaseType(dbStream);
243 			phaseTypes[phaseType.id] = phaseType;
244 		}
245 
246 		// read the turn structure
247 		int nbPhasesPerTurn = dbStream.read();
248 		turnStructure = new PhaseType[nbPhasesPerTurn];
249 		Log.debug("Turn Structure :");
250 		for (int i = 0; i < nbPhasesPerTurn; i++) {
251 			turnStructure[i] = phaseTypes[dbStream.read()];
252 			Log.debug("\t" + i + ":" + turnStructure[i].phaseName);
253 		}
254 
255 		// first phase index
256 		int startIdPhase = dbStream.read();
257 		Log.debug("First phase of first turn is "
258 				+ turnStructure[startIdPhase].phaseName + "(" + startIdPhase + ")");
259 
260 		// read phases GUI
261 		try {
262 			final InputStream in = MToolKit.getResourceAsStream(settingFile.replace(
263 					".mdb", ".pref"));
264 			MPhase.phases = new MPhase[2][turnStructure.length];
265 			for (int i = 0; i < turnStructure.length; i++) {
266 				MPhase.phases[0][i] = new MPhase(turnStructure[i], 0, in);
267 			}
268 			for (int i = 0; i < EventManager.turnStructure.length; i++) {
269 				MPhase.phases[1][i] = new MPhase(turnStructure[i], 1, in);
270 			}
271 			IOUtils.closeQuietly(in);
272 		} catch (IOException e) {
273 			JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
274 					LanguageManager.getString("loadtbssettingspb") + " : "
275 							+ e.getMessage() + e.getStackTrace()[0], LanguageManager
276 							.getString("error"), JOptionPane.WARNING_MESSAGE);
277 		}
278 
279 		// update the phases GUI
280 		StackManager.PLAYERS[StackManager.idCurrentPlayer].reset(MPhase.phases[StackManager.idCurrentPlayer]);
281 		StackManager.PLAYERS[1-StackManager.idCurrentPlayer].reset(MPhase.phases[1-StackManager.idCurrentPlayer]);
282 
283 		// read triggered abilities of play
284 		int nbTriggered = dbStream.read();
285 		Log.debug("System abilities (" + nbTriggered + "):");
286 		while (nbTriggered-- > 0) {
287 			// read the ability and register it
288 			AbilityFactory.readAbility(dbStream, SystemCard.instance)
289 					.registerToManager();
290 		}
291 
292 		// reset the breakpoints, options and initialize all phases graphics
293 		MPhase.popupMenu.removeAll();
294 		for (int i = MPhase.phases[0].length; i-- > 1;) {
295 			MPhase.phases[0][i].reset();
296 			MPhase.phases[1][i].reset();
297 		}
298 
299 		// set the current phase to ID__PHASE_MAIN
300 		phaseIndex = startIdPhase - 1;
301 		currentIdPhase = turnStructure[phaseIndex].id;
302 		parsingBeforePhaseEvent = false;
303 		parsingEndPhaseEvent = false;
304 		replacingBefore = false;
305 
306 		// read static-modifiers of game
307 		int nbStaticModifiers = dbStream.read();
308 		Log.debug("Static-modifiers (" + nbStaticModifiers + "):");
309 		while (nbStaticModifiers-- > 0) {
310 			// read the static-modifiers and register them
311 			((StaticModifierModel) ModifierFactory.readModifier(dbStream))
312 					.addModifierFromModel(SystemAbility.instance, SystemCard.instance);
313 		}
314 
315 	}
316 
317 	/***
318 	 * Go to the first phase of first turn
319 	 */
320 	public static void start() {
321 		MagicUIComponents.timer.start();
322 		gotoNextPhase();
323 	}
324 
325 	/***
326 	 * Goto the next phase.For each player (current first), if mana pool isn't
327 	 * empty -> mana burn. phase will be ID__BEFORE_PHASE_UNTAP
328 	 */
329 	public static void gotoNextPhase() {
330 		StackManager.idActivePlayer = StackManager.idCurrentPlayer;
331 		Log.debug("Ending phase " + turnStructure[phaseIndex].phaseName + "("
332 				+ phaseIndex + ")");
333 
334 		/***
335 		 * Since we are currently parsing the BEFORE_PHASE_... event, we do not go
336 		 * to the next pahse, but only return to the last instruction where the
337 		 * markup <code>parsingBeforePhaseEvent</code> has been previously set.
338 		 */
339 		if (parsingBeforePhaseEvent) {
340 			Log
341 					.debug("parsingBeforePhaseEvent is true, gotoNextPhase has been cancelled");
342 		} else {
343 
344 			if (parsingEndPhaseEvent) {
345 				Log.debug("\tEnding AGAIN " + turnStructure[phaseIndex].phaseName + "("
346 						+ phaseIndex + ")");
347 			} else {
348 				if (!EndOfPhase.tryAction(currentIdPhase)) {
349 					// this end of phase has been replaced
350 					Log.debug("\tEnd of Phase " + turnStructure[phaseIndex].phaseName
351 							+ "(" + phaseIndex + ") has been replaced");
352 					return;
353 				}
354 				parsingEndPhaseEvent = true;
355 				EndOfPhase.dispatchEvent();
356 				if (!StackManager.activePlayer().waitTriggeredBufferChoice(false)) {
357 					// Log.debug("parsingPhaseEvent is broken, gotoNextPhase has been
358 					// cancelled");
359 					return;
360 				}
361 				if (!StackManager.isEmpty()) {
362 					throw new IllegalStateException(
363 							"The stack must be empty before going to the next phase, stack="
364 									+ Arrays.toString(ZoneManager.stack.getComponents()));
365 				}
366 			}
367 		}
368 		parsingEndPhaseEvent = false;
369 		replacingBefore = false;
370 
371 		while (true) {
372 
373 			if (StackManager.gameLostProceed) {
374 				return;
375 			}
376 
377 			// change the current player?
378 			if (nextCurrentPlayer != -1) {
379 				StackManager.idCurrentPlayer = nextCurrentPlayer;
380 				nextCurrentPlayer = -1;
381 				/***
382 				 * changing current player make restart the turn even if
383 				 * <code>nextPhaseIndex</code> has been specified
384 				 */
385 				phaseIndex = -1;
386 
387 				/*
388 				 * clear the stored target list of the previous turn, and clear damages
389 				 * of players, all damages should have been resolved, but we remove all
390 				 * MDamage object in the damage list to free memory.
391 				 */
392 				StackManager.SAVED_TARGET_LISTS.clear();
393 				StackManager.PLAYERS[StackManager.idCurrentPlayer].clearDamages();
394 				StackManager.PLAYERS[1-StackManager.idCurrentPlayer].clearDamages();
395 			}
396 
397 			// set the new phase index
398 			if (!parsingBeforePhaseEvent) {
399 				updatePhase();
400 			}
401 
402 			Log.debug("Current phase is : " + turnStructure[phaseIndex].phaseName
403 					+ "(index=" + phaseIndex + ", id=" + currentIdPhase + ")");
404 
405 			StackManager.idActivePlayer = StackManager.idCurrentPlayer;
406 			turnsLbl.setText(TURN_STR + MCommonVars.registers[IdTokens.TURN_ID]);
407 
408 			/***
409 			 * Even if the current phase does not really come (due to a 'skip token'),
410 			 * we raise the 'MEventBeforePhase' event. All abilities triggering this
411 			 * way should have the 'isHidden' tag since no player action is allowed
412 			 * since this is a very special event. After this call, the stack should
413 			 * be empty since abilities are immediatly resolved (triggered -> stacked ->
414 			 * resolved).
415 			 */
416 			if (replacingBefore) {
417 				Log.debug("\t... BeforePhase can no more be replaced");
418 			} else {
419 				replacingBefore = true;
420 				if (!BeforePhase.tryAction(currentIdPhase)) {
421 					return;
422 					// Log.debug("\t... phase has not been replaced");
423 				}
424 			}
425 
426 			if (parsingBeforePhaseEvent) {
427 				Log.debug("\t... BeforePhase event is not raised again");
428 			} else {
429 				parsingBeforePhaseEvent = true;
430 				BeforePhase.dispatchEvent();
431 				if (!StackManager.activePlayer().waitTriggeredBufferChoice(false)) {
432 					return;
433 					// Log.debug("\t... no triggered BeforePhase ability");
434 				}
435 			}
436 			replacingBefore = false;
437 			parsingBeforePhaseEvent = false;
438 
439 			if (nextPhaseIndex != -1 || nextCurrentPlayer != -1) {
440 				if (nextPhaseIndex != -1) {
441 					phaseIndex = nextPhaseIndex - 1;
442 					currentIdPhase = turnStructure[phaseIndex].id;
443 					nextPhaseIndex = -1;
444 				}
445 				if (nextCurrentPlayer != -1) {
446 					StackManager.idCurrentPlayer = nextCurrentPlayer;
447 					StackManager.idActivePlayer = StackManager.idCurrentPlayer;
448 					nextCurrentPlayer = -1;
449 				}
450 			} else {
451 				// The turn structure has not been replaced.
452 				break;
453 			}
454 
455 			updatePhasesGUI();
456 		}
457 
458 		// beginning of phase ... triggered abilities
459 		if (currentPhase().skipThisPhase) {
460 			/*
461 			 * The current phase is marked with a 'skip token', we remove this one,
462 			 * and call the gotoNextPhase() function.
463 			 */
464 			Log.debug("\t-> this phase is skipped");
465 			currentPhase().skipThisPhase = false;
466 			gotoNextPhase();
467 		} else {
468 			/***
469 			 * This phase can really start, and 'Beginning event' is raised. The
470 			 * associated triggerred abilities can be added to the TBZ (triggered
471 			 * buffer zone). So after this call the TBZ may contains many abilities
472 			 * and would be managed later.
473 			 */
474 			BeginningPhase.dispatchEvent();
475 			StackManager.activePlayer().waitTriggeredBufferChoice(true);
476 		}
477 	}
478 
479 	/***
480 	 * 
481 	 */
482 	private static void updatePhase() {
483 		if (nextPhaseIndex != -1) {
484 			phaseIndex = nextPhaseIndex;
485 			currentIdPhase = turnStructure[phaseIndex].id;
486 			nextPhaseIndex = -1;
487 		} else {
488 			phaseIndex = ++phaseIndex % turnStructure.length;
489 			currentIdPhase = turnStructure[phaseIndex].id;
490 		}
491 		updatePhasesGUI();
492 	}
493 
494 	/***
495 	 * Update the phases GUI : colors indicating the current phases, and the
496 	 * handed player
497 	 */
498 	public static void updatePhasesGUI() {
499 		for (int i = MPhase.phases[StackManager.idActivePlayer].length; i-- > 0;) {
500 			MPhase.phases[StackManager.idCurrentPlayer][i].setActive(i == phaseIndex,
501 					StackManager.idCurrentPlayer == StackManager.idCurrentPlayer);
502 			MPhase.phases[1 - StackManager.idCurrentPlayer][i].setActive(false,
503 					StackManager.idCurrentPlayer != StackManager.idCurrentPlayer);
504 		}
505 	}
506 
507 	/***
508 	 * return the phase type associate to the current phase
509 	 * 
510 	 * @return the phase type associate to the current phase
511 	 */
512 	public static PhaseType currentPhaseType() {
513 		return turnStructure[phaseIndex];
514 	}
515 
516 	/***
517 	 * return the phase type associate to the current phase
518 	 * 
519 	 * @return the phase type associate to the current phase
520 	 */
521 	public static MPhase currentPhase() {
522 		return MPhase.phases[StackManager.idCurrentPlayer][phaseIndex];
523 	}
524 
525 	/***
526 	 * Return true if we are currently parsing the "before phase" event.
527 	 * 
528 	 * @return true if we are currently parsing the "before phase" event.
529 	 */
530 	public static boolean parsinfBeforeEnd() {
531 		return parsingBeforePhaseEvent;
532 	}
533 
534 	/***
535 	 * This markup indicates we are currently parsing the BEFORE_PHASE_... event.
536 	 * This token is used by the stack manager to know if the next time the
537 	 * gotoNextPhase() method is called would effectively make going to the next
538 	 * phase or simply skip the already parsing step of the BEFORE_PHASE_...
539 	 * event. Also, when this token is set to true just before the parse begin,
540 	 * and set to false the next time the gotoNextPhase() method would be called
541 	 * by the stack manager. When this markup is set to true, instead of giving
542 	 * priority to player, we resolve the stack as if that player has choosen to
543 	 * decline to response.
544 	 */
545 	private static boolean parsingBeforePhaseEvent;
546 
547 	/***
548 	 * This markup indicates we are currently parsing the END_PHASE_... event.
549 	 * This token is used by the stack manager to release a maximum of stack
550 	 * frames. During the stack resolution, instead of calling the "gotoNextPhase"
551 	 * method, if this markup is true, the process simply return.
552 	 */
553 	public static boolean parsingEndPhaseEvent;
554 
555 	/***
556 	 * is the current idPhase (not the index of phase)
557 	 */
558 	public static int currentIdPhase = 0;
559 
560 	/***
561 	 * The turn label
562 	 */
563 	public static JLabel turnsLbl;
564 
565 	/***
566 	 * The moreInfo label
567 	 */
568 	public static JLabel moreInfoLbl;
569 
570 	/***
571 	 * List of successive phase of any turn
572 	 */
573 	public static PhaseType[] turnStructure;
574 
575 	/***
576 	 * The next 'currentplayer' for the next phase. If -1, the next
577 	 * 'currentplayer' would not change.
578 	 */
579 	public static int nextCurrentPlayer;
580 
581 	/***
582 	 * The next 'currentIdPhase'. If -1, the next phase will follow the turn
583 	 * structure.
584 	 */
585 	public static int nextPhaseIndex;
586 
587 	/***
588 	 * represents the current index of phase
589 	 */
590 	public static int phaseIndex;
591 
592 	/***
593 	 * This markup is used to prevent multiple replacement of "BEFORE_PHASE_..."
594 	 * event since this event can be replaced only once per phase.
595 	 */
596 	private static boolean replacingBefore;
597 
598 }