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.action;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  
28  import net.sf.firemox.action.context.ActionContextWrapper;
29  import net.sf.firemox.action.context.MoveContext;
30  import net.sf.firemox.action.handler.FollowAction;
31  import net.sf.firemox.clickable.ability.Ability;
32  import net.sf.firemox.clickable.target.Target;
33  import net.sf.firemox.clickable.target.card.MCard;
34  import net.sf.firemox.clickable.target.player.Player;
35  import net.sf.firemox.event.Detached;
36  import net.sf.firemox.event.MovedCard;
37  import net.sf.firemox.event.context.ContextEventListener;
38  import net.sf.firemox.network.ConnectionManager;
39  import net.sf.firemox.network.message.CoreMessageType;
40  import net.sf.firemox.stack.StackManager;
41  import net.sf.firemox.test.TestOn;
42  import net.sf.firemox.token.IdPositions;
43  import net.sf.firemox.token.IdZones;
44  import net.sf.firemox.tools.Log;
45  import net.sf.firemox.tools.MToolKit;
46  import net.sf.firemox.ui.i18n.LanguageManagerMDB;
47  import net.sf.firemox.ui.wizard.Arrange;
48  import net.sf.firemox.ui.wizard.Wizard;
49  import net.sf.firemox.zone.MZone;
50  import net.sf.firemox.zone.ZoneManager;
51  
52  /***
53   * To move the current target list from their place to another. New position
54   * within the new zone, and the new controller have to be specified. <br>
55   * 
56   * @version 0.91
57   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
58   * @author <a href="mailto:kismet-sl@users.sourceforge.net">Stefano "Kismet"
59   *         Lenzi</a>
60   * @since 0.54
61   * @since 0.80 activated abilities of card are registered before the 'moved
62   *        card' is generated
63   * @since 0.80 support replacement
64   * @since 0.82 card is moved into the destination zone before the event is
65   *        generated. During the event dispatching there is an incoherence.
66   * @since 0.82 timestamp is checked
67   * @since 0.82 if there are several cards to move, controller chooses order
68   * @since 0.86 action ignore non-card element present in the target list
69   */
70  public class MoveCard extends UserAction implements LoopAction, FollowAction,
71  		BackgroundMessaging, AccessibleContext {
72  
73  	/***
74  	 * Create an instance of MoveCardList by reading a file Offset's file must
75  	 * pointing on the first byte of this action <br>
76  	 * <ul>
77  	 * Structure of InputStream : Data[size]
78  	 * <li>new controller [TestOn]</li>
79  	 * <li>destination zone [IdZone]</li>
80  	 * <li>idPosition [int16]</li>
81  	 * <li>silent [boolean]</li>
82  	 * </ul>
83  	 * 
84  	 * @param inputFile
85  	 *          file containing this action
86  	 * @throws IOException
87  	 *           if error occurred during the reading process from the specified
88  	 *           input stream
89  	 */
90  	MoveCard(InputStream inputFile) throws IOException {
91  		super(inputFile);
92  		controller = TestOn.deserialize(inputFile);
93  		destination = inputFile.read();
94  		idPosition = MToolKit.readInt16(inputFile);
95  		silent = inputFile.read() == 1;
96  	}
97  
98  	public final void replayAction(ContextEventListener context, Ability ability,
99  			Wizard wizard) {
100 		wizard.setVisible(true);
101 		if (Wizard.optionAnswer != Wizard.BACKGROUND_OPTION) {
102 			// valid answer
103 			boolean taken = false;
104 			if (!StackManager.noReplayToken.takeNoBlock()) {
105 				taken = true;
106 			}
107 
108 			final List<MCard> toBeSortedCardsCurrent = new ArrayList<MCard>();
109 			final List<MCard> toBeSortedCardsNonCurrent = new ArrayList<MCard>();
110 			fillList(toBeSortedCardsCurrent, toBeSortedCardsNonCurrent);
111 			final int[] order = ((Arrange) wizard).order;
112 			final byte[] toSend = new byte[order.length];
113 			if (((Arrange) wizard).owner == StackManager.currentPlayer()) {
114 				// current player (you) has arranged these cards
115 
116 				for (int i = order.length; i-- > 0;) {
117 					toSend[i] = (byte) order[i];
118 					StackManager.getTargetListAccess().remove(
119 							toBeSortedCardsCurrent.get(order[i]));
120 					StackManager.getTargetListAccess().add(
121 							toBeSortedCardsCurrent.get(order[i]));
122 				}
123 				// we send our choice
124 				Log.debug("Order sent : " + Arrays.toString(toSend));
125 				ConnectionManager.send(CoreMessageType.MOVE_ORDER_ANSWER, toSend);
126 
127 				// then, check the cards owned by non-current player
128 				if (toBeSortedCardsNonCurrent.size() > 1) {
129 					// now we wait the non current player choice
130 					Log.debug("Opponent is arranging moving cards he/she owns");
131 					StackManager.currentPlayer().getOpponent().setHandedPlayer();
132 					// stop here since the recursive call manages the non-current case
133 				} else {
134 					// all is done : current and non-current player have made their choice
135 					StackManager.actionManager.loopingIndex = StackManager
136 							.getTargetListAccess().size();
137 
138 					// free the locking-token
139 					if (taken) {
140 						StackManager.noReplayToken.release();
141 					}
142 
143 					StackManager.resolveStack();
144 				}
145 			} else {
146 				// non current player (you) has arranged these cards
147 
148 				for (int i = order.length; i-- > 0;) {
149 					toSend[i] = (byte) order[i];
150 					StackManager.getTargetListAccess().remove(
151 							toBeSortedCardsNonCurrent.get(order[i]));
152 					StackManager.getTargetListAccess().add(
153 							toBeSortedCardsNonCurrent.get(order[i]));
154 				}
155 
156 				// we send our choice
157 				Log.debug("Order sent : " + Arrays.toString(toSend));
158 				ConnectionManager.send(CoreMessageType.MOVE_ORDER_ANSWER, toSend);
159 
160 				// all is done : current and non-current player have made their choice
161 				StackManager.actionManager.loopingIndex = StackManager
162 						.getTargetListAccess().size();
163 
164 				// free the locking-token
165 				if (taken) {
166 					StackManager.noReplayToken.release();
167 				}
168 
169 				StackManager.resolveStack();
170 			}
171 		}
172 	}
173 
174 	/***
175 	 * return the id of this action. This action has been read from the MDB file.
176 	 * 
177 	 * @see Actiontype
178 	 * @return the id of this action
179 	 */
180 	@Override
181 	public final Actiontype getIdAction() {
182 		return Actiontype.MOVE_CARD;
183 	}
184 
185 	/***
186 	 * Move a card in a zone with a specified new controller.
187 	 * 
188 	 * @param card
189 	 *          the card to move.
190 	 * @param controller
191 	 *          the new controller.
192 	 * @param destination
193 	 *          the new zone.
194 	 * @param context
195 	 *          the context of current ability.
196 	 * @param idPosition
197 	 *          the new state of this card.
198 	 * @param ability
199 	 *          the current ability.
200 	 * @param silentMode
201 	 *          Is the silent mode is enabled while playing.
202 	 * @return true if the card has been moved.
203 	 */
204 	public static boolean moveCard(MCard card, TestOn controller,
205 			int destination, ContextEventListener context, int idPosition,
206 			Ability ability, boolean silentMode) {
207 
208 		// check timestamp
209 		if (!checkTimeStamp(context, card)) {
210 			// we ignore this action
211 			return true;
212 		}
213 
214 		return moveCard(card, (Player) controller.getTargetable(ability, card,
215 				context, null), destination, context, idPosition, ability, silentMode);
216 	}
217 
218 	/***
219 	 * @param movingCard
220 	 *          the card to move.
221 	 * @param controller
222 	 *          the new controller.
223 	 * @param destination
224 	 *          the new zone.
225 	 * @param context
226 	 *          the context of current ability.
227 	 * @param idPosition
228 	 *          the new state of this card.
229 	 * @param ability
230 	 *          the current ability.
231 	 * @param silentMode
232 	 *          Is the silent mode is enabled for this move.
233 	 * @return true if the card has been moved.
234 	 */
235 	public static boolean moveCard(MCard movingCard, Player controller,
236 			int destination, ContextEventListener context, int idPosition,
237 			Ability ability, boolean silentMode) {
238 		final MCard card = (MCard) movingCard.getOriginalTargetable();
239 		final int idDestination = MCard.getIdZone(destination, context);
240 		// add new abilities before the card is moved
241 		card.registerReplacementAbilities(idDestination);
242 		if (!MovedCard.tryAction(card, idDestination, controller, silentMode)) {
243 			// this action has been replaced
244 			return false;
245 		}
246 
247 		if (idDestination == IdZones.PLAY) {
248 			/*
249 			 * the card comes into play : the card is moved before the 'moved' event
250 			 * is generated.
251 			 */
252 			final int previousIdZone = card.getIdZone();
253 			card.moveCard(idDestination, controller,
254 					(destination & IdZones.PLAY_TAPPED) == IdZones.PLAY_TAPPED,
255 					idPosition);
256 
257 			// add the modifiers of this card activated only when card is in play
258 			if (card.getModifierModels() != null && previousIdZone != IdZones.PLAY) {
259 				card.getModifierModels().addModifierFromModel(ability, card);
260 			}
261 
262 			// add new abilities
263 			card.registerAbilities(IdZones.PLAY);
264 
265 			// but we do not update the idZone now.
266 			card.setIdZone(previousIdZone);
267 
268 			/*
269 			 * FROM THIS POINT THERE IS AN INCOHERENCE IN MCard#idZone since the card
270 			 * is in a zone Y but MCard#idZone value is X, assuming the card is moving
271 			 * from X to Y
272 			 */
273 
274 			// dispatch the event before performing this action
275 			MovedCard.dispatchEvent(card, idDestination, controller, silentMode);
276 
277 			// we update the idZone now.
278 			card.setIdZone(IdZones.PLAY);
279 
280 			/*
281 			 * FROM THIS POINT THERE IS NO MORE INCOHERENCE IN MCard#idZone
282 			 */
283 		} else {
284 			/*
285 			 * Since the card does not move into play, we proceed as usual : generate
286 			 * events, and then move physically the card.
287 			 */
288 
289 			// dispatch the event before performing this action
290 			MovedCard.dispatchEvent(card, idDestination, controller, silentMode);
291 
292 			// add new abilities
293 			card.registerAbilities(idDestination);
294 
295 			// move now the card
296 			final int previousIdZone = card.getIdZone();
297 			card.moveCard(idDestination, controller, false, idPosition);
298 
299 			// Add the modifiers
300 			if (card.getModifierModels() != null && previousIdZone != idDestination) {
301 				card.getModifierModels().addModifierFromModel(card.getDummyAbility(),
302 						null);
303 			}
304 
305 			// detachment event?
306 			if (previousIdZone == IdZones.PLAY && !silentMode) {
307 				/*
308 				 * since we are leaving play, we generate the event concerning
309 				 * detachment for each components
310 				 */
311 				for (MCard attachedCard : card.getAttachedCards()) {
312 					Detached.dispatchEvent(attachedCard, card);
313 				}
314 			}
315 		}
316 
317 		if (silentMode) {
318 			for (MCard attachedCard : card.getAttachedCards()) {
319 				attachedCard.setIdZone(idDestination);
320 				attachedCard.clearDamages();
321 			}
322 		}
323 
324 		// unregister useless abilities from the eventManager
325 		card.unregisterAbilities();
326 		return true;
327 	}
328 
329 	public boolean continueLoop(ContextEventListener context, int loopingIndex,
330 			Ability ability) {
331 		Log.debug("\t...continue loop, index : " + loopingIndex);
332 		if (!StackManager.getInstance().getTargetedList().get(loopingIndex)
333 				.isCard()
334 				|| moveCard((MCard) StackManager.getInstance().getTargetedList().get(
335 						loopingIndex), controller, destination, context, idPosition,
336 						ability, silent)) {
337 			return true;
338 		}
339 		return false;
340 	}
341 
342 	/***
343 	 * This method is called when the opponent has finished to choose the order of
344 	 * moves.
345 	 * 
346 	 * @param data
347 	 *          array corresponding to the order of cards owned by opponent.
348 	 */
349 	public synchronized void receiveMoveOrder(byte[] data) {
350 		Log.debug("receiveMoveOrder : " + Arrays.toString(data));
351 		final List<MCard> toBeSortedCardsCurrnt = new ArrayList<MCard>();
352 		final List<MCard> toBeSortedCardsNonCurrent = new ArrayList<MCard>();
353 		fillList(toBeSortedCardsCurrnt, toBeSortedCardsNonCurrent);
354 		if (StackManager.currentIsYou()) {
355 			/*
356 			 * we are receiving the move order of non current player, and we have
357 			 * already made our choice since we are the current player. Apply
358 			 * arrangement following specified order.
359 			 */
360 			for (byte i : data) {
361 				StackManager.getTargetListAccess().remove(
362 						toBeSortedCardsNonCurrent.get(i));
363 				StackManager.getTargetListAccess()
364 						.add(toBeSortedCardsNonCurrent.get(i));
365 			}
366 			// Now all players have made their choice, we resolve the stack
367 			StackManager.actionManager.loopingIndex = StackManager
368 					.getTargetListAccess().size();
369 			StackManager.resolveStack();
370 		} else {
371 			/*
372 			 * we are receiving the move order of current player. We are the
373 			 * non-current player. Apply arrangement following specified order.
374 			 */
375 			for (int i = data.length; i-- > 0;) {
376 				StackManager.getTargetListAccess().remove(
377 						toBeSortedCardsCurrnt.get(data[i]));
378 				StackManager.getTargetListAccess().add(
379 						toBeSortedCardsCurrnt.get(data[i]));
380 			}
381 
382 			// and then, the non-current player can make order choice if needed
383 			if (toBeSortedCardsNonCurrent.size() > 1) {
384 				Log.debug("You are arranging moving cards you own");
385 				StackManager.currentPlayer().getOpponent().setHandedPlayer();
386 				replayAction(StackManager.getInstance().getAbilityContext(),
387 						StackManager.currentAbility, new Arrange(MCard.getIdZone(
388 								destination, StackManager.getInstance().getAbilityContext()),
389 								toBeSortedCardsNonCurrent, new int[toBeSortedCardsNonCurrent
390 										.size()], StackManager.currentPlayer().getOpponent()));
391 			} else {
392 				// all is done : current and non-current player have made their choice
393 				StackManager.actionManager.loopingIndex = StackManager
394 						.getTargetListAccess().size();
395 				StackManager.resolveStack();
396 			}
397 		}
398 	}
399 
400 	private void fillList(List<MCard> toBeSortedCardsCurrnt,
401 			List<MCard> toBeSortedCardsNonCurrent) {
402 		/*
403 		 * list all cards controlled by CURRENT player in order to put them in the
404 		 * destination zone
405 		 */
406 		for (int i = 0; i < StackManager.getInstance().getTargetedList().size(); i++) {
407 			if (StackManager.getInstance().getTargetedList().get(i).isCard()) {
408 				if (((MCard) StackManager.getInstance().getTargetedList().get(i))
409 						.getOwner().isCurrentPlayer()) {
410 					toBeSortedCardsCurrnt.add((MCard) StackManager.getTargetListAccess()
411 							.get(i));
412 				} else {
413 					toBeSortedCardsNonCurrent.add((MCard) StackManager
414 							.getTargetListAccess().get(i));
415 				}
416 			}
417 		}
418 	}
419 
420 	public synchronized int getStartIndex() {
421 		final int count = StackManager.getInstance().getTargetedList().size();
422 		final int idDestination = MCard.getIdZone(destination, StackManager
423 				.getInstance().getAbilityContext());
424 		if (count > 1 && idDestination >= IdZones.FIRST_ADDITIONAL_ZONE
425 				&& idDestination <= IdZones.LAST_ADDITIONAL_ZONE) {
426 			final List<MCard> toBeSortedCardsCurrent = new ArrayList<MCard>(count);
427 			final List<MCard> toBeSortedCardsNonCurrent = new ArrayList<MCard>(count);
428 			fillList(toBeSortedCardsCurrent, toBeSortedCardsNonCurrent);
429 
430 			if (toBeSortedCardsCurrent.size() > 1) {
431 				// current player can arrange order of cards
432 				final int[] order = new int[toBeSortedCardsCurrent.size()];
433 				if (StackManager.currentIsYou()) {
434 					Log.debug("You (current player) are arranging moving cards you own");
435 					StackManager.currentPlayer().setHandedPlayer();
436 					replayAction(StackManager.getInstance().getAbilityContext(),
437 							StackManager.currentAbility, new Arrange(idDestination,
438 									toBeSortedCardsCurrent, order, StackManager.currentPlayer()));
439 				} else {
440 					Log
441 							.debug("Opponent (current player) is arranging moving cards he/she owns");
442 					StackManager.currentPlayer().setHandedPlayer();
443 				}
444 				return Integer.MAX_VALUE;
445 			}
446 			if (toBeSortedCardsNonCurrent.size() > 1) {
447 				// now we wait the non current player choice
448 				if (StackManager.currentIsYou()) {
449 					Log
450 							.debug("Opponent (non-current player) is arranging moving cards he/she owns");
451 					StackManager.currentPlayer().getOpponent().setHandedPlayer();
452 				} else {
453 					Log
454 							.debug("You (non-current player) are arranging moving cards you own");
455 					StackManager.currentPlayer().getOpponent().setHandedPlayer();
456 					final int[] order = new int[toBeSortedCardsNonCurrent.size()];
457 					StackManager.currentPlayer().getOpponent().setHandedPlayer();
458 					replayAction(StackManager.getInstance().getAbilityContext(),
459 							StackManager.currentAbility, new Arrange(idDestination,
460 									toBeSortedCardsNonCurrent, order, StackManager
461 											.currentPlayer().getOpponent()));
462 				}
463 				return Integer.MAX_VALUE;
464 			}
465 		}
466 		return count - 1;
467 	}
468 
469 	public void rollback(ActionContextWrapper actionContext,
470 			ContextEventListener context, Ability ability) {
471 		final MoveContext bContext = (MoveContext) actionContext.actionContext;
472 		for (int loopingIndex = 0; loopingIndex < StackManager.getInstance()
473 				.getTargetedList().size(); loopingIndex++) {
474 			if (StackManager.getInstance().getTargetedList().get(loopingIndex)
475 					.isCard()) {
476 				final MCard card = (MCard) ((MCard) StackManager.getInstance()
477 						.getTargetedList().get(loopingIndex)).getOriginalTargetable();
478 				final MZone zoneSrc = card.controller.zoneManager.getContainer(card
479 						.getIdZone());
480 
481 				zoneSrc.remove(card);
482 				card.setIdZone(bContext.idZones[loopingIndex]);
483 				card.controller = bContext.controllers[loopingIndex];
484 				if (bContext.attachedTo[loopingIndex] != null) {
485 					bContext.attachedTo[loopingIndex].add(card);
486 					// this card was attached to another one in play
487 					bContext.attachedTo[loopingIndex].getMUI().updateLayout();
488 				}
489 
490 				// update positions and controller
491 				card.isHighLighted = false;
492 				card.reversed = card.needReverse();
493 				card.getMUI().updateLayout();
494 
495 				// move to the destination this card
496 				switch (bContext.idZones[loopingIndex]) {
497 				case IdZones.PLAY:
498 					// update card UI
499 					card.tap(bContext.tapPosition[loopingIndex]);
500 					if ((Integer) bContext.indexes[loopingIndex].value != 0) {
501 						card.controller.zoneManager.play.getCard(
502 								bContext.indexes[loopingIndex].key).add(card,
503 								bContext.indexes[loopingIndex].value.intValue());
504 					} else {
505 						card.controller.zoneManager.play.add(card,
506 								bContext.indexes[loopingIndex].key);
507 					}
508 					break;
509 				case IdZones.NOWHERE:
510 					// the specified card will never be seen again
511 					break;
512 				default:
513 					MZone zone = card.controller.zoneManager
514 							.getContainer(bContext.idZones[loopingIndex]);
515 					if ((Integer) bContext.indexes[loopingIndex].value != 0) {
516 						zone.getCard(bContext.indexes[loopingIndex].key).add(card,
517 								bContext.indexes[loopingIndex].value.intValue());
518 					} else {
519 						zone.add(card, bContext.indexes[loopingIndex].key);
520 					}
521 				}
522 			} else {
523 				Log
524 						.warn("In MOVE-CARD action, target list contains non 'Card' object. Ignored");
525 			}
526 		}
527 	}
528 
529 	public void simulate(ActionContextWrapper actionContext,
530 			ContextEventListener context, Ability ability) {
531 		final MoveContext bContext = new MoveContext(StackManager.getInstance()
532 				.getTargetedList().size());
533 		actionContext.actionContext = bContext;
534 		final int idDestination = MCard.getIdZone(destination, context);
535 		final boolean newIsTapped = (destination & IdZones.PLAY_TAPPED) == IdZones.PLAY_TAPPED;
536 		for (int loopingIndex = StackManager.getInstance().getTargetedList().size(); loopingIndex-- > 0;) {
537 			if (StackManager.getInstance().getTargetedList().get(loopingIndex)
538 					.isCard()) {
539 				final MCard card = (MCard) ((MCard) StackManager.getInstance()
540 						.getTargetedList().get(loopingIndex)).getOriginalTargetable();
541 				final Player newController = (Player) controller.getTargetable(ability,
542 						card, context, null);
543 				final MZone zoneSrc = card.controller.zoneManager.getContainer(card
544 						.getIdZone());
545 				// remove card from it's previous zone
546 				bContext.tapPosition[loopingIndex] = card.tapped;
547 				bContext.controllers[loopingIndex] = card.controller;
548 				bContext.idZones[loopingIndex] = card.getIdZone();
549 				bContext.indexes[loopingIndex] = zoneSrc.getRealIndexOf(card);
550 
551 				if (card.getIdZone() == IdZones.PLAY) {
552 					final MCard attachedTo = card.getParent() instanceof MCard ? (MCard) card
553 							.getParent()
554 							: null;
555 					bContext.attachedTo[loopingIndex] = attachedTo;
556 					zoneSrc.remove(card);
557 					card.tap(false);
558 					if (attachedTo != null) {
559 						// this card was attached to another one in play
560 						attachedTo.getMUI().updateLayout();
561 					}
562 				} else if (card.getParent() != null) {
563 					zoneSrc.remove(card);
564 				}
565 
566 				// update positions ans controller
567 				card.controller = newController;
568 				card.setIdZone(idDestination);
569 				card.isHighLighted = false;
570 				card.reversed = card.needReverse();
571 				card.getMUI().updateLayout();
572 
573 				// move to the destination this card
574 				switch (idDestination) {
575 				case IdZones.PLAY:
576 					// update card UI
577 					card.tap(newIsTapped);
578 					newController.zoneManager.play.addBottom(card);
579 					break;
580 				case IdZones.NOWHERE:
581 					// the specified card will never be seen again
582 					break;
583 				default:
584 					switch (idPosition) {
585 					case IdPositions.ON_THE_TOP:
586 						newController.zoneManager.getContainer(idDestination).addTop(card);
587 						break;
588 					case IdPositions.ON_THE_BOTTOM:
589 					default:
590 						newController.zoneManager.getContainer(idDestination).addBottom(
591 								card);
592 					}
593 				}
594 			} else {
595 				Log
596 						.warn("In MOVE-CARD action, target list contains non 'Card' object. Ignored");
597 			}
598 		}
599 	}
600 
601 	@Override
602 	public String toString(Ability ability) {
603 		if (destination == IdZones.PLAY_TAPPED) {
604 			return LanguageManagerMDB.getString("move-"
605 					+ ZoneManager.getZoneName(IdZones.PLAY) + "-tapped");
606 		}
607 		if (destination == IdZones.PLAY) {
608 			return LanguageManagerMDB.getString("move-"
609 					+ ZoneManager.getZoneName(IdZones.PLAY));
610 		}
611 		if (idPosition == IdPositions.ON_THE_BOTTOM) {
612 			return LanguageManagerMDB.getString("move-"
613 					+ ZoneManager.getZoneName(MCard.getIdZone(destination, null))
614 					+ "-bottom");
615 		}
616 		return LanguageManagerMDB.getString("move-"
617 				+ ZoneManager.getZoneName(MCard.getIdZone(destination, null)) + "-top");
618 	}
619 
620 	/***
621 	 * the destination place
622 	 * 
623 	 * @see IdZones
624 	 */
625 	private final int destination;
626 
627 	/***
628 	 * The new controller
629 	 */
630 	private final TestOn controller;
631 
632 	/***
633 	 * The position where card would be placed
634 	 * 
635 	 * @see net.sf.firemox.token.IdPositions
636 	 */
637 	private final int idPosition;
638 
639 	/***
640 	 * Is the silent mode is enabled while playing.
641 	 */
642 	private final boolean silent;
643 
644 	public int getAccessibleInt(String attribute) {
645 		// TODO complete to support the AccessibleContext pattern
646 		return 0;
647 	}
648 
649 	public Target getAccessibleTargetable(String attribute) {
650 		// TODO complete to support the AccessibleContext pattern
651 		return null;
652 	}
653 
654 	/***
655 	 * Shared attrribute to access to the destination zone id.
656 	 */
657 	// public static final String SHARE_DESTINATION = "destination";
658 	/***
659 	 * Shared attrribute to access to the destination controller player.
660 	 */
661 	// public static final String SHARE_CONTROLLER = "controller";
662 }