View Javadoc

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