View Javadoc

1   /* 
2    *   Firemox 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.firemox.action;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.util.HashMap;
25  
26  import net.sf.firemox.action.context.ActionContextWrapper;
27  import net.sf.firemox.action.context.Int;
28  import net.sf.firemox.action.handler.ChosenAction;
29  import net.sf.firemox.action.handler.InitAction;
30  import net.sf.firemox.action.handler.RollBackAction;
31  import net.sf.firemox.clickable.ability.Ability;
32  import net.sf.firemox.clickable.target.Target;
33  import net.sf.firemox.clickable.target.card.MCard;
34  import net.sf.firemox.clickable.target.player.Player;
35  import net.sf.firemox.event.ModifiedRegister;
36  import net.sf.firemox.event.context.ContextEventListener;
37  import net.sf.firemox.expression.Expression;
38  import net.sf.firemox.expression.IntValue;
39  import net.sf.firemox.operation.Any;
40  import net.sf.firemox.operation.Operation;
41  import net.sf.firemox.stack.StackManager;
42  import net.sf.firemox.test.Test;
43  import net.sf.firemox.test.TestOn;
44  import net.sf.firemox.token.IdConst;
45  import net.sf.firemox.token.IdTokens;
46  
47  /***
48   * This action is used to modifiy a register of a player or a card. <br>
49   * This action can use the target list when is played : the address
50   * (idToken=register name + register index) must be IdTokens#TARGET. So the
51   * target list must set before this action would be played.
52   * 
53   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
54   * @since 0.71
55   * @since 0.85 useless operation are ignored and not genrated.
56   */
57  public class ModifyTargetableRegister extends ModifyRegister implements
58  		ChosenAction, InitAction, RollBackAction {
59  
60  	/***
61  	 * Create an instance of ModifyRegister by reading a file Offset's file must
62  	 * pointing on the first byte of this action <br>
63  	 * <ul>
64  	 * Structure of InputStream : Data[size]
65  	 * <li>[super]</li>
66  	 * </ul>
67  	 * 
68  	 * @param inputFile
69  	 *          file containing this action
70  	 * @throws IOException
71  	 *           if error occurred during the reading process from the specified
72  	 *           input stream
73  	 */
74  	ModifyTargetableRegister(InputStream inputFile) throws IOException {
75  		super(inputFile);
76  		register = TestOn.deserialize(inputFile);
77  	}
78  
79  	@Override
80  	public final Actiontype getIdAction() {
81  		return Actiontype.MODIFY_TARGETABLE_REGISTER;
82  	}
83  
84  	public boolean init(ActionContextWrapper actionContext,
85  			ContextEventListener context, Ability ability) {
86  		actionContext.actionContext = new Int(getValue(ability, null, context));
87  		return true;
88  	}
89  
90  	public boolean choose(ActionContextWrapper actionContext,
91  			ContextEventListener context, Ability ability) {
92  		return true;
93  	}
94  
95  	public void disactivate(ActionContextWrapper actionContext,
96  			ContextEventListener context, Ability ability) {
97  		// Nothing to do
98  	}
99  
100 	public boolean replay(ActionContextWrapper actionContext,
101 			ContextEventListener context, Ability ability) {
102 		return modifyRegister(StackManager.getRealSource(ability.getCard()),
103 				register.getTargetable(ability, null), index.getValue(ability, null,
104 						context), ((Int) actionContext.actionContext).getInt(), op);
105 	}
106 
107 	public void rollback(ActionContextWrapper actionContext,
108 			ContextEventListener context, Ability ability) {
109 		// TODO ModyRegister rollback --> not yet implemented
110 	}
111 
112 	public String toHtmlString(Ability ability, ContextEventListener context,
113 			ActionContextWrapper actionContext) {
114 		return toHtmlString(ability, context);
115 	}
116 
117 	@Override
118 	public boolean play(ContextEventListener context, Ability ability) {
119 		return modifyRegister(StackManager.getRealSource(ability.getCard()),
120 				register.getTargetable(ability, null), index.getValue(ability, null,
121 						context), getValue(ability, null, context), op);
122 	}
123 
124 	/***
125 	 * Generate event associated to this action. Only one or several events are
126 	 * generated and may be collected by event listeners. Then play this action
127 	 * 
128 	 * @param source
129 	 *          the source, and the concerned card to this modification
130 	 * @param target
131 	 *          the component to modify
132 	 * @param index
133 	 *          the register's index
134 	 * @param value
135 	 *          right value of operation
136 	 * @param op
137 	 *          identifier of the operation applied to the specified card
138 	 * @return true
139 	 */
140 	public static boolean modifyRegister(MCard source, Target target, int index,
141 			int value, Operation op) {
142 		if (target.isPlayer())
143 			return modifyRegister(source, (Player) target, index, op, value);
144 		return modifyRegister(source, (MCard) target, index, op, value);
145 	}
146 
147 	private static boolean modifyRegister(MCard source, Player player, int index,
148 			Operation op, int rightValue) {
149 		if (index == IdTokens.MANA_POOL) {
150 			// no care about operation, we empty the mana pool
151 			player.mana.setToZero();
152 			return true;
153 		}
154 
155 		// Generate event only if necessary
156 		if (!op.isUselessWith(index, rightValue)) {
157 			if (!ModifiedRegister.tryAction(player, source, IdTokens.PLAYER, index,
158 					op, rightValue)) {
159 				// this action has been replaced
160 				return false;
161 			}
162 			// we continue : dispatch event, and process to the register modification
163 			player.setValue(index, op, rightValue);
164 			ModifiedRegister.dispatchEvent(player, source, IdTokens.PLAYER, index,
165 					op, rightValue);
166 		}
167 		return true;
168 	}
169 
170 	private static boolean modifyRegister(MCard source, MCard card, int index,
171 			Operation op, int rightValue) {
172 		// Generate event only if necessary
173 		if (op.isUselessWith(card.getValue(index), rightValue)) {
174 			return true;
175 		}
176 		boolean replaced = false;
177 		if (index < IdTokens.FIRST_FREE_CARD_INDEX) {
178 			// notify this modification to the replacement abilities
179 			replaced = !ModifiedRegister.tryAction(card, source, IdTokens.CARD,
180 					index, op, rightValue);
181 		}
182 
183 		if (!replaced) {
184 			// also, we notify the modification of this register
185 			card.setValue(index, op, rightValue);
186 			if (index < IdTokens.FIRST_FREE_CARD_INDEX) {
187 				ModifiedRegister.dispatchEvent(card, source, IdTokens.CARD, index, op,
188 						rightValue);
189 			}
190 			return true;
191 		}
192 		return false;
193 	}
194 
195 	@Override
196 	public Test parseTest(Test test) {
197 		final HashMap<String, Expression> values = new HashMap<String, Expression>();
198 		values.put("%value", valueExpr);
199 		return test.getConstraintTest(values);
200 	}
201 
202 	@Override
203 	public boolean equal(MAction constraintAction) {
204 		if (!(constraintAction instanceof ModifyTargetableRegister)) {
205 			return false;
206 		}
207 		final ModifyTargetableRegister other = (ModifyTargetableRegister) constraintAction;
208 		return (other.op == op || other.op == Any.getInstance())
209 				&& register == other.register
210 				&& index instanceof IntValue
211 				&& ((IntValue) index).value == ((IntValue) index).value
212 				&& valueExpr instanceof IntValue
213 				&& (((IntValue) valueExpr).value == IdConst.ALL || ((IntValue) valueExpr).value == ((IntValue) other.valueExpr).value);
214 	}
215 
216 	@Override
217 	public String toString(Ability ability) {
218 		final int index = this.index.getValue(ability, null, null);
219 		String value = null;
220 		try {
221 			value = "" + valueExpr.getValue(ability, null, null);
222 		} catch (Exception e) {
223 			value = "?";
224 		}
225 		return op.getClass().getSimpleName() + " (L=" + index + ",R=" + value + ")";
226 	}
227 
228 	/***
229 	 * represents the token to modify
230 	 */
231 	protected final TestOn register;
232 }