1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.magicproject.stack;
20
21 import java.awt.Image;
22 import java.awt.Toolkit;
23
24 import net.sf.magicproject.clickable.ability.Ability;
25 import net.sf.magicproject.clickable.targetable.Targetable;
26 import net.sf.magicproject.clickable.targetable.card.MCard;
27 import net.sf.magicproject.event.context.ContextEventListener;
28 import net.sf.magicproject.event.context.MContextCardCardIntInt;
29 import net.sf.magicproject.event.context.MContextMtargetable;
30 import net.sf.magicproject.test.Test;
31 import net.sf.magicproject.token.IdConst;
32 import net.sf.magicproject.token.IdTargets;
33 import net.sf.magicproject.token.IdTokens;
34 import net.sf.magicproject.tools.MToolKit;
35 import net.sf.magicproject.ui.MagicUIComponents;
36 import net.sf.magicproject.ui.TargetGlassPane;
37 import net.sf.magicproject.ui.i18n.LanguageManager;
38
39 /***
40 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
41 * @since 0.90
42 */
43 public final class TargetHelper {
44
45 /***
46 * Code to represent the source of target action.
47 */
48 public static final String STR_SOURCE = "S";
49
50 /***
51 * Code to represent the context of a spell.
52 */
53 public static final String STR_CONTEXT1 = "C1";
54
55 /***
56 * Code to represent the context2 of a spell.
57 */
58 public static final String STR_CONTEXT2 = "C2";
59
60 /***
61 * Picture used to draw a targeted component over the Glass pane.
62 */
63
64 /***
65 * Picture used to draw a targeted component when it is added to the current
66 * target list..
67 */
68 private Image targetPictureSml;
69
70 /***
71 * Url picture used to draw a targeted component when it is added to the
72 * current target list. The returned picture is a 12 x 12 one.
73 */
74 private String targetPictureUrl;
75
76 /***
77 * Glasspane instance
78 */
79 private final TargetGlassPane targetGlassPane;
80
81 /***
82 * Create a new instance of this class.
83 */
84 private TargetHelper() {
85 targetGlassPane = new TargetGlassPane();
86 targetPictureSml = Toolkit.getDefaultToolkit().getImage(
87 IdConst.IMAGES_DIR + "target_sml.gif");
88 targetPictureUrl = "<br><img src='file:///"
89 + MToolKit.getIconPath("target_sml.gif") + "'> "
90 + LanguageManager.getString("target.istargeted");
91 }
92
93 /***
94 * Unique instance of this class.
95 */
96 private static TargetHelper instance;
97
98 /***
99 * Return the unique instance of this class.
100 *
101 * @return the unique instance of this class.
102 */
103 public static TargetHelper getInstance() {
104 if (instance == null) {
105 instance = new TargetHelper();
106 }
107 return instance;
108 }
109
110 /***
111 * Return <code>true</code> when there is the required amount of valid
112 * targets.
113 *
114 * @param ability
115 * is the ability owning this test. The card component of this
116 * ability should correspond to the card owning this test too.
117 * @param source
118 * the card source of the target. Often is the card owning the
119 * current ability.
120 * @param test
121 * the constraint applied on the target. This test must be true to
122 * make valid a target.
123 * @param type
124 * the target type (player, card, both)
125 * @param choiceMode
126 * the choice mode like random, all, choosen by playerX,...
127 * @param context
128 * the associated context of current ability.
129 * @param restrictionZone
130 * the restriction zone. If is <code>-1</code> the scan would be
131 * processed on all zones.
132 * @param hopCounter
133 * the minimum amount of target looked for. For optimisation purpose.
134 * @param canBePreempted
135 * <code>true</code> if the valid targets can be derterminated
136 * before runtime.
137 * @return <code>true</code> when there is the required amount of valid
138 * targets.
139 */
140 public boolean checkTarget(Ability ability, MCard source, Test test,
141 int type, int choiceMode, ContextEventListener context,
142 int restrictionZone, int hopCounter, boolean canBePreempted) {
143 switch (type) {
144 case IdTokens.DEALTABLE:
145
146 if (choiceMode == IdTargets.ALL) {
147 return true;
148 }
149 if (test(ability, StackManager.PLAYERS[0], test, canBePreempted)) {
150 return true;
151 }
152 if (test(ability, StackManager.PLAYERS[1], test, canBePreempted)) {
153 return true;
154 }
155 if (restrictionZone != -1) {
156 if (StackManager.PLAYERS[0].zoneManager.getContainer(restrictionZone)
157 .countAllCardsOf(test, ability, hopCounter, canBePreempted) >= hopCounter) {
158 return true;
159 }
160 if (StackManager.PLAYERS[1].zoneManager.getContainer(restrictionZone)
161 .countAllCardsOf(test, ability, hopCounter, canBePreempted) >= hopCounter) {
162 return true;
163 }
164 } else {
165 if (StackManager.PLAYERS[0].zoneManager.countAllCardsOf(test, ability,
166 hopCounter, canBePreempted) >= hopCounter) {
167 return true;
168 }
169 if (StackManager.PLAYERS[1].zoneManager.countAllCardsOf(test, ability,
170 hopCounter, canBePreempted) >= hopCounter) {
171 return true;
172 }
173 }
174
175 return false;
176 case IdTokens.PLAYER:
177
178 if (choiceMode == IdTargets.ALL || choiceMode == IdTargets.RANDOM) {
179 return true;
180 }
181 if (test(ability, StackManager.PLAYERS[0], test, canBePreempted)) {
182 return true;
183 }
184 if (test(ability, StackManager.PLAYERS[1], test, canBePreempted)) {
185 return true;
186 }
187
188 return false;
189 case IdTokens.CARD:
190
191 if (choiceMode == IdTargets.ALL) {
192 return true;
193 }
194 if (restrictionZone != -1) {
195 if (StackManager.PLAYERS[0].zoneManager.getContainer(restrictionZone)
196 .countAllCardsOf(test, ability, hopCounter, canBePreempted) >= hopCounter) {
197 return true;
198 }
199 if (StackManager.PLAYERS[1].zoneManager.getContainer(restrictionZone)
200 .countAllCardsOf(test, ability, hopCounter, canBePreempted) >= hopCounter) {
201 return true;
202 }
203 } else {
204 if (StackManager.PLAYERS[0].zoneManager.countAllCardsOf(test, ability,
205 hopCounter, canBePreempted) >= hopCounter) {
206 return true;
207 }
208 if (StackManager.PLAYERS[1].zoneManager.countAllCardsOf(test, ability,
209 hopCounter, canBePreempted) >= hopCounter) {
210 return true;
211 }
212 }
213
214 return false;
215 default:
216 return true;
217 }
218 }
219
220 /***
221 * Return <code>true</code> when there is the required amount of valid
222 * targets.
223 *
224 * @param ability
225 * is the ability owning this test. The card component of this
226 * ability should correspond to the card owning this test too.
227 * @param target
228 * component to test.
229 * @param test
230 * the constraint applied on the target. This test must be true to
231 * make valid a target.
232 * @param canBePreempted
233 * <code>true</code> if the valid targets can be derterminated
234 * before runtime.
235 * @return <code>true</code> when there is the required amount of valid
236 * targets.
237 */
238 private boolean test(Ability ability, Targetable target, Test test,
239 boolean canBePreempted) {
240 if (canBePreempted)
241 return test.test(ability, target);
242 return test.testPreemption(ability, target);
243 }
244
245 /***
246 * Add a target Id displayed on each targeted components.
247 *
248 * @param stackContext
249 * the stack context of source.
250 */
251 public synchronized void addTargetedBy(StackContext stackContext) {
252 this.stackContext = stackContext;
253 targetGlassPane.setStackContext(stackContext);
254 }
255
256 /***
257 * Remove any target Id displayed on targeted components.
258 */
259 public synchronized void removeTargetedBy() {
260 this.stackContext = null;
261 targetGlassPane.setVisible(false);
262 MagicUIComponents.magicForm.setGlassPane(MagicUIComponents.timerPanel);
263 }
264
265 /***
266 * Return picture used to draw a targeted component when it is added to the
267 * current target list. The returned picture is a 12 x 12 one.
268 *
269 * @return Picture used to draw a targeted component when it is added to the
270 * current target list.
271 */
272 public Image getTargetPictureSml() {
273 return targetPictureSml;
274 }
275
276 /***
277 * Return Url picture used to draw a targeted component when it is added to
278 * the current target list. The returned picture is a 12 x 12 one.
279 *
280 * @return Url picture used to draw a targeted component when it is added to
281 * the current target list.
282 */
283 public String getTargetPictureAsUrl() {
284 return targetPictureUrl;
285 }
286
287 /***
288 * Return the target id of given component.
289 *
290 * @param targetable
291 * the component requesting it's target id.
292 * @return the target id (base 1) of given component. Return 'S' value if is
293 * the source. Return a null value if is neither the source, neither a
294 * target.
295 */
296 public String getMyId(Targetable targetable) {
297
298 StackContext stackContext = this.stackContext;
299 if (stackContext == null) {
300 stackContext = StackManager.getInstance();
301 }
302
303
304 if (stackContext.getSourceCard() == targetable) {
305 return STR_SOURCE;
306 }
307
308 int id = -1;
309 if (stackContext.getTargetedList() != null) {
310 id = stackContext.getTargetedList().list.indexOf(targetable);
311 }
312
313 if (id < 0) {
314
315 final ContextEventListener evListener = stackContext.getAbilityContext();
316 if (evListener != null) {
317 if (evListener instanceof MContextMtargetable
318 && ((MContextMtargetable) evListener).getOriginalTargetable() == targetable) {
319 return STR_CONTEXT1;
320 }
321 if (evListener instanceof MContextCardCardIntInt
322 && ((MContextCardCardIntInt) evListener).getOriginalCard2() == targetable) {
323 return STR_CONTEXT2;
324 }
325 }
326 return null;
327 }
328
329
330 return String.valueOf(id + 1);
331 }
332
333 /***
334 * The active StackElement component. May be <code>null</code>.
335 */
336 private StackContext stackContext;
337 }