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