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   */
20  package net.sf.magicproject.clickable.targetable;
21  
22  import java.awt.Color;
23  import java.awt.event.ActionEvent;
24  import java.awt.event.ActionListener;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.swing.JMenuItem;
30  import javax.swing.JSeparator;
31  
32  import net.sf.magicproject.action.listener.WaitingAbility;
33  import net.sf.magicproject.clickable.Clickable;
34  import net.sf.magicproject.clickable.ability.Ability;
35  import net.sf.magicproject.clickable.ability.UserAbility;
36  import net.sf.magicproject.clickable.targetable.card.Damage;
37  import net.sf.magicproject.clickable.targetable.card.MCard;
38  import net.sf.magicproject.modifier.ControllerModifier;
39  import net.sf.magicproject.modifier.RegisterIndirection;
40  import net.sf.magicproject.modifier.RegisterModifier;
41  import net.sf.magicproject.stack.StackManager;
42  import net.sf.magicproject.token.IdCommonToken;
43  
44  /***
45   * Represents a target : player or card.
46   * 
47   * @see net.sf.magicproject.xml.tbs.Card
48   * @see net.sf.magicproject.clickable.targetable.player.Player
49   * @version 0.91
50   * @since 0.3
51   * @since 0.90 a map of objects {String, Tragetable} is added.
52   * @since 0.91 removered properties instance variable to CardModel
53   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
54   * @author <a href="mailto:kismet-sl@users.sourceforge.net">Stefano "Kismet"
55   *         Lenzi</a>
56   */
57  public abstract class Targetable extends Clickable implements ActionListener {
58  
59  	/***
60  	 * Private property key "creator"
61  	 */
62  	static final String KEY_CREATOR = "creator";
63  
64  	/***
65  	 * Creates a new instance of MTargetable <br>
66  	 */
67  	public Targetable() {
68  		super();
69  		isHighLighted = false;
70  		setBackground(Color.black);
71  	}
72  
73  	/***
74  	 * remove all damages on this card
75  	 */
76  	public void clearDamages() {
77  		for (int i = getComponentCount(); i-- > 0;) {
78  			if (getComponent(i) instanceof Damage) {
79  				remove(getComponent(i));
80  			}
81  			registers[IdCommonToken.DAMAGE] = 0;
82  		}
83  	}
84  
85  	@Override
86  	public abstract String toString();
87  
88  	/***
89  	 * return true if this targetable is a player
90  	 * 
91  	 * @return true if this targetable is a player
92  	 */
93  	public final boolean isPlayer() {
94  		return !isCard();
95  	}
96  
97  	/***
98  	 * indicates if this target is a card
99  	 * 
100 	 * @return true if this target is a card
101 	 */
102 	public abstract boolean isCard();
103 
104 	/***
105 	 * An ActionListener that listens to the ability choice
106 	 * 
107 	 * @param evt
108 	 *          the event
109 	 */
110 	public void actionPerformed(ActionEvent evt) {
111 		// Only trigger on context menu items
112 		if (evt.getSource() instanceof JMenuItem) {
113 			StackManager.noReplayToken.take();
114 			try {
115 				if (StackManager.idHandedPlayer == 0) {
116 					for (int j = TargetableFactory.abilitiesMenu.getComponentCount(); j-- > 0;) {
117 						if (TargetableFactory.abilitiesMenu.getComponent(j) == evt
118 								.getSource()) {
119 							// is the clicked ability an advanced one ?
120 							boolean advancedMode = false;
121 							for (int i = j; i-- > 0;) {
122 								if (TargetableFactory.abilitiesMenu.getComponent(i) instanceof JSeparator) {
123 									// this is an advanced ability
124 									advancedMode = true;
125 									((UserAbility) ((WaitingAbility) StackManager.actionManager.currentAction)
126 											.advancedAbilitiesOf(TargetableFactory.triggerTargetable)
127 											.get(j - i - 1)).mouseClicked(j - i + 127);
128 									break;
129 								}
130 							}
131 							if (!advancedMode) {
132 								// this is not an advanced ability
133 								((UserAbility) ((WaitingAbility) StackManager.actionManager.currentAction)
134 										.abilitiesOf(TargetableFactory.triggerTargetable).get(j))
135 										.mouseClicked(j);
136 							}
137 							break;
138 						}
139 					}
140 				}
141 			} catch (Throwable t) {
142 				t.printStackTrace();
143 			} finally {
144 				StackManager.noReplayToken.release();
145 			}
146 		}
147 	}
148 
149 	/***
150 	 * The border will be highligthed to a color identifying it easily as a token
151 	 * component.
152 	 */
153 	public final void tokenize() {
154 		highLight(TargetableFactory.TOKENIZE_COLOR);
155 	}
156 
157 	/***
158 	 * The border will be highligthed to a color identifying it easily as a
159 	 * targetable component.
160 	 * 
161 	 * @param highlightedZones
162 	 *          the set of highlighted zone.
163 	 */
164 	public void targetize(boolean... highlightedZones) {
165 		highLight(TargetableFactory.TARGET_COLOR);
166 	}
167 
168 	/***
169 	 * Highlight as "targetable" the list of targetable
170 	 * 
171 	 * @param list
172 	 *          the list of targetable to highlight.
173 	 * @param highlightedZones
174 	 *          the list of highlighted zones
175 	 */
176 	public static void targetize(List<Targetable> list, boolean[] highlightedZones) {
177 		for (Targetable targetable : list) {
178 			targetable.targetize(highlightedZones);
179 		}
180 	}
181 
182 	/***
183 	 * Return the value corresponding to the true register index.
184 	 * 
185 	 * @param index
186 	 *          the register index
187 	 * @return the value corresponding to the true register index.
188 	 */
189 	public abstract int getValue(int index);
190 
191 	/***
192 	 * Return the value corresponding to the true register index.
193 	 * 
194 	 * @param index
195 	 *          the register index
196 	 * @return the value corresponding to the true register index.
197 	 */
198 	public int getValueIndirection(int index) {
199 		return getValue(index);
200 	}
201 
202 	/***
203 	 * Add a modifier to this object
204 	 * 
205 	 * @param modifier
206 	 *          the modifier to add to this object
207 	 * @param index
208 	 *          is the modifier register index
209 	 */
210 	public void addModifier(RegisterModifier modifier, int index) {
211 		if (registerModifiers[index] == null) {
212 			registerModifiers[index] = modifier;
213 		} else {
214 			registerModifiers[index].addModifier(modifier);
215 		}
216 	}
217 
218 	/***
219 	 * Add a modifier to this object
220 	 * 
221 	 * @param modifier
222 	 *          the indirection modifier to add to this object
223 	 * @param index
224 	 *          is the modifier register index
225 	 */
226 	public void addModifier(RegisterIndirection modifier, int index) {
227 		if (indirections[index] == null) {
228 			indirections[index] = modifier;
229 		} else {
230 			indirections[index].addModifier(modifier);
231 		}
232 	}
233 
234 	/***
235 	 * Is this targetable is an abilty or a spell
236 	 * 
237 	 * @return true id this targetable is an ability
238 	 */
239 	public abstract boolean isAbility();
240 
241 	/***
242 	 * Is this targetable is an abilty or a spell
243 	 * 
244 	 * @return true id this targetable is a spell
245 	 */
246 	public abstract boolean isSpell();
247 
248 	/***
249 	 * Remove a register modifier from this component.
250 	 * 
251 	 * @param modifier
252 	 *          the register modifier to remove.
253 	 * @param index
254 	 *          index of register to remove.
255 	 */
256 	public abstract void removeModifier(RegisterModifier modifier, int index);
257 
258 	/***
259 	 * Remove a register-indirection modifier from this component.
260 	 * 
261 	 * @param indirection
262 	 *          the register-indirection modifier to remove.
263 	 * @param index
264 	 *          index of register indirection to remove.
265 	 */
266 	public abstract void removeModifier(RegisterIndirection indirection, int index);
267 
268 	/***
269 	 * Return this targetable as it was at the given timestamp.
270 	 * 
271 	 * @param timeStamp
272 	 *          the timestamp number.
273 	 * @return this targetable as it was at the given timestamp.
274 	 */
275 	public abstract Targetable getLastKnownTargetable(int timeStamp);
276 
277 	/***
278 	 * Return the original targetable without looking for the timestamp number.
279 	 * 
280 	 * @return the original targetable without looking for the timestamp number.
281 	 */
282 	public Targetable getOriginalTargetable() {
283 		return this;
284 	}
285 
286 	/***
287 	 * Return the named object. If the object has not been found,
288 	 * <code>null</code> value is returned.
289 	 * 
290 	 * @param objectName
291 	 *          the searched object's name
292 	 * @return the named object.
293 	 */
294 	public Targetable getPrivateNamedObject(String objectName) {
295 		if (KEY_CREATOR.equals(objectName)) {
296 			return getCreator();
297 		}
298 		if (privateNamedObjects == null) {
299 			return null;
300 		}
301 		return privateNamedObjects.get(objectName);
302 	}
303 
304 	/***
305 	 * Return the creator of this targetable component. May be null if has not
306 	 * been set.
307 	 * 
308 	 * @return the creator of this targetable component.
309 	 */
310 	public MCard getCreator() {
311 		return creator;
312 	}
313 
314 	/***
315 	 * Set the creator of this targetable component.
316 	 * 
317 	 * @param creator
318 	 *          the card creating this card. May be null.
319 	 */
320 	public void setCreator(MCard creator) {
321 		this.creator = creator;
322 	}
323 
324 	/***
325 	 * Remove the named object.
326 	 * 
327 	 * @param objectName
328 	 *          the searched object's name
329 	 */
330 	public void removePrivateNamedObject(String objectName) {
331 		if (privateNamedObjects != null) {
332 			privateNamedObjects.remove(objectName);
333 		}
334 	}
335 
336 	/***
337 	 * Add an object to this targetable. This object will be accessible with the
338 	 * specified name.
339 	 * 
340 	 * @param objectName
341 	 *          the object's name to save.
342 	 * @param targetable
343 	 *          the targetable to save.
344 	 */
345 	public void addPrivateNamedObject(String objectName, Targetable targetable) {
346 		if (privateNamedObjects == null) {
347 			privateNamedObjects = new HashMap<String, Targetable>();
348 		}
349 		privateNamedObjects.put(objectName, targetable);
350 	}
351 
352 	/***
353 	 * Remove all stored objects.
354 	 */
355 	public void clearPrivateNamedObject() {
356 		if (privateNamedObjects != null) {
357 			privateNamedObjects.clear();
358 			privateNamedObjects = null;
359 		}
360 	}
361 
362 	/***
363 	 * Return a cloned instance of map of objects of this targetable.
364 	 * 
365 	 * @return a cloned instance of map of objects of this targetable.
366 	 */
367 	public Map<String, Targetable> getPrivateNamedObjects() {
368 		if (privateNamedObjects != null) {
369 			return null;
370 		}
371 		return new HashMap<String, Targetable>(privateNamedObjects);
372 	}
373 
374 	/***
375 	 * Return the id of this component. For instance, this id is only relevant for
376 	 * players.
377 	 * 
378 	 * @return the id of this component.
379 	 */
380 	public int getId() {
381 		return 0;
382 	}
383 
384 	/***
385 	 * Return the timstamp value of this targetable.
386 	 * 
387 	 * @return the timstamp value of this targetable.
388 	 */
389 	public abstract int getTimestamp();
390 
391 	/***
392 	 * Add a reference to this targetable.
393 	 */
394 	public abstract void addTimestampReference();
395 
396 	/***
397 	 * Decrement the reference counter for the current timestamp of this card.
398 	 * 
399 	 * @param timestamp
400 	 *          is the reference to decrement.
401 	 */
402 	public abstract void decrementTimestampReference(int timestamp);
403 
404 	/***
405 	 * Current regiters of this targetable
406 	 */
407 	public int[] registers;
408 
409 	/***
410 	 * The registerModifiers on this object
411 	 */
412 	public RegisterModifier[] registerModifiers;
413 
414 	/***
415 	 * The ControllerModifier on this object
416 	 */
417 	public ControllerModifier controllerModifier;
418 
419 	/***
420 	 * The registerModifiers on this object
421 	 */
422 	public RegisterIndirection[] indirections;
423 
424 	/***
425 	 * Accessible objects of this component. Is <code>null</code> while no
426 	 * object has been saved. This map is destroyed when this component move.
427 	 */
428 	private Map<String, Targetable> privateNamedObjects;
429 
430 	/***
431 	 * The creator of this targetable component.
432 	 */
433 	private MCard creator;
434 
435 	/***
436 	 * The cached abilities of this component.
437 	 */
438 	public List<Ability> cachedAbilities;
439 }