1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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 }