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