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