View Javadoc

1   /*
2    * Created on 27 janv. 2004
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  package net.sf.magicproject.event;
22  
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Map;
28  
29  import net.sf.magicproject.clickable.ability.Ability;
30  import net.sf.magicproject.clickable.ability.AbstractAbility;
31  import net.sf.magicproject.clickable.ability.DetachmentAbility;
32  import net.sf.magicproject.clickable.ability.Priority;
33  import net.sf.magicproject.clickable.ability.ReplacementAbility;
34  import net.sf.magicproject.clickable.targetable.card.AbstractCard;
35  import net.sf.magicproject.clickable.targetable.card.MCard;
36  import net.sf.magicproject.clickable.targetable.player.Player;
37  import net.sf.magicproject.event.context.ContextEventListener;
38  import net.sf.magicproject.event.context.MContextCardCardIntInt;
39  import net.sf.magicproject.test.Test;
40  import net.sf.magicproject.test.TestFactory;
41  
42  /***
43   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
44   * @since 0.54
45   * @since 0.80 support replacement
46   */
47  public class MovedCard extends TriggeredEvent {
48  
49  	/***
50  	 * Create an instance of MEventListener by reading a file Offset's file must
51  	 * pointing on the first byte of this event <br>
52  	 * <ul>
53  	 * Structure of InputStream : Data[size]
54  	 * <li>idZone [1]</li>
55  	 * <li>test to apply on source [...]</li>
56  	 * <li>test to apply on destination [...]</li>
57  	 * </ul>
58  	 * 
59  	 * @param inputFile
60  	 *          is the file containing this event
61  	 * @param card
62  	 *          is the card owning this event
63  	 * @throws IOException
64  	 *           if error occurred during the reading process from the specified
65  	 *           input stream
66  	 */
67  	public MovedCard(InputStream inputFile, MCard card) throws IOException {
68  		super(inputFile, card);
69  		testDestination = TestFactory.readNextTest(inputFile);
70  	}
71  
72  	/***
73  	 * Creates a new instance of CanICast specifying all attributes of this class.
74  	 * All parameters are copied, not cloned. So this new object shares the card
75  	 * and the specified codes
76  	 * 
77  	 * @param idPlace
78  	 *          the place constraint to activate this event
79  	 * @param testSource
80  	 *          the test of this event, this one is applied on source
81  	 * @param testDestination
82  	 *          test to apply on destination
83  	 * @param card
84  	 *          is the card owning this card
85  	 */
86  	public MovedCard(int idPlace, Test testSource, Test testDestination,
87  			MCard card) {
88  		super(idPlace, testSource, card);
89  		this.testDestination = testDestination;
90  	}
91  
92  	@Override
93  	public MEventListener clone(MCard card) {
94  		return new MovedCard(idZone, test, testDestination, card);
95  	}
96  
97  	/***
98  	 * Tell if the current event matches with this event. If there is an
99  	 * additional code to check, it'would be checked if the main event matches
100 	 * with the main event
101 	 * 
102 	 * @param movingCard
103 	 *          the moving card
104 	 * @param ability
105 	 *          is the ability owning this test. The card component of this
106 	 *          ability should correspond to the card owning this test too.
107 	 * @return true if the current event match with this event
108 	 */
109 	public boolean isMatching(Ability ability, MCard movingCard) {
110 		return test(ability, movingCard);
111 	}
112 
113 	@Override
114 	public boolean reCheck(ContextEventListener previousContext, Ability ability) {
115 		return super.reCheck(previousContext, ability)
116 				&& testDestination.test(ability,
117 						((MContextCardCardIntInt) previousContext).getCard());
118 	}
119 
120 	/***
121 	 * Dispatch this event to all active event listeners able to understand this
122 	 * event. The listening events able to understand this event are <code>this
123 	 * </code>
124 	 * and other multiple event listeners. For each event listeners having
125 	 * responded they have been activated, the corresponding ability is added to
126 	 * the triggered buffer zone of player owning this ability
127 	 * 
128 	 * @param movingCard
129 	 *          the moving card
130 	 * @param idPlaceDest
131 	 *          destination zone of this move
132 	 * @param newController
133 	 *          the new controller.
134 	 * @param silentMode
135 	 *          Is the silent mode is enabled for this move.
136 	 * @return true if this action cannot be played, or has been replaced by
137 	 *         another one(s)
138 	 */
139 	public static boolean tryAction(MCard movingCard, int idPlaceDest,
140 			Player newController, boolean silentMode) {
141 		if (silentMode) {
142 			return true;
143 		}
144 		final Map<Priority, List<ReplacementAbility>> map = getReplacementAbilities(EVENT);
145 		for (Priority priority : Priority.values()) {
146 			List<AbstractCard> result = null;
147 			final int previousPlace = movingCard.getIdZone();
148 			final Player previousController = movingCard.controller;
149 			movingCard.controller = newController;
150 			for (ReplacementAbility ability : map.get(priority)) {
151 				// save the previous place before simulating the movement
152 				if (((MovedCard) ability.eventComing()).isMatching(ability, movingCard)
153 						&& ability.isMatching()) {
154 					/*
155 					 * simulate the movement, and then restore the real card zone, this
156 					 * cheat is needed since the 'MovedCard' event is a two pass event
157 					 */
158 					movingCard.setIdZone(idPlaceDest);
159 					if (((MovedCard) ability.eventComing()).testDestination.test(ability,
160 							movingCard)) {
161 						// the second pass succeed, this replacement is valid
162 						if (result == null) {
163 							result = new ArrayList<AbstractCard>();
164 						}
165 						result.add(ability.getTriggeredClone(new MContextCardCardIntInt(
166 								movingCard, null, idPlaceDest, newController.idPlayer)));
167 					}
168 					movingCard.setIdZone(previousPlace);
169 				}
170 			}
171 			if (result != null) {
172 				// unregister useless abilities from the eventManager
173 				movingCard.unregisterAbilities();
174 				manageReplacement(movingCard, result, "moved card");
175 				return false;
176 			}
177 			movingCard.controller = previousController;
178 		}
179 		return true;
180 	}
181 
182 	/***
183 	 * Dispatch this event to all active event listeners able to understand this
184 	 * event. The listening events able to understand this event are <code>this
185 	 * </code>
186 	 * and other multiple event listeners. For each event listeners having
187 	 * responded they have been activated, the corresponding ability is added to
188 	 * the triggered buffer zone of player owning this ability
189 	 * 
190 	 * @param movingCard
191 	 *          the moving card
192 	 * @param idPlaceDest
193 	 *          destination zone of this move
194 	 * @param newController
195 	 *          the new controller.
196 	 * @param silentMode
197 	 *          Is the silent mode is enabled for this move.
198 	 */
199 	public static void dispatchEvent(MCard movingCard, int idPlaceDest,
200 			Player newController, boolean silentMode) {
201 		for (Ability ability : TRIGGRED_ABILITIES.get(EVENT)) {
202 			if ((!silentMode || (ability instanceof AbstractAbility && !(ability instanceof DetachmentAbility)))
203 					&& ((MovedCard) ability.eventComing())
204 							.isMatching(ability, movingCard) && ability.isMatching()) {
205 				ability.triggerIt(new MContextCardCardIntInt(movingCard, null,
206 						idPlaceDest, newController.idPlayer, movingCard.getTimestamp() + 1,
207 						-1));
208 			}
209 		}
210 	}
211 
212 	@Override
213 	public final Event getIdEvent() {
214 		return EVENT;
215 	}
216 
217 	@Override
218 	public boolean equals(Object other) {
219 		return other instanceof MovedCard && ((MovedCard) other).test == test
220 				&& ((MovedCard) other).testDestination == testDestination;
221 	}
222 
223 	/***
224 	 * The event type.
225 	 */
226 	public static final Event EVENT = Event.MOVING_CARD;
227 
228 	/***
229 	 * test of card destination
230 	 */
231 	private final Test testDestination;
232 
233 }