1 #include "UnitManager.h"
2 //#include "LogFile.h"
3
sRAIGroup(int Index)4 sRAIGroup::sRAIGroup(int Index)
5 {
6 index = Index;
7 M = 0;
8 C = 0;
9 }
10
~sRAIGroup()11 sRAIGroup::~sRAIGroup()
12 {
13 for( map<int,EnemyInfo*>::iterator i=Enemies.begin(); i!=Enemies.end(); ++i )
14 {
15 i->second->attackGroups.erase(this);
16 }
17 }
18
cUnitManager(IAICallback * callback,cRAI * Global)19 cUnitManager::cUnitManager(IAICallback* callback, cRAI* Global)
20 {
21 cb=callback;
22 G=Global;
23 l=G->l;
24 GroupSize=0;
25 AttackOrders=false;
26 SLSize=0;
27 MaxGroupMSize=0;
28 memset(SL, 0, SCOUT_POSITON_LIST_SIZE);
29 memset(Group, 0, RAI_GROUP_SIZE);
30 }
31
UnitFinished(int unit,UnitInfo * U)32 void cUnitManager::UnitFinished(int unit,UnitInfo *U)
33 {
34 // *l<<" (t="<<U->udrBL->task<<")";
35 switch( U->udrBL->task )
36 {
37 case TASK_CONSTRUCT:
38 G->B->UBuilderFinished(unit,U);
39 break;
40 case TASK_ASSAULT:
41 {
42 UAssault.insert(cRAI::iupPair(unit,U));
43 UpdateGroupSize();
44 Assign(unit,U);
45 if( ActiveAttackOrders() )
46 SendattackGroups();
47 }
48 break;
49 case TASK_SCOUT:
50 {
51 UScout.insert(isPair(unit,sScoutUnitInfo()));
52 }
53 break;
54 case TASK_SUICIDE:
55 {
56 USuicide.insert(cRAI::iupPair(unit,U));
57 }
58 break;
59 case TASK_SUPPORT:
60 {
61 USupport.insert(unit);
62 }
63 break;
64 case TASK_TRANSPORT:
65 {
66 UTrans.insert(itPair(unit,sTransportUnitInfo(U->ud)));
67 }
68 break;
69 }
70 }
71
UnitDestroyed(int unit,UnitInfo * U)72 void cUnitManager::UnitDestroyed(int unit,UnitInfo *U)
73 {
74 // *l<<" (t="<<U->udrBL->task<<")";
75 switch( U->udrBL->task )
76 {
77 case TASK_CONSTRUCT:
78 G->B->UBuilderDestroyed(unit,U);
79 break;
80 case TASK_ASSAULT:
81 {
82 UAssault.erase(unit);
83 GroupRemoveUnit(unit,U);
84 }
85 break;
86 case TASK_SCOUT:
87 {
88 UScout.erase(unit);
89 }
90 break;
91 case TASK_SUICIDE:
92 {
93 USuicide.erase(unit);
94 }
95 break;
96 case TASK_SUPPORT:
97 {
98 USupport.erase(unit);
99 }
100 break;
101 case TASK_TRANSPORT:
102 {
103 UTrans.erase(unit);
104 }
105 break;
106 }
107 }
108
UnitIdle(int unit,UnitInfo * U)109 void cUnitManager::UnitIdle(int unit,UnitInfo *U)
110 {
111 // *l<<" (t="<<U->udrBL->task<<")";
112 switch( U->udrBL->task )
113 {
114 case TASK_CONSTRUCT:
115 G->B->UBuilderIdle(unit,U);
116 break;
117 case TASK_ASSAULT:
118 {
119 if( int(U->group->Enemies.size()) > 0 )
120 {
121 U->inCombat = true;
122 G->UpdateEventAdd(1,cb->GetCurrentFrame()+90,unit,U);
123 }
124 if( G->Enemies.empty() && (UAssault.size() > 50 || (G->UDH->BLMobileRadar->UDefActiveTemp == 0)) )
125 {
126 int num=0;
127 for( map<int,UnitInfo*>::iterator iU = U->group->Units.begin(); iU != U->group->Units.end(); ++iU )
128 {
129 if( cb->GetUnitPos(iU->first).distance2D(U->group->M->ScoutPoint) < 350.0f )
130 num++;
131 }
132 if( num >= 1+int(U->group->Units.size())/2 )
133 {
134 U->group->M->ScoutPoint = G->GetRandomPosition(U->area);
135 for( map<int,UnitInfo*>::iterator iU = U->group->Units.begin(); iU != U->group->Units.end(); ++iU )
136 G->UpdateEventAdd(1,0,iU->first,iU->second);
137 }
138
139 Command c;
140 if( cb->GetUnitPos(unit).distance2D(U->group->M->ScoutPoint) < 400.0f )
141 {
142 c.id = CMD_WAIT;
143 c.timeOut = cb->GetCurrentFrame()+900;
144 // G->UpdateEventAdd(1,cb->GetCurrentFrame()+300,unit,U);
145 }
146 else
147 {
148 c.id = CMD_MOVE;
149 c.params.push_back(U->group->M->ScoutPoint.x);
150 c.params.push_back(U->group->M->ScoutPoint.y);
151 c.params.push_back(U->group->M->ScoutPoint.z);
152 }
153 cb->GiveOrder(unit, &c);
154 }
155 else
156 {
157 Command c;
158 if( cb->GetUnitPos(unit).distance2D(U->group->M->RallyPoint) < 400.0f )
159 {
160 c.id = CMD_WAIT;
161 c.timeOut = cb->GetCurrentFrame()+900;
162 // G->UpdateEventAdd(1,cb->GetCurrentFrame()+900,unit,U);
163 }
164 else
165 {
166 c.id = CMD_MOVE;
167 c.params.push_back(U->group->M->RallyPoint.x);
168 c.params.push_back(U->group->M->RallyPoint.y);
169 c.params.push_back(U->group->M->RallyPoint.z);
170 }
171 cb->GiveOrder(unit, &c);
172 }
173 }
174 break;
175 case TASK_SCOUT:
176 {
177 sScoutUnitInfo *S = &UScout.find(unit)->second;
178 if( S->ScoutLocAssigned )
179 {
180 float3 Pos=cb->GetUnitPos(unit);
181 //const UnitDef* ud = cb->GetUnitDef(unit);
182
183 if( Pos.x - S->SL->position.x > 100 || Pos.x - S->SL->position.x < -100 || Pos.z - S->SL->position.z > 100 || Pos.z - S->SL->position.z < -100 )
184 {
185 Command c;
186 c.id = CMD_MOVE;
187 c.params.push_back(S->SL->position.x);
188 c.params.push_back(S->SL->position.y);
189 c.params.push_back(S->SL->position.z);
190 cb->GiveOrder(unit, &c);
191 }
192 return;
193 }
194 if( SLSize>0 )
195 {
196 S->SL= SL[0];
197 SL[0]=SL[--SLSize];
198 UnitIdle(unit,U);
199 return;
200 }
201 Command c;
202 c.id = CMD_MOVE;
203 float3 movePos=G->GetRandomPosition(U->area);
204 c.params.push_back(movePos.x);
205 c.params.push_back(movePos.y);
206 c.params.push_back(movePos.z);
207 cb->GiveOrder(unit, &c);
208 }
209 break;
210 case TASK_SUICIDE:
211 {
212 Command c;
213 if( int(G->Enemies.size()) > 0 && G->CM->GetClosestEnemy(cb->GetUnitPos(unit), U) >= 0 )
214 {
215 set<int> Targets;
216 for( map<int,EnemyInfo>::iterator iE=G->Enemies.begin(); iE!=G->Enemies.end(); ++iE )
217 if( G->TM->CanMoveToPos(U->area,G->CM->GetEnemyPosition(iE->first,&iE->second)) )
218 Targets.insert(iE->first);
219
220 int iT=rand()%int(Targets.size());
221 set<int>::iterator enemyID = Targets.begin();
222 for( int i=0; i<iT; i++,enemyID++ ) {}
223
224 U->inCombat=true;
225 U->enemyID = *enemyID;
226 U->E = &G->Enemies.find(U->enemyID)->second;
227 U->enemyEff = G->CM->CanAttack(U,U->E,G->CM->GetEnemyPosition(U->enemyID,U->E));
228
229 c.id = CMD_ATTACK;
230 c.params.push_back(U->enemyID);
231 cb->GiveOrder(unit,&c);
232 return;
233 }
234
235 c.id = CMD_MOVE;
236 float3 movePos=G->GetRandomPosition(U->area);
237 c.params.push_back(movePos.x);
238 c.params.push_back(movePos.y);
239 c.params.push_back(movePos.z);
240 cb->GiveOrder(unit, &c);
241 }
242 break;
243 case TASK_SUPPORT:
244 {
245 Command c;
246 c.id = CMD_WAIT;
247 cb->GiveOrder(unit, &c);
248 }
249 break;
250 case TASK_TRANSPORT:
251 {
252 sTransportUnitInfo *T = &UTrans.find(unit)->second;
253 if( T->AssistID == -1 )
254 {
255 Command c;
256 c.id = CMD_WAIT;
257 cb->GiveOrder(unit, &c);
258
259 G->UpdateEventAdd(1,cb->GetCurrentFrame()+450,unit,U);
260 }
261 }
262 break;
263 }
264 }
265
EnemyEnterLOS(int enemy,EnemyInfo * E)266 void cUnitManager::EnemyEnterLOS(int enemy,EnemyInfo *E)
267 {
268 EnemyEnterRadar(enemy,E);
269 }
270
EnemyEnterRadar(int enemy,EnemyInfo * E)271 void cUnitManager::EnemyEnterRadar(int enemy,EnemyInfo *E)
272 {
273 if( ActiveAttackOrders() )
274 SendattackGroups();
275 }
276
UnitMoveFailed(int unit,UnitInfo * U)277 bool cUnitManager::UnitMoveFailed(int unit, UnitInfo *U)
278 {
279 if( int(UTrans.size()) == 0 )
280 return false;
281 for( map<int,sTransportUnitInfo>::iterator iT=UTrans.begin(); iT!=UTrans.end(); ++iT )
282 {
283 if( iT->second.AssistID == -1 && iT->second.ud->transportMass >= U->ud->mass )
284 {
285 iT->second.AssistID=unit;
286 //return true;
287 }
288 }
289 return false;
290 }
291
UpdateGroupSize()292 void cUnitManager::UpdateGroupSize()
293 {
294 MaxGroupMSize=5+int(UAssault.size())/4;
295 }
296
ActiveAttackOrders()297 bool cUnitManager::ActiveAttackOrders()
298 {
299 if( int(G->Enemies.size()) == 0 )
300 {
301 // if( AttackOrders ) cb->SendTextMsg("Defending",5);
302 AttackOrders=false;
303 }
304 else if( int(UAssault.size()) >= 60 || (int(UAssault.size()) >= 6 && int(UAssault.size()) > 0.8*G->Enemies.size()) || G->UDH->BLBuilder->UDefActive == 0 )
305 {
306 // if( !AttackOrders ) cb->SendTextMsg("Attacking",5);
307 AttackOrders=true;
308 }
309 else if( int(UAssault.size()) <= 4 || (int(UAssault.size()) <= 40 && int(UAssault.size()) < 0.533*G->Enemies.size()) )
310 {
311 if( AttackOrders )
312 {
313 // cb->SendTextMsg("Defending",5);
314 AttackOrders=false;
315 for( int i=0; i<GroupSize; i++ ) // TEMP
316 {
317 set<int> deletion;
318 for( map<int,EnemyInfo*>::iterator iE = Group[i]->Enemies.begin(); iE != Group[i]->Enemies.end(); ++iE )
319 if( iE->second->baseThreatID == -1 )
320 deletion.insert(iE->first);
321 while( int(deletion.size()) > 0 )
322 {
323 GroupRemoveEnemy(*deletion.begin(),Group[i]->Enemies.find(*deletion.begin())->second,Group[i]);
324 deletion.erase(*deletion.begin());
325 }
326 }
327 }
328 }
329
330 return AttackOrders;
331 }
332
GroupAddUnit(int unit,UnitInfo * U,sRAIGroup * group)333 void cUnitManager::GroupAddUnit(int unit, UnitInfo* U, sRAIGroup* group)
334 {
335 group->Units.insert(cRAI::iupPair(unit,U));
336 U->group = group;
337 if( int(group->Enemies.size()) > 0 )
338 U->inCombat = true;
339
340 if( U->udrBL->task == TASK_ASSAULT )
341 {
342 if( group->M == 0 )
343 group->M = new sRAIGroupMilitary;
344 group->M->count++;
345 }
346 else if( U->udrBL->task == TASK_CONSTRUCT )
347 {
348 if( group->C == 0 )
349 group->C = new sRAIGroupConstruct;
350 group->C->count++;
351 }
352 }
353
GroupRemoveUnit(int unit,UnitInfo * U)354 void cUnitManager::GroupRemoveUnit(int unit, UnitInfo* U)
355 {
356 UpdateGroupSize();
357 U->group->Units.erase(unit);
358
359 if( U->udrBL->task == TASK_ASSAULT )
360 {
361 U->group->M->count--;
362 if( U->group->M->count == 0 )
363 {
364 delete U->group->M;
365 U->group->M = 0;
366 }
367 }
368 else if( U->udrBL->task == TASK_CONSTRUCT )
369 {
370 U->group->C->count--;
371 if( U->group->C->count == 0 )
372 {
373 delete U->group->C;
374 U->group->C = 0;
375 }
376 }
377
378 if( int(U->group->Units.size()) == 0 )
379 {
380 GroupSize--;
381 sRAIGroup* RGroup=Group[U->group->index];
382 Group[U->group->index]=Group[GroupSize];
383 Group[U->group->index]->index = U->group->index;
384 delete RGroup;
385 }
386 }
387
GroupAddEnemy(int enemy,EnemyInfo * E,sRAIGroup * group)388 void cUnitManager::GroupAddEnemy(int enemy, EnemyInfo *E, sRAIGroup* group)
389 {
390 if( !G->ValidateUnitList(&group->Units) )
391 return;
392
393 group->Enemies.insert(cRAI::iepPair(enemy,E));
394 E->attackGroups.insert(group);
395 if( group->Enemies.size() == 1 )
396 {
397 for( map<int,UnitInfo*>::iterator iU = group->Units.begin(); iU != group->Units.end(); ++iU )
398 {
399 iU->second->inCombat=true;
400 if( !G->IsHumanControled(iU->first,iU->second) )
401 G->UpdateEventAdd(1,-1,iU->first,iU->second);
402 }
403 }
404 }
405
GroupRemoveEnemy(int enemy,EnemyInfo * E,sRAIGroup * group)406 void cUnitManager::GroupRemoveEnemy(int enemy, EnemyInfo *E, sRAIGroup* group)
407 {
408 if( !G->ValidateUnitList(&group->Units) )
409 return;
410
411 group->Enemies.erase(enemy);
412 E->attackGroups.erase(group);
413 for( map<int,UnitInfo*>::iterator iU = group->Units.begin(); iU != group->Units.end(); ++iU )
414 {
415 if( iU->second->enemyID == enemy )
416 {
417 iU->second->enemyID = -1;
418 if( !G->IsHumanControled(iU->first,iU->second) )
419 G->UpdateEventAdd(1,0,iU->first,iU->second);
420 }
421 }
422 if( int(group->Enemies.size()) == 0 && int(G->EThreat.size()) == 0 && !ActiveAttackOrders() )
423 {
424 GroupResetRallyPoint(group);
425 group->M->ScoutPoint = G->GetRandomPosition(group->Units.begin()->second->area);
426 }
427 }
428
GroupResetRallyPoint(sRAIGroup * group)429 void cUnitManager::GroupResetRallyPoint(sRAIGroup* group)
430 {
431 float3 GPos = cb->GetUnitPos(group->Units.begin()->first);
432 UnitInfo* GU = group->Units.begin()->second;
433 int iBest=-1;
434 // UnitInfo* uBest;
435
436 G->ValidateUnitList(&G->UImmobile);
437 for(map<int,UnitInfo*>::iterator iU=G->UImmobile.begin(); iU!=G->UImmobile.end(); ++iU)
438 {
439 if( G->TM->CanMoveToPos(GU->area,cb->GetUnitPos(iU->first)) && GPos.distance2D(cb->GetUnitPos(iU->first)) < GPos.distance2D(cb->GetUnitPos(iBest)) )
440 {
441 iBest = iU->first;
442 // uBest = iU->second;
443 }
444 }
445
446 if( iBest != -1 )
447 group->M->RallyPoint = cb->GetUnitPos(iBest);
448 else
449 group->M->RallyPoint = GPos;
450 // G->DebugDrawShape(group->M->RallyPoint,100.0f,50,0,50,900);
451
452 if( group->M->RallyPoint.x < 8*cb->GetMapWidth() - group->M->RallyPoint.x )
453 group->M->RallyPoint.x -= 300;
454 else
455 group->M->RallyPoint.x += 300;
456 if( group->M->RallyPoint.z < 8*cb->GetMapHeight() - group->M->RallyPoint.z )
457 group->M->RallyPoint.z -= 300;
458 else
459 group->M->RallyPoint.z += 300;
460
461 group->M->RallyPoint.x += -250.0f + rand()%501;
462 group->M->RallyPoint.z += -250.0f + rand()%501;
463 G->CorrectPosition(group->M->RallyPoint);
464 // G->DebugDrawShape(group->M->RallyPoint,100.0f,25,0,50,900);
465
466 float3 pos = cb->ClosestBuildSite(GU->ud,group->M->RallyPoint,800,15);
467 if( pos.x <= 0 && pos.y <= 0 && pos.z <= 0 )
468 pos = cb->ClosestBuildSite(GU->ud,group->M->RallyPoint,800,3);
469 if( pos.x <= 0 && pos.y <= 0 && pos.z <= 0 )
470 group->M->RallyPoint = GPos;
471 else
472 group->M->RallyPoint = pos;
473 G->CorrectPosition(group->M->RallyPoint);
474
475 // G->DebugDrawShape(group->M->RallyPoint,100.0f,5,0,50,900);
476 }
477
Assign(int unit,UnitInfo * U)478 void cUnitManager::Assign(int unit,UnitInfo *U)
479 {
480 set<int> Grs;
481 for( int i=0; i<GroupSize; i++ )
482 {
483 if( U->area == Group[i]->Units.begin()->second->area &&
484 U->ud->canLoopbackAttack == Group[i]->Units.begin()->second->udr->ud->canLoopbackAttack &&
485 int(Group[i]->Units.size()) < MaxGroupMSize )
486 {
487 Grs.insert(i);
488 for(map<int,UnitInfo*>::iterator GM=Group[i]->Units.begin(); GM!=Group[i]->Units.end(); ++GM)
489 {
490 sRAIUnitDef* udr = GM->second->udr;
491 if( U->ud->speed > 1.5*udr->ud->speed || 1.5*U->ud->speed < udr->ud->speed )
492 {
493 Grs.erase(i);
494 break;
495 }
496 }
497 }
498 }
499
500 if( GroupSize == 25 && int(Grs.size()) == 0 )
501 {
502 *l<<"\nWARNING: Maximum number of groups reached";
503 Grs.insert(24);
504 }
505
506 if( int(Grs.size()) > 0 )
507 {
508 GroupAddUnit(unit,U,Group[*Grs.begin()]);
509 }
510 else
511 {
512 Group[GroupSize] = new sRAIGroup(GroupSize);
513 sRAIGroup* group = Group[GroupSize];
514 GroupSize++;
515
516 GroupAddUnit(unit,U,group);
517 group->M->ScoutPoint = G->GetRandomPosition(U->area);
518 GroupResetRallyPoint(group);
519 }
520 }
521
SendattackGroups()522 void cUnitManager::SendattackGroups()
523 {
524 for( int i=0; i<GroupSize; i++ ) {
525 if( (Group[i]->Enemies.size() == (size_t)0) &&
526 ( (Group[i]->Units.size() >= (size_t)4) ||
527 (G->UDH->BLBuilder->UDefActive == 0) ) ) {
528 // int enemyID = G->CM->GetClosestEnemy(cb->GetUnitPos(Group[i]->Units.begin()->first), Group[i]->Units.begin()->second);
529 // TODO: FIXME: implement me
530 }
531 }
532 }
533