001         package com.croftsoft.apps.mars.model.seri;
002    
003         import java.awt.*;
004         import java.io.*;
005         import java.util.*;
006    
007         import com.croftsoft.core.lang.NullArgumentException;
008         import com.croftsoft.core.math.geom.Point2DD;
009         import com.croftsoft.core.math.geom.PointXY;
010         import com.croftsoft.core.math.geom.ShapeLib;
011         import com.croftsoft.core.util.ArrayKeeper;
012         import com.croftsoft.core.util.ArrayLib;
013         import com.croftsoft.core.util.StableArrayKeeper;
014    
015         import com.croftsoft.apps.mars.ai.DefaultTankOperator;
016         import com.croftsoft.apps.mars.ai.TankOperator;
017    
018         import com.croftsoft.apps.mars.model.AmmoDump;
019         import com.croftsoft.apps.mars.model.AmmoDumpAccessor;
020         import com.croftsoft.apps.mars.model.Bullet;
021         import com.croftsoft.apps.mars.model.Damageable;
022         import com.croftsoft.apps.mars.model.Game;
023         import com.croftsoft.apps.mars.model.Impassable;
024         import com.croftsoft.apps.mars.model.Model;
025         import com.croftsoft.apps.mars.model.ModelAccessor;
026         import com.croftsoft.apps.mars.model.Obstacle;
027         import com.croftsoft.apps.mars.model.Tank;
028         import com.croftsoft.apps.mars.model.TankAccessor;
029         import com.croftsoft.apps.mars.model.World;
030    
031         /*********************************************************************
032         * A World implementation.
033         *
034         * @version
035         *   2003-05-11
036         * @since
037         *   2003-04-03
038         * @author
039         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
040         *********************************************************************/
041    
042         public final class  SeriWorld
043           implements World, Serializable
044         //////////////////////////////////////////////////////////////////////
045         //////////////////////////////////////////////////////////////////////
046         {
047    
048         private static final long  serialVersionUID = 0L;
049    
050         //
051    
052         private final Random               random;
053    
054         private final SeriAmmoDump.Shared  seriAmmoDumpShared;
055    
056         private final ArrayKeeper          modelArrayKeeper;
057    
058         private final Point2DD             center;
059    
060         private final java.util.List       modelList;
061    
062         //////////////////////////////////////////////////////////////////////
063         //////////////////////////////////////////////////////////////////////
064    
065         public  SeriWorld (
066           Random               random,
067           SeriAmmoDump.Shared  seriAmmoDumpShared )
068         //////////////////////////////////////////////////////////////////////
069         {
070           modelArrayKeeper = new StableArrayKeeper ( new Model [ 0 ] );
071    
072           center = new Point2DD ( );
073    
074           NullArgumentException.check ( this.random = random );
075    
076           NullArgumentException.check (
077             this.seriAmmoDumpShared = seriAmmoDumpShared );
078    
079           modelList = new ArrayList ( );
080         }
081    
082         //////////////////////////////////////////////////////////////////////
083         //////////////////////////////////////////////////////////////////////
084    
085         public void  clear ( )
086         //////////////////////////////////////////////////////////////////////
087         {
088           modelArrayKeeper.setArray ( new Model [ 0 ] );
089         }
090    
091         public AmmoDump  createAmmoDump (
092           double  centerX,
093           double  centerY )
094         //////////////////////////////////////////////////////////////////////
095         {
096           SeriAmmoDump  seriAmmoDump = new SeriAmmoDump (
097             this,
098             centerX,
099             centerY,
100             seriAmmoDumpShared.ammoMax,
101             seriAmmoDumpShared );
102    
103           modelArrayKeeper.insert ( seriAmmoDump );
104    
105           return seriAmmoDump;
106         }
107    
108         public Bullet  createBullet (
109           double  originX,
110           double  originY,
111           double  heading )
112         //////////////////////////////////////////////////////////////////////
113         {
114           SeriBullet  seriBullet
115             = new SeriBullet ( this, originX, originY, heading );
116    
117           modelArrayKeeper.insert ( seriBullet );
118    
119           return seriBullet;
120         }
121    
122         public Obstacle  createObstacle (
123           double     centerX,
124           double     centerY,
125           double     radius,
126           double     radiusMin,
127           Rectangle  driftBounds )
128         //////////////////////////////////////////////////////////////////////
129         {
130           SeriObstacle  seriObstacle = new SeriObstacle (
131             this, centerX, centerY, radius, radiusMin, random, driftBounds );
132    
133           modelArrayKeeper.insert ( seriObstacle );
134    
135           return seriObstacle;
136         }
137    
138         public Tank  createTank (
139           double  centerX,
140           double  centerY,
141           Color   color )
142         //////////////////////////////////////////////////////////////////////
143         {
144           SeriTank  seriTank = new SeriTank ( this, centerX, centerY, color );
145    
146           TankOperator  tankOperator = new DefaultTankOperator ( random );
147    
148           seriTank.setTankOperator ( tankOperator );
149    
150           tankOperator.setTankConsole ( seriTank );
151    
152           modelArrayKeeper.insert ( seriTank );
153    
154           return seriTank;
155         }
156    
157         public void  remove ( Model  model )
158         //////////////////////////////////////////////////////////////////////
159         {
160           modelArrayKeeper.remove ( model );
161         }
162    
163         //////////////////////////////////////////////////////////////////////
164         //////////////////////////////////////////////////////////////////////
165    
166         public AmmoDump [ ]  getAmmoDumps (
167           PointXY       pointXY,
168           AmmoDump [ ]  ammoDumps )
169         //////////////////////////////////////////////////////////////////////
170         {
171           return ( AmmoDump [ ] ) getModels (
172             pointXY,
173             ammoDumps,
174             AmmoDump.class );
175         }
176    
177         public Damageable [ ]  getDamageables (
178           Shape           shape,
179           Damageable [ ]  damageables )
180         //////////////////////////////////////////////////////////////////////
181         {
182           return ( Damageable [ ] ) getModels (
183             shape,
184             damageables,
185             Damageable.class );
186         }
187    
188         public Impassable [ ]  getImpassables ( )
189         //////////////////////////////////////////////////////////////////////
190         {
191           return ( Impassable [ ] )
192             modelArrayKeeper.getArray ( Impassable.class );
193         }
194    
195         public Iterator  getImpassables (
196           Shape  shape,
197           Model  model )
198         //////////////////////////////////////////////////////////////////////
199         {
200           modelList.clear ( );
201    
202           Impassable [ ]  impassables = getImpassables ( );
203    
204           for ( int  i = 0; i < impassables.length; i++ )
205           {
206             Impassable  impassable = impassables [ i ];
207    
208             if ( ( impassable != model )
209               && impassable.isActive ( )
210               && ShapeLib.intersects ( shape, impassable.getShape ( ) ) )
211             {
212               modelList.add ( impassable );
213             }
214           }
215    
216           return modelList.iterator ( );
217         }
218    
219    
220         public Model [ ]  getModels ( )
221         //////////////////////////////////////////////////////////////////////
222         {
223           return ( Model [ ] ) modelArrayKeeper.getArray ( );
224         }
225    
226         public ModelAccessor [ ]  getModelAccessors (
227           ModelAccessor [ ]  modelAccessors )       
228         //////////////////////////////////////////////////////////////////////
229         {
230           return getModelAccessors ( ( Shape ) null, modelAccessors );
231         }
232    
233         public ModelAccessor [ ]  getModelAccessors (
234           Shape              shape,
235           ModelAccessor [ ]  modelAccessors )       
236         //////////////////////////////////////////////////////////////////////
237         {
238           Model [ ]  allModels = getModels ( );
239    
240           if ( shape == null )
241           {
242             return allModels;
243           }
244    
245           NullArgumentException.check ( modelAccessors );
246    
247           int  index = 0;
248    
249           for ( int  i = 0; i < allModels.length; i++ )
250           {
251             Model  model = allModels [ i ];
252    
253             if ( ShapeLib.intersects ( shape, model.getShape ( ) ) )
254             {
255               if ( index < modelAccessors.length )
256               {
257                 modelAccessors [ index ] = model;
258               }
259               else
260               {
261                 modelAccessors = ( ModelAccessor [ ] )
262                   ArrayLib.append ( modelAccessors, model );
263               }
264    
265               index++;
266             }
267           }
268    
269           if ( index < modelAccessors.length )
270           {
271             modelAccessors [ index ] = null;
272           }
273    
274           return modelAccessors;
275         }
276    
277         public Obstacle [ ]  getObstacles ( )
278         //////////////////////////////////////////////////////////////////////
279         {
280           return ( Obstacle [ ] )
281             modelArrayKeeper.getArray ( Obstacle.class );
282         }
283    
284         public Tank [ ]  getTanks ( )
285         //////////////////////////////////////////////////////////////////////
286         {
287           return ( Tank [ ] ) modelArrayKeeper.getArray ( Tank.class );
288         }
289    
290         //////////////////////////////////////////////////////////////////////
291         //////////////////////////////////////////////////////////////////////
292    
293         public void  prepare ( )
294         //////////////////////////////////////////////////////////////////////
295         {
296           Model [ ]  models = getModels ( );
297    
298           for ( int  i = 0; i < models.length; i++ )
299           {
300             models [ i ].prepare ( );
301           }
302         }
303    
304         public void  update ( double  timeDelta )
305         //////////////////////////////////////////////////////////////////////
306         {
307           Model [ ]  models = getModels ( );
308    
309           for ( int  i = 0; i < models.length; i++ )
310           {
311             models [ i ].update ( timeDelta );
312           }
313         }
314    
315         //////////////////////////////////////////////////////////////////////
316         //////////////////////////////////////////////////////////////////////
317    
318         public void  fireBullet (
319           double  originX,
320           double  originY,
321           double  heading )
322         //////////////////////////////////////////////////////////////////////
323         {
324           boolean  bulletFired = false;
325    
326           Bullet [ ]  bullets = ( Bullet [ ] )
327             modelArrayKeeper.getArray ( Bullet.class );
328    
329           for ( int  i = 0; i < bullets.length; i++ )
330           {
331             Bullet  bullet = bullets [ i ];
332    
333             if ( !bullet.isActive  ( )
334               && !bullet.isUpdated ( ) )
335             {
336               bullet.fire ( originX, originY, heading );
337    
338               bulletFired = true;
339    
340               break;
341             }
342           }
343    
344           if ( !bulletFired )
345           {
346             createBullet ( originX, originY, heading );
347           }
348         }
349    
350         public boolean  isBlockedByObstacle ( Shape  shape )
351         //////////////////////////////////////////////////////////////////////
352         {
353           Obstacle [ ]  obstacles = getObstacles ( );
354    
355           for ( int  i = 0; i < obstacles.length; i++ )
356           {
357             Obstacle  obstacle = obstacles [ i ];
358    
359             if ( obstacle.isActive ( )
360               && ShapeLib.intersects ( shape, obstacle.getShape ( ) ) )
361             {
362               return true;
363             }
364           }
365    
366           return false;
367         }
368    
369         public boolean  isBlocked (
370           Shape  shape,
371           Model  model )
372         //////////////////////////////////////////////////////////////////////
373         {
374           Impassable [ ]  impassables = getImpassables ( );
375    
376           for ( int  i = 0; i < impassables.length; i++ )
377           {
378             Impassable  impassable = impassables [ i ];
379    
380             if ( ( impassable != model )
381               && impassable.isActive ( )
382               && ShapeLib.intersects ( shape, impassable.getShape ( ) ) )
383             {
384               return true;
385             }
386           }
387    
388           return false;
389         }
390    
391         public boolean  isBlocked ( Model  model )
392         //////////////////////////////////////////////////////////////////////
393         {
394           return isBlocked ( model.getShape ( ), model );
395         }
396    
397         public PointXY  getClosestAmmoDumpCenter ( PointXY  pointXY )
398         //////////////////////////////////////////////////////////////////////
399         {
400           AmmoDumpAccessor  ammoDumpAccessor = ( AmmoDumpAccessor )
401             getModelClosest ( pointXY, AmmoDumpAccessor.class, null );
402    
403           if ( ammoDumpAccessor != null )
404           {
405             return
406               ShapeLib.getCenter ( ammoDumpAccessor.getShape ( ), center );
407           }
408    
409           return null;
410         }
411    
412         public PointXY  getClosestEnemyTankCenter (
413            PointXY  pointXY,
414            Color    friendColor )
415         //////////////////////////////////////////////////////////////////////
416         {
417           double  closestDistance = Double.POSITIVE_INFINITY;
418    
419           int  index = -1;
420    
421           TankAccessor [ ]  tankAccessors = ( TankAccessor [ ] )
422             modelArrayKeeper.getArray ( TankAccessor.class );
423    
424           for ( int  i = 0; i < tankAccessors.length; i++ )
425           {
426             TankAccessor  tankAccessor = tankAccessors [ i ];
427    
428             if ( tankAccessor.isActive ( )
429               && !tankAccessor.getColor ( ).equals ( friendColor ) )
430             {
431               double  distance = pointXY.distanceXY (
432                 ShapeLib.getCenter ( tankAccessor.getShape ( ), center ) );
433    
434    
435               if ( distance < closestDistance )
436               {
437                 closestDistance = distance;
438    
439                 index = i;
440               }
441             }
442           }
443    
444           if ( index > -1 )
445           {
446             return ShapeLib.getCenter (
447               tankAccessors [ index ].getShape ( ), center );
448           }
449    
450           return null;
451         }
452    
453         public Model  getModel (
454           PointXY    pointXY,
455           Class [ ]  classes,
456           Model      model )
457         //////////////////////////////////////////////////////////////////////
458         {
459           double  x = pointXY.getX ( );
460    
461           double  y = pointXY.getY ( );
462    
463           Model [ ]  models = getModels ( );
464    
465           for ( int  i = 0; i < models.length; i++ )
466           {
467             Model  otherModel = models [ i ];
468    
469             if ( ( otherModel != model )
470               && otherModel.isActive ( )
471               && otherModel.getShape ( ).contains ( x, y ) )
472             {
473               for ( int  j = 0; j < classes.length; j++ )
474               {
475                 if ( classes [ j ].isInstance ( otherModel ) )
476                 {
477                   return otherModel;
478                 }
479               }
480             }        
481           }
482    
483           return null;
484         }
485    
486         //////////////////////////////////////////////////////////////////////
487         //////////////////////////////////////////////////////////////////////
488    
489         private Model [ ]  getModels ( Class  c )
490         //////////////////////////////////////////////////////////////////////
491         {
492           if ( c == null )
493           {
494             return ( Model [ ] ) modelArrayKeeper.getArray ( );
495           }
496    
497           return ( Model [ ] ) modelArrayKeeper.getArray ( c );
498         }
499    
500         private Model [ ]  getModels (
501           PointXY    pointXY,
502           Model [ ]  models,
503           Class      c )
504         //////////////////////////////////////////////////////////////////////
505         {
506           Model [ ]  allModels = getModels ( c );
507    
508           if ( pointXY == null )
509           {
510             return allModels;
511           }
512    
513           NullArgumentException.check ( models );
514    
515           double  x = pointXY.getX ( );
516    
517           double  y = pointXY.getY ( );
518    
519           int  index = 0;
520    
521           for ( int  i = 0; i < allModels.length; i++ )
522           {
523             Model  model = allModels [ i ];
524    
525             if ( model.isActive ( )
526               && model.getShape ( ).contains ( x, y ) )
527             {
528               if ( index < models.length )
529               {
530                 models [ index ] = model;
531               }
532               else
533               {
534                 models = ( Model [ ] ) ArrayLib.append ( models, model );
535               }
536    
537               index++;
538             }
539           }
540    
541           if ( index < models.length )
542           {
543             models [ index ] = null;
544           }
545    
546           return models;
547         }
548    
549         private Model [ ]  getModels (
550           Shape      shape,
551           Model [ ]  models,
552           Class      c )
553         //////////////////////////////////////////////////////////////////////
554         {
555           Model [ ]  allModels = getModels ( c );
556    
557           if ( shape == null )
558           {
559             return allModels;
560           }
561    
562           NullArgumentException.check ( models );
563    
564           int  index = 0;
565    
566           for ( int  i = 0; i < allModels.length; i++ )
567           {
568             Model  model = allModels [ i ];
569    
570             if ( model.isActive ( )
571               && ShapeLib.intersects ( shape, model.getShape ( ) ) )
572             {
573               if ( index < models.length )
574               {
575                 models [ index ] = model;
576               }
577               else
578               {
579                 models = ( Model [ ] ) ArrayLib.append ( models, model );
580               }
581    
582               index++;
583             }
584           }
585    
586           if ( index < models.length )
587           {
588             models [ index ] = null;
589           }
590    
591           return models;
592         }
593    
594         private Damageable [ ]  getDamageables ( )
595         //////////////////////////////////////////////////////////////////////
596         {
597           return ( Damageable [ ] )
598             modelArrayKeeper.getArray ( Damageable.class );
599         }
600    
601         private Model  getModelClosest (
602           PointXY  pointXY,
603           Class    c,
604           Model    model )
605         //////////////////////////////////////////////////////////////////////
606         {
607           int  index = -1;
608    
609           double  closestDistance = Double.POSITIVE_INFINITY;
610    
611           Model [ ]  models = ( Model [ ] ) modelArrayKeeper.getArray ( );
612    
613           for ( int  i = 0; i < models.length; i++ )
614           {
615             Model  otherModel = models [ i ];
616    
617             if ( ( otherModel != model )
618               && otherModel.isActive ( )
619               && c.isInstance ( otherModel ) )
620             {
621               double  distance = ShapeLib.getCenter (
622                 otherModel.getShape ( ), center ).distanceXY ( pointXY );
623    
624               if ( distance < closestDistance )
625               {
626                 closestDistance = distance;
627    
628                 index = i;           
629               }
630             }
631           }
632    
633           if ( index > -1 )
634           {
635             return models [ index ];
636           }
637    
638           return null;
639         }
640    
641         //////////////////////////////////////////////////////////////////////
642         //////////////////////////////////////////////////////////////////////
643         }