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