1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sf.magicproject.clickable.mana;
23
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.Graphics;
27 import java.awt.Graphics2D;
28 import java.awt.Image;
29 import java.awt.event.MouseEvent;
30 import java.awt.geom.Rectangle2D;
31 import java.awt.image.PixelGrabber;
32 import java.io.InputStream;
33 import java.net.URL;
34 import java.util.ArrayList;
35 import java.util.List;
36
37 import javax.swing.JOptionPane;
38
39 import net.sf.magicproject.action.PayMana;
40 import net.sf.magicproject.action.context.ManaCost;
41 import net.sf.magicproject.clickable.Clickable;
42 import net.sf.magicproject.clickable.ability.Ability;
43 import net.sf.magicproject.clickable.targetable.player.Player;
44 import net.sf.magicproject.deckbuilder.MdbLoader;
45 import net.sf.magicproject.network.ConnectionManager;
46 import net.sf.magicproject.network.IdMessages;
47 import net.sf.magicproject.stack.StackManager;
48 import net.sf.magicproject.test.Test;
49 import net.sf.magicproject.test.True;
50 import net.sf.magicproject.token.IdCommonToken;
51 import net.sf.magicproject.tools.Configuration;
52 import net.sf.magicproject.tools.Log;
53 import net.sf.magicproject.tools.MToolKit;
54 import net.sf.magicproject.tools.PairIntObject;
55 import net.sf.magicproject.tools.Picture;
56 import net.sf.magicproject.ui.MagicUIComponents;
57 import net.sf.magicproject.ui.i18n.LanguageManager;
58
59 /***
60 * Representes the mana pool of one color of one player : BLACK,BLUE,GREEN,RED,
61 * WHITE,COLORLESS. A graphic, in function of mana's color is displayed with a
62 * label representing the amount of manas for this colored(less) mana. if we
63 * consider the opponent case, we have a reversed a rotation of PI to do.
64 *
65 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
66 * @see net.sf.magicproject.clickable.mana.ManaPool
67 * @see net.sf.magicproject.token.IdCommonToken#COLORLESS_MANA
68 * @see net.sf.magicproject.token.IdCommonToken#BLACK_MANA
69 * @see net.sf.magicproject.token.IdCommonToken#BLUE_MANA
70 * @see net.sf.magicproject.token.IdCommonToken#GREEN_MANA
71 * @see net.sf.magicproject.token.IdCommonToken#RED_MANA
72 * @see net.sf.magicproject.token.IdCommonToken#WHITE_MANA
73 * @since 0.3 support reversed mana picture for opponent
74 * @since 0.53 "enableReverse" option
75 * @since 0.60 extends MClickable class
76 * @since 0.83 new mana representation of mana pool
77 */
78 public class Mana extends Clickable {
79
80
81 private static final int MANA_WIDTH = Player.PLAYER_SIZE_HEIGHT;
82
83 private static final int MANA_HEIGHT = MANA_WIDTH;
84
85 /***
86 * Creates a new instance of MMana
87 *
88 * @param idColor
89 * if the color of this mana
90 * @param reverseImage
91 * if true the mana picture will be flipped horizontally and
92 * vertically.
93 */
94 Mana(int idColor, boolean reverseImage) {
95 super();
96 this.color = idColor;
97 this.reverseImage = reverseImage;
98 setPreferredSize(new Dimension(MANA_WIDTH, MANA_HEIGHT));
99 setToolTipText(LanguageManager.getString("Mana" + idColor));
100 addMouseListener(this);
101 }
102
103 /***
104 * Upadte the mana pictures following the specified emulated TBS
105 *
106 * @param mdb
107 */
108 public static void init(String mdb) {
109
110 int error = 0;
111 for (int i = IdCommonToken.COLOR_NAMES.length; i-- > 0;) {
112 try {
113 if (error == 0 && i != 0) {
114 IMAGES[i] = Picture.loadImage(
115 MToolKit.getTbsPicture("mana/colored/big/"
116 + MdbLoader.coloredBigManas[i], false),
117 new URL(MdbLoader.coloredManaBigURL
118 + MdbLoader.coloredBigManas[i])).getContent();
119 if (IMAGES[i] == null) {
120 error += (i + 1) * 2;
121 } else {
122
123 Picture.download(MToolKit.getTbsPicture("mana/colored/small/"
124 + MdbLoader.coloredSmlManas[i], false), new URL(
125 MdbLoader.coloredManaSmlURL + MdbLoader.coloredSmlManas[i]));
126 }
127 } else if (error == 0) {
128 IMAGES[0] = Picture.loadImage(
129 MToolKit.getTbsPicture("mana/colorless/big/"
130 + MdbLoader.colorlessBigURL, false),
131 new URL(MdbLoader.colorlessURL + MdbLoader.colorlessBigURL))
132 .getContent();
133 if (IMAGES[0] == null) {
134 error += (i + 1) * 2 + MdbLoader.colorlessSmlManas.length;
135 } else {
136
137 for (int j = MdbLoader.colorlessSmlManas.length; j-- > 0;) {
138 Picture.download(MToolKit.getTbsPicture("mana/colorless/small/"
139 + MdbLoader.colorlessSmlManas[j], false), new URL(
140 MdbLoader.colorlessURL + MdbLoader.colorlessSmlManas[j]));
141 }
142 Picture.download(MToolKit.getTbsPicture("mana/colorless/small/"
143 + MdbLoader.unknownSmlMana, false), new URL(
144 MdbLoader.colorlessURL + MdbLoader.unknownSmlMana));
145 }
146 }
147 } catch (Exception e1) {
148 error += (i + 1) * 2;
149 Log.error("ERROR : could not load mana picture " + i, e1);
150 }
151
152
153 if (IMAGES[i] != null) {
154 final int[] pixels = new int[1];
155 try {
156 new PixelGrabber(IMAGES[i], 18, 1, 1, 1, pixels, 0, 1).grabPixels();
157 TEXT_COLOR[i] = new Color(pixels[0]).darker();
158 } catch (InterruptedException e) {
159 TEXT_COLOR[i] = Color.black;
160 }
161 } else {
162 TEXT_COLOR[i] = Color.black;
163 }
164 }
165
166 if (error > 0) {
167
168 JOptionPane
169 .showMessageDialog(
170 MagicUIComponents.magicForm,
171 "One or several mana pictures ("
172 + error
173 + ") have not been found\nCheck your internet connection and/or you proxy configuration\nHave a look in console output for more details.",
174 "Load error", JOptionPane.WARNING_MESSAGE);
175 }
176 }
177
178 /***
179 * return the amount of mana of this color
180 *
181 * @return the amount of mana of this color
182 */
183 public int getMana() {
184 return getMana(null);
185 }
186
187 /***
188 * return the amount of mana of this color
189 *
190 * @param abilityRequest
191 * the ability containing action requesting this mana
192 * @return the amount of mana of this color
193 */
194 public int getMana(Ability abilityRequest) {
195 if (abilityRequest != null) {
196
197 int result = getPlayer().registers[color];
198 for (PairIntObject<Test> pair : restrictionList) {
199
200 if (!pair.value.test(abilityRequest, abilityRequest.getCard())) {
201
202 result -= pair.key;
203 }
204 }
205 return result;
206 }
207 return getPlayer().registers[color];
208 }
209
210 /***
211 * empty the mana pool of this mana
212 *
213 * @return the old pool of this mana
214 */
215 public int setToZero() {
216 final int oldValue = getPlayer().registers[color];
217 setTo(0);
218 return oldValue;
219 }
220
221 /***
222 * set the pool of this mana
223 *
224 * @param idNumber
225 * is the new pool of this mana
226 * @return the new pool of this mana ( is idNumber)
227 */
228 private int setTo(int idNumber) {
229 getPlayer().registers[color] = idNumber;
230 return idNumber;
231 }
232
233 /***
234 * Add a number of mana of this color
235 *
236 * @param idNumber
237 * is the number of mana to add to the mana pool
238 * @param restriction
239 * the test defining mana usage
240 * @return the new pool of this mana
241 */
242 public int addMana(int idNumber, Test restriction) {
243 if (idNumber > 0) {
244 setTo(getPlayer().registers[color] + idNumber);
245 if (restriction != null && restriction != True.getInstance()) {
246
247 for (PairIntObject<Test> pair : restrictionList) {
248 if (pair.value == restriction) {
249
250 pair.key += idNumber;
251 return getPlayer().registers[color];
252 }
253 }
254 restrictionList.add(new PairIntObject<Test>(idNumber, restriction));
255 }
256 }
257 return getPlayer().registers[color];
258 }
259
260 /***
261 * Remove a number of mana of this color from the mana pool.
262 *
263 * @param nb
264 * is the number of mana to remove from the mana pool
265 * @param abilityRequest
266 * the ability containing action requesting this mana
267 * @return amount of mana effectively removed from the mana pool.
268 */
269 public int removeMana(int nb, Ability abilityRequest) {
270 return removeMana(nb, abilityRequest, null);
271 }
272
273 /***
274 * Remove a number of mana of this color from the mana pool.
275 *
276 * @param nb
277 * is the number of mana to remove from the mana pool
278 * @param abilityRequest
279 * the ability containing action requesting this mana
280 * @param manaContext
281 * is the action context containing information on mana cost of the
282 * requesting ability;
283 * @return amount of mana effectively removed from the mana pool.
284 */
285 public int removeMana(int nb, Ability abilityRequest, ManaCost manaContext) {
286 if (abilityRequest != null) {
287
288 int toRemove = nb;
289 int i = restrictionList.size();
290 while (i-- > 0 && toRemove > 0) {
291 final PairIntObject<Test> restriction = restrictionList.get(i);
292 if (!(restriction.value).test(abilityRequest, abilityRequest.getCard())) {
293
294 if (restriction.key - toRemove <= 0) {
295
296 restrictionList.remove(i);
297 if (restriction.key - toRemove == 0) {
298
299 if (manaContext != null) {
300 manaContext.addRestriction(color, restriction.value, toRemove);
301 }
302 break;
303 }
304
305 if (manaContext != null) {
306 manaContext.addRestriction(color, restriction.value,
307 restriction.key);
308 }
309 toRemove -= restriction.key;
310 } else {
311
312 if (manaContext != null) {
313 manaContext.addRestriction(color, restriction.value, toRemove);
314 }
315 restriction.key -= toRemove;
316 break;
317 }
318 }
319 }
320 }
321 if (nb <= getPlayer().registers[color]) {
322 setTo(getPlayer().registers[color] - nb);
323 return nb;
324 }
325
326 return setToZero();
327 }
328
329 /***
330 * @see java.awt.Component#paint(java.awt.Graphics)
331 * @since 0.3 faster reverse draw without use of rotation
332 */
333 @Override
334 public void paint(Graphics g) {
335 if (PayMana.useMana && IMAGES[color] != null) {
336 super.paint(g);
337 final Graphics2D g2d = (Graphics2D) g;
338 if (reverseImage && Configuration.getBoolean("reverseSide", false)) {
339 g2d.rotate(Math.PI, MANA_WIDTH / 2, MANA_HEIGHT / 2);
340 }
341 g2d.drawImage(IMAGES[color], 0, 0, MANA_WIDTH, MANA_WIDTH, null);
342 g2d.setColor(TEXT_COLOR[color]);
343
344 if (StackManager.PLAYERS[0] != null
345 && StackManager.PLAYERS[0].registers != null) {
346 final Rectangle2D stringDim = g2d.getFontMetrics().getStringBounds(
347 String.valueOf(getPlayer().registers[color]), g);
348 g2d.fill3DRect(MANA_WIDTH - (int) stringDim.getWidth() - 4,
349 MANA_HEIGHT - 11, (int) stringDim.getWidth() + 3, 10, true);
350 g2d.setColor(Color.black);
351 g2d.drawString(String.valueOf(getPlayer().registers[color]), MANA_WIDTH
352 - (int) stringDim.getWidth() - 2, MANA_HEIGHT - 2);
353
354 }
355 }
356
357
358
359
360 if (isHighLighted) {
361 g.setColor(highLightColor);
362 g.draw3DRect(0, 0, MANA_WIDTH - 1, MANA_HEIGHT - 1, true);
363 g.draw3DRect(1, 1, MANA_WIDTH - 3, MANA_HEIGHT - 3, true);
364 }
365
366 }
367
368 @Override
369 public void mouseClicked(MouseEvent e) {
370
371 StackManager.noReplayToken.take();
372 try {
373 if (ConnectionManager.isConnected()
374 && e.getButton() == MouseEvent.BUTTON1
375 && StackManager.idHandedPlayer == 0
376 && StackManager.actionManager.clickOn(this)) {
377 StackManager.actionManager.succeedClickOn(this);
378 }
379 } catch (Throwable t) {
380 t.printStackTrace();
381 } finally {
382 StackManager.noReplayToken.release();
383 }
384 }
385
386 /***
387 * This method is invoked when opponent has clicked on this object. this call
388 * should be done from the net.sf.magicproject.network listener
389 *
390 * @param input
391 * input stream of our net.sf.magicproject.network connection
392 */
393 public void clickOn(InputStream input) {
394
395 StackManager.actionManager.succeedClickOn(this);
396 }
397
398 @Override
399 public void sendClickToOpponent() {
400
401 ConnectionManager.sendToOpponent(IdMessages.MSG_CLICK_MANA,
402 reverseImage ? 0 : 1, color);
403 }
404
405 @Override
406 public String toString() {
407 return IdCommonToken.COLOR_NAMES[color];
408 }
409
410 /***
411 * return the player owning this mana
412 *
413 * @return the player owning this mana
414 */
415 public Player getPlayer() {
416 return reverseImage ? StackManager.PLAYERS[1] : StackManager.PLAYERS[0];
417 }
418
419 /***
420 * represent all images used to represents energy source for each sort
421 */
422 private static final Image[] IMAGES = new Image[6];
423
424 /***
425 * represent all foreground colors used to represent the amount of energy for
426 * each type
427 */
428 private static final Color[] TEXT_COLOR = new Color[6];
429
430 /***
431 * color of this mana
432 */
433 public int color;
434
435 /***
436 * List of pair [mana, restriction]
437 */
438 private List<PairIntObject<Test>> restrictionList = new ArrayList<PairIntObject<Test>>();
439
440 /***
441 * Indicates if graphics are reversed (PI rotation)
442 */
443 private boolean reverseImage;
444
445 }