View Javadoc

1   /*
2    * Created on Sep 3, 2004 
3    * 
4    *   Magic-Project is a turn based strategy simulator
5    *   Copyright (C) 2003-2007 Fabrice Daugan
6    *
7    *   This program is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU General Public License as published by the Free 
9    * Software Foundation; either version 2 of the License, or (at your option) any
10   * later version.
11   *
12   *   This program is distributed in the hope that it will be useful, but WITHOUT 
13   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
15   * details.
16   *
17   *   You should have received a copy of the GNU General Public License along  
18   * with this program; if not, write to the Free Software Foundation, Inc., 
19   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   * 
21   */
22  package net.sf.magicproject.modifier;
23  
24  import java.awt.Graphics;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import net.sf.magicproject.action.RefreshModifier;
29  import net.sf.magicproject.clickable.ability.Ability;
30  import net.sf.magicproject.clickable.ability.RefreshAbility;
31  import net.sf.magicproject.clickable.ability.RemoveModifier;
32  import net.sf.magicproject.clickable.targetable.card.MCard;
33  import net.sf.magicproject.clickable.targetable.card.SystemCard;
34  import net.sf.magicproject.event.MEventListener;
35  import net.sf.magicproject.event.MovedCard;
36  import net.sf.magicproject.event.TriggeredEvent;
37  import net.sf.magicproject.test.And;
38  import net.sf.magicproject.test.InZone;
39  import net.sf.magicproject.test.IsTested;
40  import net.sf.magicproject.test.Test;
41  import net.sf.magicproject.test.True;
42  import net.sf.magicproject.test.TestOn;
43  import net.sf.magicproject.token.IdZones;
44  import net.sf.magicproject.tools.Log;
45  
46  /***
47   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
48   */
49  public abstract class Modifier implements Unregisterable, ObjectModifier {
50  
51  	/***
52  	 * Creates a new instance of Modifier <br>
53  	 * 
54  	 * @param name
55  	 *          The modifier name.
56  	 * @param to
57  	 *          Targetable attached to.
58  	 * @param creatorAbility
59  	 *          is the ability owning this test. The card component of this
60  	 *          ability should correspond to the card owning this test too.
61  	 * @param whileCondition
62  	 *          When this test is true, this modifier is activated. Otherwise this
63  	 *          modifier does nothing.
64  	 * @param linkedEvents
65  	 *          the linked events used to build dynamically the corresponding
66  	 *          abilities.
67  	 * @param until
68  	 *          the until events stopping this modifier.
69  	 * @param linked
70  	 *          is this modifier is linked to the creator.
71  	 * @param layer
72  	 *          the layer of this modifier.
73  	 */
74  	protected Modifier(String name, MCard to, Ability creatorAbility,
75  			Test whileCondition, List<MEventListener> linkedEvents,
76  			List<MEventListener> until, boolean linked, int layer) {
77  		this.name = name;
78  		this.to = to;
79  		this.layer = layer;
80  		abilities = new ArrayList<Ability>();
81  		this.ability = creatorAbility;
82  		final MCard creator = creatorAbility.getCard();
83  
84  		/*
85  		 * create the abilities linked to this modifier in order to maintain the
86  		 * coherence. Any event that could modifiy the "while-test" make a triggered
87  		 * ability to be created listening this event.
88  		 */
89  		if (linkedEvents != null) {
90  			final RefreshModifier refreshAction = new RefreshModifier(this);
91  			for (MEventListener event : linkedEvents) {
92  				final Ability refreshAbility = new RefreshAbility(
93  						(TriggeredEvent) event.clone(to), refreshAction,
94  						creator == null ? to : creator);
95  				refreshAbility.registerToManager();
96  				abilities.add(refreshAbility);
97  			}
98  		}
99  
100 		// link creator <--> target
101 		if (linked && creator != null && creator != SystemCard.instance) {
102 			// when the creator moves, this modifier is destroyed
103 			final Ability linkAbility = new RemoveModifier(new MovedCard(
104 					IdZones.PLAY, And.append(IsTested.TESTED_IS_ME, new InZone(
105 							IdZones.PLAY, TestOn.THIS)), True.getInstance(), creator),
106 					this);
107 			linkAbility.registerToManager();
108 			abilities.add(linkAbility);
109 		}
110 
111 		// when the until condition become true, this modifier is destroyed
112 		for (MEventListener event : until) {
113 			final Ability untilAbility = new RemoveModifier((TriggeredEvent) event
114 					.clone(to), this);
115 			untilAbility.registerToManager();
116 			abilities.add(untilAbility);
117 		}
118 
119 		this.whileCondition = whileCondition;
120 	}
121 
122 	public int paintObject(Graphics g, int startX, int startY) {
123 		if (next != null) {
124 			return next.paintObject(g, startX, startY);
125 		}
126 		return startX;
127 	}
128 
129 	/***
130 	 * Add a modifier to the end of the modifier chain. The current modifier stays
131 	 * the first modifier of this chain.
132 	 * 
133 	 * @param modifier
134 	 *          the property modifier to add.
135 	 * @return the new chain.
136 	 */
137 	public final Modifier addModifier(Modifier modifier) {
138 		assert modifier.next != null;
139 		if (modifier.next != null) {
140 			throw new InternalError("'next' modifier should not be specified");
141 		}
142 
143 		// Is the specified modifier has lower layer?
144 		if (modifier.layer < layer) {
145 			// insert the modifier just before this modifier
146 			modifier.next = this;
147 			return modifier;
148 		}
149 
150 		// Are we to the end of the chain?
151 		if (this.next == null) {
152 			// the modifier becomes the last one of the chain
153 			this.next = modifier;
154 			return this;
155 		}
156 
157 		// continue within the chain to add this modifier to the end of this layer
158 		this.next = next.addModifier(modifier);
159 		return this;
160 	}
161 
162 	/***
163 	 * remove from the manager a modifier
164 	 * 
165 	 * @param modifier
166 	 *          the modifier to remove
167 	 * @return the new chain
168 	 */
169 	protected Modifier removeModifier(Modifier modifier) {
170 		if (next != null) {
171 			next = next.removeModifier(modifier);
172 		} else {
173 			Log.warn("Cannot remove the modifier " + modifier.getClass() + ", name="
174 					+ modifier.name);
175 		}
176 		return this;
177 	}
178 
179 	/***
180 	 * Refresh this modifier following the whileCondition.
181 	 */
182 	public abstract void refresh();
183 
184 	public int getNbObjects(String objectName, Test objectTest) {
185 		if (next == null) {
186 			return 0;
187 		}
188 		return next.getNbObjects(objectName, objectTest);
189 	}
190 
191 	public Modifier removeObject(String objectName, Test objectTest) {
192 		// if (next == null):no more instance of this object on the card -> ignored
193 		if (next != null) {
194 			next = next.removeObject(objectName, objectTest);
195 		}
196 		return this;
197 	}
198 
199 	public void removeFromManager() {
200 		if (unregisteringModifier) {
201 			// we are currently unregistering this modifier
202 			return;
203 		}
204 		unregisteringModifier = true;
205 		for (int i = abilities.size(); i-- > 0;) {
206 			abilities.get(i).removeFromManager();
207 		}
208 		unregisteringModifier = false;
209 	}
210 
211 	/***
212 	 * Tag indicating we are currently unregistering this modifier
213 	 */
214 	protected boolean unregisteringModifier;
215 
216 	/***
217 	 * Tag indicating this modifier is completely unregistered and can be released
218 	 */
219 	protected boolean unregisteredModifier;
220 
221 	@Override
222 	public String toString() {
223 		return name;
224 	}
225 
226 	public MCard getCard() {
227 		return ability.getCard();
228 	}
229 
230 	/***
231 	 * The next modifier
232 	 */
233 	public Modifier next;
234 
235 	/***
236 	 * The modifier name
237 	 */
238 	protected final String name;
239 
240 	/***
241 	 * When this test is true, this modifier is activated. Otherwise this modifier
242 	 * does nothing.
243 	 */
244 	protected final Test whileCondition;
245 
246 	/***
247 	 * Is this modifier is activated
248 	 */
249 	protected boolean activated;
250 
251 	/***
252 	 * Targetable attached to.
253 	 */
254 	protected final MCard to;
255 
256 	/***
257 	 * The ability having created this modifier.
258 	 */
259 	protected Ability ability;
260 
261 	/***
262 	 * Abilities linked to this modifier
263 	 */
264 	protected final List<Ability> abilities;
265 
266 	/***
267 	 * is the strategy used to add this modifier within the existing chain.
268 	 */
269 	public int layer;
270 }