View Javadoc

1   /*
2    *   Magic-Project 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  package net.sf.magicproject.event;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Map;
26  
27  import net.sf.magicproject.clickable.ability.Ability;
28  import net.sf.magicproject.clickable.ability.Priority;
29  import net.sf.magicproject.clickable.ability.ReplacementAbility;
30  import net.sf.magicproject.clickable.targetable.Targetable;
31  import net.sf.magicproject.clickable.targetable.card.AbstractCard;
32  import net.sf.magicproject.clickable.targetable.card.MCard;
33  import net.sf.magicproject.clickable.targetable.card.SystemCard;
34  import net.sf.magicproject.event.context.MContextCardCardIntInt;
35  import net.sf.magicproject.expression.Expression;
36  import net.sf.magicproject.expression.ExpressionFactory;
37  import net.sf.magicproject.operation.Any;
38  import net.sf.magicproject.operation.Operation;
39  import net.sf.magicproject.operation.OperationFactory;
40  import net.sf.magicproject.stack.StackManager;
41  import net.sf.magicproject.test.Test;
42  import net.sf.magicproject.test.TestFactory;
43  import net.sf.magicproject.token.IdTokens;
44  import net.sf.magicproject.token.Register;
45  
46  /***
47   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
48   * @since 0.54 suport either player, either card registers modification
49   * @since 0.80 the looked for operation is added
50   * @since 0.83 support the general register modification (both player and card)
51   * @since 0.85 useless operation are ignored and not genrated.
52   */
53  public class ModifiedRegister extends TriggeredEvent {
54  
55  	/***
56  	 * Create an instance of MEventModifiedRegister by reading a file Offset's
57  	 * file must pointing on the first byte of this event <br>
58  	 * <ul>
59  	 * Structure of InputStream : Data[size]
60  	 * <li>idZone [1]</li>
61  	 * <li>test for source of modification[Test]</li>
62  	 * <li>test for modified component[Test]</li>
63  	 * <li>operation [Operation]</li>
64  	 * <li>register [Register]</li>
65  	 * <li>index [Expression]</li>
66  	 * </ul>
67  	 * 
68  	 * @param inputFile
69  	 *          is the file containing this event
70  	 * @param card
71  	 *          is the card owning this event
72  	 * @throws IOException
73  	 *           if error occurred during the reading process from the specified
74  	 *           input stream
75  	 */
76  	ModifiedRegister(InputStream inputFile, MCard card) throws IOException {
77  		super(inputFile, card);
78  		testModified = TestFactory.readNextTest(inputFile);
79  		op = OperationFactory.readNextOperation(inputFile);
80  		register = Register.deserialize(inputFile);
81  		index = ExpressionFactory.readNextExpression(inputFile);
82  	}
83  
84  	/***
85  	 * Creates a new instance of MEventModifiedRegister specifying all attributes
86  	 * of this class. All parameters are copied, not cloned. So this new object
87  	 * shares the card and the specified codes
88  	 * 
89  	 * @param idZone
90  	 *          the place constraint to activate this event
91  	 * @param sourceTest
92  	 *          the test applied on card modifying the card.
93  	 * @param testModified
94  	 *          the test applied on the modified component.
95  	 * @param card
96  	 *          is the card owning this card
97  	 * @param op
98  	 *          the looked for operation. Any or specific operation instance.
99  	 * @param register
100 	 *          the modified register
101 	 * @param index
102 	 *          the modified register.
103 	 */
104 	public ModifiedRegister(int idZone, Test sourceTest, Test testModified,
105 			MCard card, Operation op, Register register, Expression index) {
106 		super(idZone, sourceTest, card);
107 		this.testModified = testModified;
108 		this.op = op;
109 		this.register = register;
110 		this.index = index;
111 	}
112 
113 	@Override
114 	public MEventListener clone(MCard card) {
115 		return new ModifiedRegister(idZone, test, testModified, card, op, register,
116 				index);
117 	}
118 
119 	/***
120 	 * Tell if the current event matches with this event. If there is an
121 	 * additional code to check, it'would be checked if the main event matches
122 	 * with the main event
123 	 * 
124 	 * @param ability
125 	 *          is the ability owning this test. The card component of this
126 	 *          ability should correspond to the card owning this test too.
127 	 * @param modified
128 	 *          the component containing the modified register. May be null if the
129 	 *          container was not a card.
130 	 * @param source
131 	 *          the card modifying the requested register.
132 	 * @param op
133 	 *          the looked for operation triggering this event
134 	 * @param register
135 	 *          the modified register
136 	 * @param index
137 	 *          the modified register's index
138 	 * @return true if the current event match with this event
139 	 */
140 	protected boolean isMatching(Ability ability, Targetable modified,
141 			MCard source, Operation op, int register, int index) {
142 		return (this.register.ordinal() == register || this.register.ordinal() == IdTokens.TARGET)
143 				&& index == this.index.getValue(ability, modified, null)
144 				&& (this.op == op || this.op == Any.getInstance())
145 				&& testModified.test(ability, modified) && test(ability, source);
146 	}
147 
148 	/***
149 	 * Dispatch this event to all active event listeners able to understand this
150 	 * event. The listening events able to understand this event are <code>this
151 	 * </code>
152 	 * and other multiple event listeners. For each event listeners having
153 	 * responded they have been activated, the corresponding ability is added to
154 	 * the triggered buffer zone of player owning this ability
155 	 * 
156 	 * @param modified
157 	 *          the component containing the modified register. May be null if the
158 	 *          container was not a card.
159 	 * @param pSource
160 	 *          the card modifying the requested register.
161 	 * @param register
162 	 *          the modified register
163 	 * @param index
164 	 *          the modified register's index
165 	 * @param op
166 	 *          the operation
167 	 * @param rightValue
168 	 *          the right value of this modification
169 	 * @since 0.85 useless operation are ignored and not genrated.
170 	 */
171 	public static final void dispatchEvent(Targetable modified, MCard pSource,
172 			int register, int index, Operation op, int rightValue) {
173 		MCard source = pSource;
174 		if (source == SystemCard.instance
175 				&& StackManager.getInstance().getAbilityContext() != null
176 				&& StackManager.triggered.getAbilityContext() instanceof MContextCardCardIntInt
177 				&& ((MContextCardCardIntInt) StackManager.triggered.getAbilityContext())
178 						.getCard2() != null) {
179 			source = ((MContextCardCardIntInt) StackManager.triggered
180 					.getAbilityContext()).getCard2();
181 		}
182 
183 		// propagate the existing "context2" value
184 		final int context2 = StackManager.getInstance().getAbilityContext() != null
185 				&& StackManager.triggered.getAbilityContext() instanceof MContextCardCardIntInt ? ((MContextCardCardIntInt) StackManager.triggered
186 				.getAbilityContext()).getValue2()
187 				: index;
188 
189 		for (Ability ability : TRIGGRED_ABILITIES.get(EVENT)) {
190 			try {
191 				if (ability.isMatching()
192 						&& ((ModifiedRegister) ability.eventComing()).isMatching(ability,
193 								modified, source, op, register, index)) {
194 					ability.triggerIt(new MContextCardCardIntInt(modified, source,
195 							rightValue, context2, modified.getTimestamp() + 1, source
196 									.getTimestamp() + 1));
197 				}
198 			} catch (Throwable e) {
199 				e.printStackTrace();
200 				throw new InternalError("Error while testing ability : " + ability);
201 			}
202 		}
203 	}
204 
205 	/***
206 	 * /** Dispatch this event to replacement abilites only. If one or several
207 	 * abilities have been activated this way, this function will return false.
208 	 * The return value must be checked. In case of <code>false</code> value,
209 	 * the caller should not call any stack resolution since activated abilities
210 	 * are being played.
211 	 * 
212 	 * @param modified
213 	 *          the component containing the modified register. May be null if the
214 	 *          container was not a card.
215 	 * @param pSource
216 	 *          the card modifying the requested register.
217 	 * @param register
218 	 *          the modified register
219 	 * @param index
220 	 *          the modified register's index
221 	 * @param op
222 	 *          the operation
223 	 * @param rightValue
224 	 *          the right value of this modification
225 	 * @return true if and only if no replacement abilities have been activated
226 	 */
227 	public static final boolean tryAction(Targetable modified, MCard pSource,
228 			int register, int index, Operation op, int rightValue) {
229 		MCard source = pSource;
230 		if (pSource == SystemCard.instance
231 				&& StackManager.getInstance().getAbilityContext() != null
232 				&& StackManager.triggered.getAbilityContext() instanceof MContextCardCardIntInt
233 				&& ((MContextCardCardIntInt) StackManager.triggered.getAbilityContext())
234 						.getCard2() != null) {
235 			source = ((MContextCardCardIntInt) StackManager.triggered
236 					.getAbilityContext()).getCard2();
237 		}
238 
239 		final int context2 = StackManager.getInstance().getAbilityContext() != null
240 				&& StackManager.triggered.getAbilityContext() instanceof MContextCardCardIntInt ? ((MContextCardCardIntInt) StackManager.triggered
241 				.getAbilityContext()).getValue2()
242 				: 0;
243 
244 		final Map<Priority, List<ReplacementAbility>> map = getReplacementAbilities(EVENT);
245 		for (Priority priority : Priority.values()) {
246 			List<AbstractCard> result = null;
247 			for (ReplacementAbility ability : map.get(priority)) {
248 				if (((ModifiedRegister) ability.eventComing()).isMatching(ability,
249 						modified, source, op, register, index)) {
250 					if (result == null) {
251 						result = new ArrayList<AbstractCard>();
252 					}
253 					result.add(ability.getTriggeredClone(new MContextCardCardIntInt(
254 							modified, source, rightValue, context2)));
255 				}
256 			}
257 			if (!manageReplacement(source, result, "modified register")) {
258 				return false;
259 			}
260 		}
261 		return true;
262 	}
263 
264 	@Override
265 	public final Event getIdEvent() {
266 		return EVENT;
267 	}
268 
269 	/***
270 	 * The event type.
271 	 */
272 	public static final Event EVENT = Event.MODIFIED_REGISTER;
273 
274 	/***
275 	 * The token we are looking for
276 	 */
277 	protected Register register;
278 
279 	/***
280 	 * The register index
281 	 */
282 	protected Expression index;
283 
284 	/***
285 	 * represent the test of the modified component
286 	 */
287 	protected Test testModified;
288 
289 	/***
290 	 * The looked for operation
291 	 */
292 	protected Operation op;
293 }