View Javadoc

1   /*
2    * 
3    *   Magic-Project is a turn based strategy simulator
4    *   Copyright (C) 2003-2007 Fabrice Daugan
5    *
6    *   This program is free software; you can redistribute it and/or modify it 
7    * under the terms of the GNU General Public License as published by the Free 
8    * Software Foundation; either version 2 of the License, or (at your option) any
9    * later version.
10   *
11   *   This program is distributed in the hope that it will be useful, but WITHOUT 
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
14   * details.
15   *
16   *   You should have received a copy of the GNU General Public License along  
17   * with this program; if not, write to the Free Software Foundation, Inc., 
18   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   * 
20   */
21  package net.sf.magicproject.action;
22  
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import net.sf.magicproject.action.handler.StandardAction;
29  import net.sf.magicproject.action.listener.WaitingAbility;
30  import net.sf.magicproject.action.listener.WaitingCard;
31  import net.sf.magicproject.clickable.ability.Ability;
32  import net.sf.magicproject.clickable.ability.ActivatedAbility;
33  import net.sf.magicproject.clickable.targetable.Targetable;
34  import net.sf.magicproject.clickable.targetable.card.MCard;
35  import net.sf.magicproject.clickable.targetable.player.Player;
36  import net.sf.magicproject.event.MEventListener;
37  import net.sf.magicproject.event.context.ContextEventListener;
38  import net.sf.magicproject.expression.Expression;
39  import net.sf.magicproject.expression.ExpressionFactory;
40  import net.sf.magicproject.stack.ActivatedChoiceList;
41  import net.sf.magicproject.stack.StackManager;
42  import net.sf.magicproject.test.Test;
43  import net.sf.magicproject.test.TestFactory;
44  import net.sf.magicproject.zone.MZone;
45  
46  /***
47   * Force a player to play ONE or several abilities. The player must be in the
48   * first index of current target-list. When the forced ability is played, the
49   * corresponding card is add to the target-list. The 'hop' attribute is used to
50   * skip actions when no available ability can be played or when the player
51   * cancels this action. The 'must-be-played' attribute allow or not the player
52   * to cancel this action.
53   * 
54   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
55   * @since 0.86
56   */
57  class ForcePlay extends UserAction implements StandardAction, WaitingCard,
58  		WaitingAbility {
59  
60  	/***
61  	 * Create an instance of CreateCard by reading a file Offset's file must
62  	 * pointing on the first byte of this action
63  	 * <ul>
64  	 * Structure of InputStream : Data[size]
65  	 * <li>on error hop [Expression]</li>
66  	 * <li>mustBePlayed [boolean]</li>
67  	 * <li>cardTest [Test.]</li>
68  	 * <li>abilityTest [Test]</li>
69  	 * </ul>
70  	 * 
71  	 * @param inputFile
72  	 *          file containing this action
73  	 * @throws IOException
74  	 *           if error occurred during the reading process from the specified
75  	 *           input stream
76  	 */
77  	ForcePlay(InputStream inputFile) throws IOException {
78  		super(inputFile);
79  		hop = ExpressionFactory.readNextExpression(inputFile);
80  		mustBePlayed = inputFile.read() == 1;
81  		cardTest = TestFactory.readNextTest(inputFile);
82  		abilityTest = TestFactory.readNextTest(inputFile);
83  	}
84  
85  	/***
86  	 * return the id of this action. This action has been read from the mdb file.
87  	 * 
88  	 * @see Actiontype
89  	 * @return the id of this action
90  	 */
91  	@Override
92  	public final Actiontype getIdAction() {
93  		return Actiontype.FORCE_PLAY;
94  	}
95  
96  	public List<Ability> abilitiesOf(MCard card) {
97  		return activChoiceList == null ? null : activChoiceList.abilitiesOf(card);
98  	}
99  
100 	public List<Ability> advancedAbilitiesOf(MCard card) {
101 		return activChoiceList == null ? null : activChoiceList
102 				.advancedAbilitiesOf(card);
103 	}
104 
105 	/***
106 	 * Called to specify the triggered card chosen for the current action by the
107 	 * handed player
108 	 * 
109 	 * @param card
110 	 *          the clicked card by the handed player for the current action
111 	 * @return true if this click has been managed. Return false if this click has
112 	 *         been ignored
113 	 */
114 	public boolean clickOn(MCard card) {
115 		return StackManager.idHandedPlayer != 0;
116 	}
117 
118 	/***
119 	 * Called to specify the triggered card chosen for the current action by the
120 	 * handed player
121 	 * 
122 	 * @param ability
123 	 *          the clicked card by the handed player for the current action
124 	 * @return true if this click has been managed. Return false if this click has
125 	 *         been ignored
126 	 */
127 	public boolean clickOn(Ability ability) {
128 		return StackManager.idHandedPlayer == 0;
129 	}
130 
131 	public boolean succeedClickOn(MCard card) {
132 		throw new InternalError("doesn't wait card");
133 	}
134 
135 	public boolean succeedClickOn(Ability ability) {
136 		finished();
137 		StackManager.getInstance().getTargetedList().list.add(ability.getCard());
138 		StackManager.newSpell(ability, ability.isMatching());
139 		return true;
140 	}
141 
142 	/***
143 	 * Called by the handed player when he/she wants to skip/abort this action. No
144 	 * stack operation should be done here.<br>
145 	 * For this action, the cancel is always accepted. If both players haved
146 	 * declined to play an activated ability, the stack would be resolved.
147 	 * 
148 	 * @return true if this action allow the skip/cancel.
149 	 */
150 	public boolean manualSkip() {
151 		if (mustBePlayed) {
152 			return false;
153 		}
154 		finished();
155 		return false;
156 	}
157 
158 	/***
159 	 * Called when this action is finished (aborted or completed)
160 	 */
161 	public void finished() {
162 		if (activChoiceList != null) {
163 			activChoiceList.disHighLight();
164 			activChoiceList.clear();
165 			activChoiceList = null;
166 		}
167 		if (zoneList != null) {
168 			for (int i = zoneList.size(); i-- > 0;) {
169 				zoneList.get(i).disHighLight();
170 			}
171 			zoneList.clear();
172 			zoneList = null;
173 			StackManager.PLAYERS[0].disHighLight();
174 			StackManager.PLAYERS[1].disHighLight();
175 		}
176 	}
177 
178 	public boolean play(ContextEventListener context, Ability ability) {
179 		if (StackManager.getTargetListAccess().isEmpty()
180 				|| !StackManager.getTargetListAccess().get(0).isPlayer()) {
181 			throw new RuntimeException(
182 					"In ForcePlay action, the target-list should contin at least on player");
183 		}
184 		final List<Targetable> validCards = new ArrayList<Targetable>();
185 		final Player player = (Player) StackManager.getTargetListAccess().get(0);
186 
187 		if (restrictionZone != -1) {
188 			StackManager.PLAYERS[StackManager.idCurrentPlayer].zoneManager
189 					.getContainer(restrictionZone).checkAllCardsOf(cardTest, validCards,
190 							ability);
191 			StackManager.PLAYERS[1 - StackManager.idCurrentPlayer].zoneManager
192 					.getContainer(restrictionZone).checkAllCardsOf(cardTest, validCards,
193 							ability);
194 		} else {
195 			StackManager.PLAYERS[StackManager.idCurrentPlayer].zoneManager
196 					.checkAllCardsOf(cardTest, validCards, ability);
197 			StackManager.PLAYERS[1 - StackManager.idCurrentPlayer].zoneManager
198 					.checkAllCardsOf(cardTest, validCards, ability);
199 		}
200 		final List<Ability> res = new ArrayList<Ability>();
201 		final List<Ability> advRes = new ArrayList<Ability>();
202 
203 		for (int i = MEventListener.CAN_I_CAST_ABILITIES[player.idPlayer].size(); i-- > 0;) {
204 			final Ability abilityI = MEventListener.CAN_I_CAST_ABILITIES[player.idPlayer]
205 					.get(i);
206 			if (abilityI instanceof ActivatedAbility
207 					&& validCards.contains(abilityI.getCard())
208 					&& abilityTest.test(abilityI, abilityI.getCard())
209 					&& abilityI.checkTargetActions() && abilityI.checkObjectActions()) {
210 				if (abilityI.isMatching()) {
211 					res.add(abilityI);
212 				} else {
213 					advRes.add(abilityI);
214 				}
215 			}
216 		}
217 		if (!res.isEmpty()) {
218 			// at least on playable/valid ability
219 			finished();
220 			activChoiceList = new ActivatedChoiceList(res, advRes);
221 			res.clear();
222 			advRes.clear();
223 			zoneList = activChoiceList.highLight();
224 			player.setActivePlayer();
225 			return false;
226 		}
227 		StackManager.actionManager.setHop(hop.getValue(ability, null, context));
228 		return true;
229 	}
230 
231 	@Override
232 	public String toString(Ability ability) {
233 		return "Force to play";
234 	}
235 
236 	/***
237 	 * The card to add
238 	 */
239 	private Test abilityTest;
240 
241 	/***
242 	 * The test applied on card to determine if one ability can/must be played
243 	 * from this card.
244 	 */
245 	private Test cardTest;
246 
247 	/***
248 	 * The zone identifant where the scan is restricted. If is equal to -1, there
249 	 * would be no restriction zone.
250 	 * 
251 	 * @see net.sf.magicproject.token.IdZones
252 	 */
253 	protected int restrictionZone;
254 
255 	/***
256 	 * When is true, the player must play the determinated abilities.
257 	 */
258 	private boolean mustBePlayed;
259 
260 	/***
261 	 * This is the list of zone concerned by highlighted cards
262 	 */
263 	private List<MZone> zoneList;
264 
265 	/***
266 	 * The hop to do in case of no plaable ability
267 	 */
268 	private Expression hop;
269 
270 	/***
271 	 * the current list of choices of active player
272 	 */
273 	private ActivatedChoiceList activChoiceList;
274 }