1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }