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.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  	// private Image targetPicture;
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") + "'>&nbsp;"
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 			// Target is a player or card
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 			// no valid target
175 			return false;
176 		case IdTokens.PLAYER:
177 			// Target is a player
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 			// no valid player
188 			return false;
189 		case IdTokens.CARD:
190 			// Target is a card
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 			// no valid card
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 		// Is there a spell under the cursor?
298 		StackContext stackContext = this.stackContext;
299 		if (stackContext == null) {
300 			stackContext = StackManager.getInstance();
301 		}
302 
303 		// Is it the souce?
304 		if (stackContext.getSourceCard() == targetable) {
305 			return STR_SOURCE; // Now "Source" text is no more printed "S";
306 		}
307 
308 		int id = -1;
309 		if (stackContext.getTargetedList() != null) {
310 			id = stackContext.getTargetedList().list.indexOf(targetable);
311 		}
312 		// Is it a target?
313 		if (id < 0) {
314 			// Is this component is in the context
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 		// Return the target Id
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 }