1   import java.util.*;
2   import java.awt.*;
3   import java.awt.event.*;
4   import java.applet.*;
5   import java.awt.geom.*;
6   import java.awt.image.*;
7   
8   /**
9    * Class for displaying the map and handling the Player Movements.  Fires Events for
10   * battles and redirects
11   * 
12   * @see Player
13   * @see People
14   * @see MapObject
15   * @see Redirect
16   * @see RedirectEvent
17   * @see Game
18   * @see BattleEvent
19   */
20  public class Grid extends Panel 
21  {
22      /**
23       * The default number of Rows/COlumns
24       */
25      public static final int DEFAULTNUM = 16;
26  
27      /**
28       * Left direction
29       */
30      public static final int LEFT = 0;
31      /**
32       * Right direction
33       */
34      public static final int RIGHT = 1;
35      /**
36       * Up direction
37       */
38      public static final int UP = 2;
39      /**
40       * Down direction
41       */
42      public static final int DOWN = 3;
43  
44      /**
45       * The number of rows
46       */
47      protected int numi; // Num Rows
48      /**
49       * The number of columns
50       */
51      protected int numj; // Num Columns
52  
53      /**
54       * The position of the player, the row/i
55       */
56      protected int pi; // Player position i
57      /**
58       * The position of the player, the column/j
59       */
60      protected int pj; // Player position j
61  
62      /**
63       * The BattleListeners
64       */
65      private Vector battleListeners;
66      /**
67       * The RedirectEventListeners
68       */
69      private Vector redirectListeners;
70  
71      /**
72       * This
73       */
74      MapObject mp[][];
75      /**
76       * Default backdrop
77       */
78      MapObject def;
79      /**
80       * The Monsters allowed on this
81       */
82      Vector monAllow;
83      /**
84       * The Monster level for wild Monsters
85       */
86      int monsterLevel;
87      /**
88       * is there a battle
89       */
90      boolean battle;
91  
92      /**
93       * Needed for calls to paintAll
94       */
95      Graphics g; // Needed for call to repaint
96  
97      /**
98       * Construct a new Grid of size Grid.DEFAULTNUM
99       */
100     public Grid()
101     {
102         mp = new MapObject[DEFAULTNUM][DEFAULTNUM];
103         numi = DEFAULTNUM;
104         numj = DEFAULTNUM;
105         monAllow = new Vector();
106         monsterLevel = 10;
107         setLayout(new GridLayout(numi, numj, 0, 0));
108         battle = false;
109         enableEvents( AWTEvent.KEY_EVENT_MASK);
110     }
111 
112     /**
113      * Gets the number of rows.
114      * 
115      * @return the Number of rows
116      */
117     public int getNumRows() { return numi; }
118     /**
119      * Gets the number of columns
120      * 
121      * @return the number of columns
122      */
123     public int getNumColumns() { return numj; }
124 
125     /**
126      * Determines if the Location specified is a valid on this.
127      * 
128      * @param i the row
129      * @param j the column
130      * @return true iff i & j are in this ie less than Grid.DEFAULTNUM, and greater than 0
131      */
132     public synchronized boolean isValidLocation(int i, int j)
133     {
134         if(i >= 0 && i < numi && j >= 0 && j < numj)
135             return true;
136         return false;
137     }
138 
139     /**
140      * Determines if the Location specified can be moved into
141      * 
142      * @param i the row
143      * @param j the column
144      * @return truee iff can be moved into, ie if isValidLocation, and canBeEntered
145      * @see MapObject
146      * @see Grass
147      * @see Floor
148      */
149     public synchronized boolean canMove(int i, int j)
150     {
151         if(!isValidLocation(i, j))
152             return false;
153         if(mp[i][j] == null)
154             return true;
155         return mp[i][j].canBeEntered();
156     }
157     /**
158      * Sets the default backdrop to display.
159      * 
160      * @param m the MapObject to have as the backdrop
161      */
162     public synchronized void setDefault(MapObject m)
163     {
164         if(m == null)
165             return;
166         if(m.canBeEntered())
167         {
168             this.def = m;
169         }
170     }
171     /**
172      * Returns the preferred size of this.
173      * Needs be larger or equal to the size of the Applet
174      * 
175      * @return the Dimension of this
176      * @see Game
177      */
178     public Dimension getPerferredSize()
179     {
180         return new Dimension(640, 480);
181     }
182     /**
183      * Sets the Player of this.
184      * 
185      * @param p the new Player of this
186      */
187     public synchronized void setPlayer(Player p)
188     {
189         if(p != null)
190         {
191             try 
192             {
193                 removeObject(pi, pj);
194                 setObjectAt(p, pi, pj);
195             } 
196             catch(Exception e) { }
197         }
198     }
199     /**
200      * Sets the object at the Location specified
201      * 
202      * @param mp the MapObject to set at i, j
203      * @param i the row
204      * @param j the column
205      * @exception InvalidLocationException iff !isValidException(i, j)
206      * @exception NonEmptyException iff !canMove(i, j)
207      */
208     public synchronized void setObjectAt(MapObject mp, int i, int j) throws InvalidLocationException, NonEmptyException
209     {
210         if(isValidLocation(i, j))
211         {
212             if(canMove(i, j))
213             {
214                 try
215                 {
216                     remove(this.mp[i][j]);
217                 }
218                 catch(Exception e) { }
219                 this.mp[i][j] = mp;
220                 add(this.mp[i][j], numi*i+j);
221                 if(mp.getType() == MapObject.PLAYER)
222                 {
223                     pi = i; pj = j;
224                 }
225             }
226             else
227                 throw new NonEmptyException("(" + i + "," + j + ") cannot be moved into");
228         }
229         else
230             throw new InvalidLocationException("Invalid Location (" + i + "," + j + ")");
231     }
232     /**
233      * Removes and returns the MapObject at the specified Location
234      * 
235      * @param i the row
236      * @param j the column
237      * @exception InvalidLocationException iff !isValidException(i, j)
238      */
239     public synchronized MapObject removeObject(int i, int j) throws InvalidLocationException
240     {
241         if(isValidLocation(i, j))
242         {
243             remove(mp[i][j]);
244             MapObject mo = mp[i][j];
245             mp[i][j] = def.getClone();
246             add(mp[i][j], numi*i+j);
247             return mo;
248         }
249         else
250             throw new InvalidLocationException("Invalid Location (" + i + "," + j + ")");
251     }
252     /**
253      * Remove All Objects from the Grid.
254      */
255     public synchronized void removeAllObjects()
256     {
257         Player player = (Player)mp[pi][pj];
258         for(int i = 0; i < numi; i++)
259         {
260             for(int j = 0; j < numj; j++)
261             {
262                 mp[i][j] = def.getClone();
263             }
264         }
265         mp[0][0] = player;
266     }
267 
268     /**
269      * Gets the MapObject at i, j.
270      * 
271      * @param i the row
272      * @param j the columne
273      * @exception InvalidLocationException iff !isValidException(i, j)
274      * @exception EmptyLocationException if the Location only contains the default MapObject
275      */
276     public synchronized MapObject mapObjectAt(int i, int j) throws EmptyLocationException, InvalidLocationException
277     {
278         if(battle)
279             return null;
280         if(isValidLocation(i, j))
281         {
282             if( !(mp[i][j].canBeEntered()) )
283             {
284                 return mp[i][j];
285             }
286             else
287             {
288                 throw new EmptyLocationException("("+ i + "," + j + " contains no usable Object");
289             }
290         }
291         else
292             throw new InvalidLocationException("("+ i + "," + j + " is not a valid location");
293     }
294 
295     /**
296      * Gets the Location of the specified MapObject, uses equals(Object o).
297      * Has a O(n*n) run time.
298      * 
299      * @param mp the MapObject to search for.
300      */
301     public Location locationOf(MapObject mp) throws InvalidLocationException
302     {
303         for(int i = 0; i < numi; i++)
304         {
305             for(int j = 0; j < numj; j++)
306             {
307                 if(this.mp[i][j] == mp)
308                     return new Location(i, j);
309             }
310         }
311         throw new InvalidLocationException("MapObject not found on Grid");
312     }
313     /**
314      * Returns the MapObject in the direction specified within the distance specified from the i, j specified.
315      * 
316      * @param i the row
317      * @param j the column
318      * @param dir the direction as specified above
319      * @param distance the distance to look
320      * @exception InvalidLocationException iff !isValidException(i, j)
321      */
322     public synchronized MapObject isPeopleInDirection(int i, int j, int dir, int distance) throws InvalidLocationException
323     {
324         if(battle)
325             return null;
326         if(isValidLocation(i, j))
327         {
328             int d = 1;
329             if(dir == LEFT)
330             {
331                 for(--j; j < numj && d <= distance && j >= 0; j--, d++)
332                 {
333                     if(mp[i][j].getType() == MapObject.PLAYER || mp[i][j].getType() == MapObject.PERSON)
334                     {
335                         return mp[i][j];
336                     }
337                     else if(!(mp[i][j].canBeEntered())) // can't see over rocks, etc
338                     {
339                         return null;
340                     }
341                 }
342             }
343             else if(dir == RIGHT)
344             {
345                 for(++j; j < numj && d <= distance && j >=0; j++, d++)
346                 {
347                     if(mp[i][j].getType() == MapObject.PLAYER || mp[i][j].getType() == MapObject.PERSON)
348                     {
349                         return mp[i][j];
350                     }
351                     else if(!(mp[i][j].canBeEntered())) // can't see over rocks, etc
352                     {
353                         return null;
354                     }
355                 }
356             }
357             else if(dir == UP)
358             {
359                 for(--i; i < numi && d <= distance && i >= 0; i--, d++)
360                 {
361                     if(mp[i][j].getType() == MapObject.PLAYER || mp[i][j].getType() == MapObject.PERSON)
362                     {
363                         return mp[i][j];
364                     }
365                     else if(!(mp[i][j].canBeEntered())) // can't see over rocks, etc
366                     {
367                         return null;
368                     }
369                 }
370             }
371             else if(dir == DOWN)
372             {
373                 for(++i; i < numi && d <= distance && i >= 0; i++, d++)
374                 {
375                     if(mp[i][j].getType() == MapObject.PLAYER || mp[i][j].getType() == MapObject.PERSON)
376                     {
377                         return mp[i][j];
378                     }
379                     else if(!(mp[i][j].canBeEntered())) // can't see over rocks, etc
380                     {
381                         return null;
382                     }
383                 }
384             }
385             return null;
386         }
387         else
388             throw new InvalidLocationException("("+ i + "," + j + " is not a valid location");
389     }
390     /**
391      * Gets the Player of this.
392      * 
393      * @return the Player of this
394      */
395     public synchronized Player getPlayer() { return (Player)mp[pi][pj]; }
396     /**
397      * Moves the Player in the direction specified
398      * 
399      * @param direction the direction to move the player, as specified above
400      */
401     public synchronized void movePlayerTo(int direction) throws NonEmptyException, InvalidLocationException
402     {
403         battle = false;
404         switch(direction)
405         {
406             case LEFT:
407             {
408                 if(pj-1 >= 0)
409                 {
410                     if(mp[pi][pj-1].getType() == MapObject.REDIRECT)
411                     {
412                         if(((Player)mp[pi][pj]).getBadgeCount() >= ((Redirect)mp[pi][pj-1]).getNumberBadgesRequired())
413                             fireRedirectEvent((Redirect)mp[pi][pj-1]);
414                         return;
415                     }
416                     else if(!canMove(pi, pj-1))
417                         return;
418                     Player player = (Player)removeObject(pi, pj);
419                     pj--;
420                     if(mp[pi][pj].getType() == MapObject.MONSTER)
421                     {
422                         Monster m = (Monster)removeObject(pi, pj);
423                         setObjectAt(player, pi, pj);
424                         beginBattleWithPlayer(m);
425                     }
426                     else
427                     {
428                         setObjectAt(player, pi, pj);
429                     }
430                 }
431                 else
432                     throw new NonEmptyException("(" + (pi-1) + "," + pj + ") is cannot be moved into");
433                 break;
434             }
435             case RIGHT:
436             {
437                 if(pj+1 < numj)
438                 {
439                     if(mp[pi][pj+1].getType() == MapObject.REDIRECT)
440                     {
441                         if(((Player)mp[pi][pj]).getBadgeCount() >= ((Redirect)mp[pi][pj+1]).getNumberBadgesRequired())
442                             fireRedirectEvent((Redirect)mp[pi][pj+1]);
443                         return;
444                     }
445                     else if(!canMove(pi, pj+1))
446                         return;
447                     Player player = (Player)removeObject(pi, pj);
448                     pj++;
449                     if(mp[pi][pj].getType() == MapObject.MONSTER)
450                     {
451                         Monster m = (Monster)removeObject(pi, pj);
452                         setObjectAt(player, pi, pj);
453                         beginBattleWithPlayer(m);
454                     }
455                     else
456                     {
457                         setObjectAt(player, pi, pj);
458                     }
459                 }
460                 else
461                     throw new NonEmptyException("(" + (pi+1) + "," + pj + ") is cannot be moved into");
462                 break;
463             }
464             case UP:
465             {
466                 if(pi-1 >= 0)
467                 {
468                     if(mp[pi-1][pj].getType() == MapObject.REDIRECT)
469                     {
470                         if(((Player)mp[pi][pj]).getBadgeCount() >= ((Redirect)mp[pi-1][pj]).getNumberBadgesRequired())
471                             fireRedirectEvent((Redirect)mp[pi-1][pj]);
472                         return;
473                     }
474                     else if(!canMove(pi-1, pj))
475                         return;
476                     Player player = (Player)removeObject(pi, pj);
477                     pi--;
478                     if(mp[pi][pj].getType() == MapObject.MONSTER)
479                     {
480                         Monster m = (Monster)removeObject(pi, pj);
481                         setObjectAt(player, pi, pj);
482                         beginBattleWithPlayer(m);
483                     }
484                     else
485                     {
486                         setObjectAt(player, pi, pj);
487                     }
488                 }
489                 else
490                     throw new NonEmptyException("(" + pi + "," + (pj-1) + ") is cannot be moved into");
491                 break;
492             }
493             case DOWN:
494             {
495                 if(pi+1 < numj)
496                 {
497                     if(mp[pi+1][pj].getType() == MapObject.REDIRECT)
498                     {
499                         if(((Player)mp[pi][pj]).getBadgeCount() >= ((Redirect)mp[pi+1][pj]).getNumberBadgesRequired())
500                             fireRedirectEvent((Redirect)mp[pi+1][pj]);
501                         return;
502                     }
503                     else if(!canMove(pi+1, pj))
504                         return;
505                     Player player = (Player)removeObject(pi, pj);
506                     pi++;
507                     if(mp[pi][pj].getType() == MapObject.MONSTER)
508                     {
509                         Monster m = (Monster)removeObject(pi, pj);
510                         setObjectAt(player, pi, pj);
511                         beginBattleWithPlayer(m);
512                     }
513                     else
514                     {
515                         setObjectAt(player, pi, pj);
516                     }
517                 }
518                 else
519                     throw new NonEmptyException("(" + pi + "," + (pj+1) + ") is cannot be moved into");
520                 break;
521             }
522         }
523     }
524 
525     /**
526      * Moves the MapObject at i, j to ni, nj.
527      * 
528      * @param i the row originally at
529      * @param j the column origanally at
530      * @param ni the new row
531      * @param nj the new column
532      * @exception InvalidLocationException iff !isValidException(i, j)
533      * @exception NonEmptyException iff !canMove(i, j)
534      * @exception EmptyLocationException Will Not Be Thrown.
535      */
536     public synchronized void moveMapObjectTo(int i, int j, int ni, int nj) throws NonEmptyException, InvalidLocationException, EmptyLocationException
537     {
538         if(battle)
539             return;
540         if(isValidLocation(i, j))
541         {
542             if(isValidLocation(ni, nj))
543             {
544                 if(canMove(ni, nj))
545                 {
546                     MapObject mp = removeObject(i, j);
547                     if(mp.getType() == MapObject.PERSON)
548                         setObjectAt(mp, ni, nj);
549                 }
550                 else
551                     throw new NonEmptyException("(" + (i) + "," + j + ") is cannot be moved into");
552             }
553         }
554         else
555             throw new InvalidLocationException("(" + i + "," + j + ") is not a valid location");
556     }
557     /**
558      * Handle the Events.  Overriden to handle the KeyEvents.
559      * 
560      * @param e the AWTEvent to process
561      */
562     public synchronized void processEvent(AWTEvent e) 
563     {
564         if(e.getID() == KeyEvent.KEY_PRESSED)
565         {
566             int ti = pi, tj = pj;
567             try
568             {
569                 switch(((KeyEvent)e).getKeyCode())
570                 {
571                     case KeyEvent.VK_LEFT:
572                         {
573                         movePlayerTo(LEFT);
574                         ((Player)mp[pi][pj]).setDirection(LEFT);
575                         //((Player)mp[pi][pj]).stopBattle();
576                         break;
577                     }
578                     case KeyEvent.VK_RIGHT:
579                         {
580                         movePlayerTo(RIGHT);
581                         ((Player)mp[pi][pj]).setDirection(RIGHT);
582                         //((Player)mp[pi][pj]).stopBattle();
583                         break;
584                     }
585                     case KeyEvent.VK_UP:
586                         {
587                         movePlayerTo(UP);
588                         ((Player)mp[pi][pj]).setDirection(UP);
589                         //((Player)mp[pi][pj]).stopBattle();
590                         break;
591                     }
592                     case KeyEvent.VK_DOWN:
593                         {
594                         movePlayerTo(DOWN);
595                         ((Player)mp[pi][pj]).setDirection(DOWN);
596                         //((Player)mp[pi][pj]).stopBattle();
597                         break;
598                     }
599                 }
600                 repaint(ti, tj);
601                 repaint(pi, pj);
602             }
603             catch (Exception ile) { }
604         }
605         super.processEvent(e);
606     }
607     /**
608      * Allow wild Monsters of type m on this.
609      * 
610      * @param m the Monster.<type> to allow
611      */
612     public void allowMonsterOnMap(int m)
613     {
614         if(m == Monster.ELECTRIC || m == Monster.EARTH || m == Monster.FIRE || m == Monster.WATER || m == Monster.GAS)
615             monAllow.add(new Integer(m));
616     }
617     /**
618      * Sets the wild Monsters level for this
619      * 
620      * @param l the level of the wild Monsters
621      */
622     public void setMonsterLevel(int l)
623     {
624         if(l > 1 && l < Monster.MAXLEVEL)
625             monsterLevel = l;
626     }
627     /**
628      * Fills the Grid in a standard manner, useful for debugging.
629      */
630     public void fillGrid() // Temporary until MAP implemented
631     {
632         battle = false;
633         int wi, hi;
634         wi = getWidth()/numj;
635         hi = getHeight()/numi;
636         def = new Grass();
637 
638         for(int i = 0; i < numi; i++)
639         {
640             for(int j = 0; j < numj; j++)
641             {
642                 if(mp[i][j] == null)
643                 {
644                     if(i%5 == j%10)
645                         mp[i][j] = new Rock();
646                     else
647                         mp[i][j] = def.getClone();
648                     add(mp[i][j]);
649                 }
650             }
651         }
652         try
653         {
654             removeObject(0, 0);
655             People pl = new Player();
656             setObjectAt(pl, 0, 0);
657             pi = 0; pj = 0;
658 
659             removeObject(15, 15);
660             pl = new Person(DOWN);
661             setObjectAt(pl, 15, 15);
662             ((Person)pl).setGrid(this);
663 
664             removeObject(numi/2,numj/2);
665             pl = new Person(LEFT);
666             setObjectAt(pl, numi/2, numj/2);
667             ((Person)pl).setGrid(this);
668 
669             removeObject(numi/4,numj/4);
670             pl = new Person(LEFT);
671             setObjectAt(pl, numi/4, numj/4);
672             ((Person)pl).setGrid(this);
673 
674             removeObject(numi/5,numj/5);
675             pl = new Person(LEFT);
676             setObjectAt(pl, numi/5, numj/5);
677             ((Person)pl).setGrid(this);
678 
679             removeObject(numi/6,numj/6);
680             pl = new Person(LEFT);
681             setObjectAt(pl, numi/5, numj/5);
682             ((Person)pl).setGrid(this);
683         }
684         catch(Exception e) { }
685     }
686     /**
687      * Initialize the Grid, ie start the Peopl Moving, and fill this
688      * with wild Monsters
689      */
690     public void init()
691     {
692         battle = false;
693         try
694         {
695             Random r = new Random();
696             r.setSeed(System.currentTimeMillis());
697             for(int i = 0; i < DEFAULTNUM; i++)
698             {
699                 for(int j = 0; j < DEFAULTNUM; j++)
700                 {
701                     if(mp[i][j].getType() == MapObject.PERSON)
702                     {
703                         ((Person)mp[i][j]).setGrid(this);
704                     }
705                     else if(mp[i][j].getType() == MapObject.TRAINER)
706                     {
707                         ((Trainer)mp[i][j]).setGrid(this);
708                     }
709                     else if(mp[i][j].getType() == MapObject.MONSTER)
710                     {
711                         removeObject(i, j);
712                     }
713                 }
714             }
715             if(monAllow.size() <= 0)
716                 return;
717 
718             // Adding 10 Monsters Randomly distrubuted
719             Monster m;
720             MapObject ma;
721             int lev10, lev7, lev6;
722             lev10 = monsterLevel*10;
723             lev7 = monsterLevel*7;
724             lev6 = monsterLevel*6;
725             for(int i = 0, j = 0, s, t, u; i < 10; i++, j=0)
726             {
727                 do
728                 {
729                     j++;
730                     s = r.nextInt(DEFAULTNUM);
731                     t = r.nextInt(DEFAULTNUM);
732                 } while( !(mp[s][t].canBeEntered()) && j < 5 );
733                 removeObject(s, t);
734                 ma = def.getClone();
735                 u = r.nextInt(monAllow.size());
736                 switch(((Integer)monAllow.get(u)).intValue())
737                 {
738                     case Monster.FIRE:
739                     {
740                         m = new FireMon((s%2 == 0 ? "MoPyro" : "Flamesaur"));
741                         m.setBehind(ma);
742                         
743                         m.setLevel(monsterLevel);
744                         m.setMaxHP(lev10);
745                         m.setHP(lev10);
746                         m.setDefense(lev7);
747                         m.setMaxDefense(lev7);
748                         m.setAttack(lev6);
749                         m.setMaxAttack(lev6);
750                         m.setMaxExperience(lev10);
751                         m.setExperience(Math.abs(lev10-20));
752 
753                         if(monsterLevel > 30)
754                             m.addAttack(FireMon.A3);
755                         if(monsterLevel >= 40)
756                             m.addAttack(FireMon.A4);
757 
758                         setObjectAt(m,s, t);
759                         break;
760                     }
761                     case Monster.WATER:
762                     {
763                         m = new WaterMon((s%2 == 0 ? "Alligatrix" : "Sharkasaur"));
764                         m.setBehind(ma);
765 
766                         m.setLevel(monsterLevel);
767                         m.setMaxHP(lev6);
768                         m.setHP(lev6);
769                         m.setDefense(lev10);
770                         m.setMaxDefense(lev10);
771                         m.setAttack(lev7);
772                         m.setMaxAttack(lev7);
773                         m.setMaxExperience(lev10);
774                         m.setExperience(Math.abs(lev10-20));
775 
776                         if(monsterLevel > 30)
777                             m.addAttack(WaterMon.A3);
778                         if(monsterLevel >= 40)
779                             m.addAttack(WaterMon.A4);
780 
781                         setObjectAt(m,s, t);
782                         break;
783                     }
784                     case Monster.EARTH:
785                     {
786                         m = new EarthMon((s%2 == 0 ? "Rhono" : "Groundyx"));
787                         m.setBehind(ma);
788                         
789                         m.setLevel(monsterLevel);
790                         m.setMaxHP(lev10);
791                         m.setHP(lev10);
792                         m.setDefense(lev6);
793                         m.setMaxDefense(lev6);
794                         m.setAttack(lev7);
795                         m.setMaxAttack(lev7);
796                         m.setMaxExperience(lev10);
797                         m.setExperience(Math.abs(lev10-20));
798 
799                         if(monsterLevel > 30)
800                             m.addAttack(EarthMon.A3);
801                         if(monsterLevel >= 40)
802                             m.addAttack(EarthMon.A4);
803 
804                         setObjectAt(m,s, t);
805                         break;
806                     }
807                     case Monster.GAS:
808                     {
809                         m = new GasMon((s%2 == 0 ? "Smelltor" : "Eurekasaur"));
810                         m.setBehind(ma);
811                         
812                         m.setLevel(monsterLevel);
813                         m.setMaxHP(lev7);
814                         m.setHP(lev7);
815                         m.setDefense(lev10);
816                         m.setMaxDefense(lev10);
817                         m.setAttack(lev6);
818                         m.setMaxAttack(lev6);
819                         m.setMaxExperience(lev10);
820                         m.setExperience(Math.abs(lev10-20));
821 
822                         if(monsterLevel > 30)
823                             m.addAttack(GasMon.A3);
824                         if(monsterLevel >= 40)
825                             m.addAttack(GasMon.A4);
826 
827                         setObjectAt(m,s, t);
828                         break;
829                     }
830                     case Monster.ELECTRIC:
831                     {
832                         m = new ElectricMon((s%2 == 0 ? "Shockachu" : "Voltasaur"));
833                         m.setBehind(ma);
834                         
835                         m.setLevel(monsterLevel);
836                         m.setMaxHP(lev6);
837                         m.setHP(lev6);
838                         m.setDefense(lev7);
839                         m.setMaxDefense(lev7);
840                         m.setAttack(lev10);
841                         m.setMaxAttack(lev10);
842                         m.setMaxExperience(lev10);
843                         m.setExperience(Math.abs(lev10-20));
844 
845                         if(monsterLevel > 30)
846                             m.addAttack(ElectricMon.A3);
847                         if(monsterLevel >= 40)
848                             m.addAttack(ElectricMon.A4);
849 
850                         setObjectAt(m,s, t);
851                         break;
852                     }
853                 }
854             }
855         } 
856         catch(Exception e) { }
857     }
858     /**
859      * Removes the older wild Monsters, and add new ones randomly
860      * from th selection allowed.
861      */
862     public void fillMonsters()
863     {
864         try
865         {
866             for(int i = 0; i < DEFAULTNUM; i++)
867             {
868                 for(int j = 0; j < DEFAULTNUM; j++)
869                 {
870                     if(mp[i][j].getType() == MapObject.MONSTER)
871                     {
872                         removeObject(i, j);
873                     }
874                 }
875             }
876             Random r = new Random();
877             r.setSeed(System.currentTimeMillis());
878             battle = false;
879             if(monAllow.size() <= 0)
880                 return;
881             // Adding 10 Monsters Randomly distrubuted
882             Monster m;
883             MapObject ma;
884             int lev10, lev7, lev6;
885             lev10 = monsterLevel*10;
886             lev7 = monsterLevel*7;
887             lev6 = monsterLevel*6;
888             for(int i = 0, s, t, u, j = 0; i < 10; i++, j = 0)
889             {
890                 do
891                 {
892                     j++;
893                     s = r.nextInt(DEFAULTNUM);
894                     t = r.nextInt(DEFAULTNUM);
895                 } while( !(mp[s][t].canBeEntered()) && j < 5);
896                 removeObject(s, t);
897                 ma = def.getClone();
898                 u = r.nextInt(monAllow.size());
899                 switch(((Integer)monAllow.get(u)).intValue())
900                 {
901                     case Monster.FIRE:
902                         {
903                         m = new FireMon((s%2 == 0 ? "MoPyro" : "Flamesaur"));
904                         m.setBehind(ma);
905                         
906                         m.setLevel(monsterLevel);
907                         m.setMaxHP(lev10);
908                         m.setHP(lev10);
909                         m.setDefense(lev7);
910                         m.setMaxDefense(lev7);
911                         m.setAttack(lev6);
912                         m.setMaxAttack(lev6);
913                         m.setMaxExperience(lev10);
914                         m.setExperience(Math.abs(lev10-20));
915 
916                         if(monsterLevel > 30)
917                             m.addAttack(FireMon.A3);
918                         if(monsterLevel >= 40)
919                             m.addAttack(FireMon.A4);
920 
921                         setObjectAt(m,s, t);
922                         break;
923                     }
924                     case Monster.WATER:
925                         {
926                         m = new WaterMon((s%2 == 0 ? "Alligatrix" : "Sharkasaur"));
927                         m.setBehind(ma);
928 
929                         m.setLevel(monsterLevel);
930                         m.setMaxHP(lev6);
931                         m.setHP(lev6);
932                         m.setDefense(lev10);
933                         m.setMaxDefense(lev10);
934                         m.setAttack(lev7);
935                         m.setMaxAttack(lev7);
936                         m.setMaxExperience(lev10);
937                         m.setExperience(Math.abs(lev10-20));
938 
939                         if(monsterLevel > 30)
940                             m.addAttack(WaterMon.A3);
941                         if(monsterLevel >= 40)
942                             m.addAttack(WaterMon.A4);
943 
944                         setObjectAt(m,s, t);
945                         break;
946                     }
947                     case Monster.EARTH:
948                         {
949                         m = new EarthMon((s%2 == 0 ? "Rhono" : "Groundyx"));
950                         m.setBehind(ma);
951                         
952                         m.setLevel(monsterLevel);
953                         m.setMaxHP(lev10);
954                         m.setHP(lev10);
955                         m.setDefense(lev6);
956                         m.setMaxDefense(lev6);
957                         m.setAttack(lev7);
958                         m.setMaxAttack(lev7);
959                         m.setMaxExperience(lev10);
960                         m.setExperience(Math.abs(lev10-20));
961 
962                         if(monsterLevel > 30)
963                             m.addAttack(EarthMon.A3);
964                         if(monsterLevel >= 40)
965                             m.addAttack(EarthMon.A4);
966 
967                         setObjectAt(m,s, t);
968                         break;
969                     }
970                     case Monster.GAS:
971                         {
972                         m = new GasMon((s%2 == 0 ? "Smelltor" : "Eurekasaur"));
973                         m.setBehind(ma);
974                         
975                         m.setLevel(monsterLevel);
976                         m.setMaxHP(lev7);
977                         m.setHP(lev7);
978                         m.setDefense(lev10);
979                         m.setMaxDefense(lev10);
980                         m.setAttack(lev6);
981                         m.setMaxAttack(lev6);
982                         m.setMaxExperience(lev10);
983                         m.setExperience(Math.abs(lev10-20));
984 
985                         if(monsterLevel > 30)
986                             m.addAttack(GasMon.A3);
987                         if(monsterLevel >= 40)
988                             m.addAttack(GasMon.A4);
989 
990                         setObjectAt(m,s, t);
991                         break;
992                     }
993                     case Monster.ELECTRIC:
994                         {
995                         m = new ElectricMon((s%2 == 0 ? "Shockachu" : "Voltasaur"));
996                         m.setBehind(ma);
997                         
998                         m.setLevel(monsterLevel);
999                         m.setMaxHP(lev6);
1000                        m.setHP(lev6);
1001                        m.setDefense(lev7);
1002                        m.setMaxDefense(lev7);
1003                        m.setAttack(lev10);
1004                        m.setMaxAttack(lev10);
1005                        m.setMaxExperience(lev10);
1006                        m.setExperience(Math.abs(lev10-20));
1007
1008                        if(monsterLevel > 30)
1009                            m.addAttack(ElectricMon.A3);
1010                        if(monsterLevel >= 40)
1011                            m.addAttack(ElectricMon.A4);
1012
1013                        setObjectAt(m,s, t);
1014                        break;
1015                    }
1016                }
1017            }
1018        }
1019        catch(Exception e) { }
1020    }
1021    /**
1022     * Destroy all threads tied to this by setting their
1023     * Grid Objects to null.
1024     * 
1025     * @see PersonAI
1026     * @see Trainer
1027     */
1028    public void destroy()
1029    {
1030        for(int i = 0; i < DEFAULTNUM; i++)
1031        {
1032            for(int j = 0; j < DEFAULTNUM; j++)
1033            {
1034                if(mp[i][j].getType() == MapObject.PERSON)
1035                {
1036                    ((Person)mp[i][j]).setGrid(null); // Kill AI
1037                }
1038                else if(mp[i][j].getType() == MapObject.TRAINER)
1039                {
1040                    ((Trainer)mp[i][j]).setGrid(null); // Kill AI
1041                }
1042                mp[i][j] = null; // Kill ME
1043            }
1044        }
1045    }
1046    /**
1047     * Draws the components of this
1048     * 
1049     * @param g the Graphics
1050     */
1051    public synchronized void paint(Graphics g)
1052    {
1053        this.g = g;
1054        super.paint(g);
1055    }
1056    /**
1057     * Overriden to rmove the flickering effect
1058     * 
1059     * @param g the Graphics
1060     */
1061    public synchronized void update(Graphics g) // Remove Filcker Effect Limits to one the number of enterable MapObjects
1062    {
1063        paint(g);
1064    }
1065    /**
1066     * Repaint the Location specified.
1067     * 
1068     * @param i the row
1069     * @param j the column
1070     */
1071    public synchronized void repaint(int i, int j)
1072    {
1073        if(isValidLocation(i, j))
1074        {
1075            int w = getSize().width/numj;
1076            int h = getSize().height/numi;
1077            int x = j*w/numj;
1078            int y = i*h/numi;
1079            g.setClip(x, y, w, h);
1080            paintAll(g);
1081        }
1082    }
1083
1084    /**
1085     * Add a class to be notified of Battles
1086     * 
1087     * @param the class to notify
1088     */
1089    public void addBattleListener(BattleListener bl)
1090    {
1091        if ( battleListeners == null )
1092            battleListeners = new Vector();
1093        battleListeners.addElement( bl );
1094    }
1095    /**
1096     * Removes a class that was being notified.
1097     * 
1098     * @param the class to stop notifying
1099     */
1100    public void removeBattleListener(BattleListener bl)
1101    {
1102            if ( battleListeners != null )
1103                battleListeners.removeElement( bl );
1104    }
1105    /**
1106     * Fire a BattleEvent, and inform all classes that are listening
1107     * 
1108     * @param mp the MapObject of the Players Opponent
1109     */
1110    private synchronized void fireEvent(MapObject mp) 
1111    {
1112        if ( battleListeners == null )
1113            return;
1114        BattleEvent event = new BattleEvent(this, BattleEvent.BATTLE_STARTED, this.mp[pi][pj], mp);
1115        for (Enumeration e = battleListeners.elements(); e.hasMoreElements(); )
1116            ((BattleListener)e.nextElement()).battleBegin( event );
1117    }
1118    /**
1119     * Add a class to be notified of Battles
1120     * 
1121     * @param the class to notify
1122     */
1123    public void addRedirectListener(RedirectListener r)
1124    {
1125        if ( redirectListeners == null )
1126            redirectListeners = new Vector();
1127        redirectListeners.addElement( r );
1128    }
1129    /**
1130     * Removes a class that was being notified.
1131     * 
1132     * @param the class to stop notifying
1133     */
1134    public void removeRedirectListener(RedirectListener r)
1135    {
1136        if ( redirectListeners != null )
1137            redirectListeners.removeElement( r );
1138    }
1139    /**
1140     * Fire a RedirectEvent, and inform all classes that are listening
1141     * 
1142     * @param mp the Redirect
1143     * @see Redirect
1144     */
1145    private synchronized void fireRedirectEvent(Redirect mp) 
1146    {
1147        synchronized(this.mp[pi][pj])
1148        {
1149            battle = true;
1150            if ( redirectListeners == null )
1151                return;
1152            RedirectEvent event = new RedirectEvent(this, RedirectEvent.REDIRECT_FIRED, mp.getMapTo(), (Player)this.mp[pi][pj]);
1153            for (Enumeration e = redirectListeners.elements(); e.hasMoreElements(); )
1154                ((RedirectListener)e.nextElement()).redirectFired( event );
1155        }
1156    }
1157    /**
1158     * Call to begin a battle with th Player, fires the events.
1159     * 
1160     * @param opp the Opponent of the Player.
1161     */
1162    public synchronized void beginBattleWithPlayer(MapObject opp)
1163    {
1164        synchronized(mp[pi][pj]) // Don't let others look at me!
1165        {                           // They're all gonna laugh at me!!
1166            synchronized(opp)
1167            {
1168                if(((Player)mp[pi][pj]).isBattling())
1169                    return;
1170                battle = true;
1171                ((Player)mp[pi][pj]).battle(); // I'll teach them a lesson!
1172                fireEvent(opp); // Let's fight, we'll see whose laughing!
1173            }
1174        }
1175    }
1176}