1 // Copyright Hugh Perkins 2006, 2009
2 // hughperkins@gmail.com http://manageddreams.com
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 //  more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program in the file licence.txt; if not, write to the
16 // Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
17 // 1307 USA
18 // You can find the licence also on the web at:
19 // http://www.opensource.org/licenses/gpl-license.php
20 //
21 // ======================================================================================
22 //
23 
24 package hughai.packcoordinators;
25 
26 import java.util.*;
27 
28 import com.springrts.ai.*;
29 import com.springrts.ai.oo.clb.*;
30 
31 import hughai.*;
32 import hughai.utils.*;
33 import hughai.basictypes.*;
34 import hughai.unitdata.*;
35 
36 // this manages an attack pack, eg group of tanks
37 // specifically ,ensures they stay together, rather than streaming
38 // in theory
39 public class AttackPackCoordinator extends PackCoordinator
40 {
41    public float MaxPackDiameterOuterThreshold = 500;
42    public float MaxPackDiameterInnerThreshold = 300;
43    public float movetothreshold = 20;
44    public int MaxPackToConsider = 5;
45 
46    public float AttackDistance = 50;
47 
48    //	HashMap< Integer,UnitDef> UnitDefListByDeployedId;
49    TerrainPos targetpos;
50 
51    UnitController unitController;
52 
53    //public delegate void AttackPackDeadHandler();
54 
55    //public event AttackPackDeadHandler AttackPackDeadEvent;
56 
57    // can pass in pointer to a hashtable in another class if we want
58    // ie other class can directly modify our hashtable
AttackPackCoordinator( PlayerObjects playerObjects )59    public AttackPackCoordinator( PlayerObjects playerObjects )
60    {
61       super(playerObjects);
62       this.unitController = playerObjects.getUnitController();
63 
64       csai.registerGameListener( new GameListenerHandler() );
65       //		csai.TickEvent += new CSAI.TickHandler( this.Tick );
66    }
67 
68    // does NOT imply Activate()
69    @Override
SetTarget( TerrainPos newtarget )70    public void SetTarget( TerrainPos newtarget )
71    {
72       this.targetpos = newtarget;
73       //Activate();
74    }
75 
76    TerrainPos lasttargetpos = null;
77 
78    @Override
Recoordinate()79    void Recoordinate()
80    {
81       if( !activated )
82       {
83          return;
84       }
85 
86       // first we scan the list to find the 5 closest units to target, in order
87       // next we measure distance of first unit from 5th
88       // if distance is less than MaxPackDiameter, we move in
89       // otherwise 5th unit holds, and we move units to position of 5th unit
90       // pack must have at least 5 units, otherwise we call AttackPackDead event
91 
92       if( !CheckIfPackAlive() )
93       {
94          return;
95       }
96 
97       logfile.WriteLine( this.getClass().getSimpleName() + " recoordinate" );
98       int packsize = Math.min(MaxPackToConsider, unitsControlled.size());
99       UnitInfo[] closestunits = GetClosestUnits(targetpos, packsize);
100       if( closestunits.length == 0 ) {
101          return;
102       }
103       TerrainPos packheadpos = closestunits[0].pos;
104       TerrainPos packtailpos = closestunits[packsize - 1].pos;
105       double packsquareddiameter = packheadpos.GetSquaredDistance( packtailpos );
106       csai.DebugSay("packsize: " + packsize + " packdiameter: " + Math.sqrt(packsquareddiameter));
107       // logfile.WriteLine( "AttackPackCoordinator packheadpos " + packheadpos.toString() + " packtailpos " + packtailpos.toString() + " packsquareddiamter " + packsquareddiameter );
108       if (( regrouping && ( packsquareddiameter < (MaxPackDiameterInnerThreshold * MaxPackDiameterInnerThreshold) ) ) ||
109             (!regrouping && ( packsquareddiameter < (MaxPackDiameterOuterThreshold * MaxPackDiameterOuterThreshold)) ))
110       {
111          regrouping = false;
112          csai.DebugSay("attacking");
113          Attack( closestunits);
114       }
115       else
116       {
117          csai.DebugSay("regrouping");
118          regrouping = true;
119          Regroup(closestunits[(packsize / 2)].pos);
120       }
121    }
122 
123    //boolean attacking = false;
124    boolean regrouping = false;
125 
126    // placeholder...
GetAttackDistance(UnitInfo[]closestunits)127    void GetAttackDistance(UnitInfo[]closestunits)
128    {
129       // for( UnitInfo unitinfo : closestunits )
130       //    {
131       //       if( unitinfo.unitdef.
132       //   }
133    }
134 
Attack(UnitInfo[] closestunits)135    void Attack(UnitInfo[] closestunits)
136    {
137       //logfile.WriteLine( "AttackPackCoordinator attacking" );
138       //if( debugon )
139       // {
140       //      aicallback.SendTextMsg( "AttackPackCoordinator attacking", 0 );
141       // }
142 
143       // get vector from head unit to target
144       // pick point a bit behind target, backwards along vector
145       TerrainPos vectortargettohead =
146          targetpos.subtract( closestunits[0].pos );
147       vectortargettohead.Normalize();
148       //vectortargettohead = vectortargettohead * AttackDistance;
149       MoveTo( targetpos.add( vectortargettohead.multiply( AttackDistance ) ) );
150    }
151 
Regroup( TerrainPos regouppos )152    void Regroup( TerrainPos regouppos )
153    {
154       logfile.WriteLine( "AttackPackCoordinator regrouping to " + regouppos );
155       if( debugon )
156       {
157 //         csai.SendTextMsg( "AttackPackCoordinator regrouping to " + regouppos );
158       }
159       MoveTo( regouppos );
160    }
161 
MoveTo( TerrainPos pos )162    void MoveTo( TerrainPos pos )
163    {
164       // check whether we really need to do anything or if order is roughly same as last one
165       if( csai.DebugOn )
166       {
167          drawingUtils.DrawUnit("ARMSOLAR", pos, 0.0f, 50, aicallback.getSkirmishAI().getTeamId(), true, true);
168       }
169       if( restartedfrompause ||
170             pos.GetSquaredDistance( lasttargetpos )
171             > ( movetothreshold * movetothreshold ) )
172       {
173          for( Unit unit : unitsControlled )
174          {
175             //int deployedid = (int)de.Key;
176             //UnitDef unitdef = de.Value as UnitDef;
177             giveOrderWrapper.MoveTo(unit, pos );
178             //aicallback.GiveOrder( deployedid, new Command( Command.CMD_MOVE, pos.ToDoubleArray() ) );
179          }
180          restartedfrompause = false;
181          lasttargetpos = pos;
182       }
183    }
184 
CheckIfPackAlive()185    boolean CheckIfPackAlive()
186    {
187       //if( UnitDefListByDeployedId.size() < MinPackSize )
188       // {
189       //     if( AttackPackDeadEvent != null )
190       //   {
191       //     AttackPackDeadEvent();
192       // }
193       //     return false;
194       // }
195       return true;
196    }
197 
198    class UnitInfo
199    {
200       public Unit unit;
201       public TerrainPos pos;
202       public UnitDef unitdef;
203       public double squareddistance;
UnitInfo()204       public UnitInfo(){}
UnitInfo( Unit unit, TerrainPos pos, UnitDef unitdef, double squareddistance )205       public UnitInfo( Unit unit, TerrainPos pos, UnitDef unitdef, double squareddistance )
206       {
207          this.unit = unit;
208          this.pos = pos;
209          this.unitdef = unitdef;
210          this.squareddistance = squareddistance;
211       }
212    }
213 
GetClosestUnits( TerrainPos targetpos, int numclosestunits )214    UnitInfo[] GetClosestUnits( TerrainPos targetpos, int numclosestunits )
215    {
216       UnitInfo[] closestunits = new UnitInfo[ numclosestunits ];
217       double worsttopfivesquareddistance = 0; // got to get better than this to enter the list
218       int numclosestunitsfound = 0;
219       for( Unit unit : unitsControlled ) {
220          TerrainPos unitpos = unitController.getPos( unit );
221          UnitDef unitdef = unit.getDef();
222          double unitsquareddistance = unitpos.GetSquaredDistance( targetpos );
223          if( numclosestunitsfound < numclosestunits )
224          {
225             UnitInfo unitinfo = new UnitInfo( unit, unitpos, unitdef, unitsquareddistance );
226             InsertIntoArray( closestunits, unitinfo, numclosestunitsfound );
227             numclosestunitsfound++;
228             worsttopfivesquareddistance = closestunits[ numclosestunitsfound - 1 ].squareddistance;
229          }
230          else if( unitsquareddistance < worsttopfivesquareddistance )
231          {
232             UnitInfo unitinfo = new UnitInfo( unit, unitpos, unitdef, unitsquareddistance );
233             InsertIntoArray( closestunits, unitinfo, numclosestunits );
234             worsttopfivesquareddistance = closestunits[ numclosestunits - 1 ].squareddistance;
235          }
236       }
237       return closestunits;
238    }
239 
240    // we add it to the bottom, then bubble it up
InsertIntoArray( UnitInfo[] closestunits, UnitInfo newunit, int numexistingunits )241    void InsertIntoArray( UnitInfo[] closestunits, UnitInfo newunit, int numexistingunits )
242    {
243       if( numexistingunits < closestunits.length )
244       {
245          closestunits[ numexistingunits ] = newunit;
246          numexistingunits++;
247       }
248       else
249       {
250          closestunits[ numexistingunits - 1 ] = newunit;
251       }
252       // bubble new unit up
253       for( int i = numexistingunits - 2; i >= 0; i-- )
254       {
255          if( closestunits[ i ].squareddistance > closestunits[ i + 1 ].squareddistance )
256          {
257             UnitInfo swap = closestunits[ i ];
258             closestunits[ i ] = closestunits[ i + 1 ];
259             closestunits[ i + 1 ] = swap;
260          }
261       }
262       // debug;
263       //  logfile.WriteLine( "AttackPackCoordinator.InsertIntoArray");
264       //  for( int i = 0; i < numexistingunits; i++ )
265       //   {
266       //       logfile.WriteLine(i + ": " + closestunits[ i ].squareddistance );
267       //   }
268    }
269 
270    class GameListenerHandler extends GameAdapter {
271       //      int ticks = 0;
272       @Override
Tick( int frame )273       public void Tick( int frame )
274       {
275          //         ticks++;
276          //         if( ticks >= 30 )
277          //         {
278          Recoordinate();
279 
280          //            ticks = 0;
281          //         }
282       }
283    }
284 }
285 
286