1 // -------------------------------------------------------------------------
2 // AAI
3 //
4 // A skirmish AI for the Spring engine.
5 // Copyright Alexander Seizinger
6 //
7 // Released under GPL license: see LICENSE.html for more information.
8 // -------------------------------------------------------------------------
9 
10 #include "AAI.h"
11 #include "AAIBrain.h"
12 #include "AAIBuildTable.h"
13 #include "AAIExecute.h"
14 #include "AAIUnitTable.h"
15 #include "AAIConfig.h"
16 #include "AAIMap.h"
17 #include "AAIGroup.h"
18 #include "AAISector.h"
19 
20 #include "LegacyCpp/UnitDef.h"
21 using namespace springLegacyAI;
22 
AAIBrain(AAI * ai)23 AAIBrain::AAIBrain(AAI *ai)
24 {
25 	this->ai = ai;
26 	freeBaseSpots = false;
27 	expandable = true;
28 
29 	max_distance = ai->Getmap()->xSectors + ai->Getmap()->ySectors - 2;
30 	sectors.resize(max_distance);
31 
32 	base_center = ZeroVector;
33 
34 	max_combat_units_spotted.resize(AAIBuildTable::ass_categories, 0);
35 	attacked_by.resize(AAIBuildTable::combat_categories, 0);
36 	defence_power_vs.resize(AAIBuildTable::ass_categories, 0);
37 
38 	enemy_pressure_estimation = 0;
39 }
40 
~AAIBrain(void)41 AAIBrain::~AAIBrain(void)
42 {
43 }
44 
45 
GetAttackDest(bool land,bool water)46 AAISector* AAIBrain::GetAttackDest(bool land, bool water)
47 {
48 	float best_rating = 0.0f, my_rating = 0.0f;
49 	AAISector *dest = 0, *sector;
50 
51 	//int side = ai->Getside()-1;
52 
53 	float ground =  1.0f;
54 	float air = 1.0f;
55 	float hover = 1.0f;
56 	float sea = 1.0f;
57 	float submarine = 1.0f;
58 
59 	float def_power;
60 
61 	// TODO: improve destination sector selection
62 	for(int x = 0; x < ai->Getmap()->xSectors; ++x)
63 	{
64 		for(int y = 0; y < ai->Getmap()->ySectors; ++y)
65 		{
66 			sector = &ai->Getmap()->sector[x][y];
67 
68 			if(sector->distance_to_base == 0 || sector->enemy_structures == 0)
69 					my_rating = 0;
70 			else
71 			{
72 				if(land && sector->water_ratio < 0.4)
73 				{
74 					def_power = sector->GetEnemyDefencePower(ground, air, hover, sea, submarine);
75 
76 					if(def_power)
77 					my_rating = sector->enemy_structures / sector->GetEnemyDefencePower(ground, air, hover, sea, submarine);
78 
79 					my_rating = sector->enemy_structures / (2 * sector->GetEnemyDefencePower(ground, air, hover, sea, submarine) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f) + 1);
80 					my_rating /= (8 + sector->distance_to_base);
81 				}
82 				else if(water && sector->water_ratio > 0.6)
83 				{
84 					my_rating = sector->enemy_structures / (2 * sector->GetEnemyDefencePower(ground, air, hover, sea, submarine) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f) + 1);
85 					my_rating /= (8 + sector->distance_to_base);
86 				}
87 			}
88 
89 			if(my_rating > best_rating)
90 			{
91 				dest = sector;
92 				best_rating = my_rating;
93 			}
94 		}
95 	}
96 
97 	return dest;
98 }
99 
GetNextAttackDest(AAISector * current_sector,bool land,bool water)100 AAISector* AAIBrain::GetNextAttackDest(AAISector *current_sector, bool land, bool water)
101 {
102 	float best_rating = 0, my_rating, dist;
103 	AAISector *dest = 0, *sector;
104 
105 	//int side = ai->Getside()-1;
106 
107 	float ground = 1.0f;
108 	float air = 1.0f;
109 	float hover = 1.0f;
110 	float sea = 1.0f;
111 	float submarine = 1.0f;
112 
113 	// TODO: improve destination sector selection
114 	for(int x = 0; x < ai->Getmap()->xSectors; x++)
115 	{
116 		for(int y = 0; y < ai->Getmap()->ySectors; y++)
117 		{
118 			sector = &ai->Getmap()->sector[x][y];
119 
120 			if(sector->distance_to_base == 0 || sector->enemy_structures < 0.001f)
121 					my_rating = 0;
122 			else
123 			{
124 				if(land && sector->water_ratio < 0.35)
125 				{
126 					dist = sqrt( pow((float)sector->x - current_sector->x, 2) + pow((float)sector->y - current_sector->y , 2) );
127 
128 					my_rating = 1.0f / (1.0f + pow(sector->GetEnemyDefencePower(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
129 
130 				}
131 				else if(water && sector->water_ratio > 0.65)
132 				{
133 					dist = sqrt( pow((float)(sector->x - current_sector->x), 2) + pow((float)(sector->y - current_sector->y), 2) );
134 
135 					my_rating = 1.0f / (1.0f + pow(sector->GetEnemyDefencePower(ground, air, hover, sea, submarine), 2.0f) + pow(sector->GetLostUnits(ground, air, hover, sea, submarine) + 1, 1.5f));
136 					my_rating /= (1.0f + dist);
137 				}
138 				else
139 					my_rating = 0;
140 			}
141 
142 			if(my_rating > best_rating)
143 			{
144 				dest = sector;
145 				best_rating = my_rating;
146 			}
147 		}
148 	}
149 
150 	return dest;
151 }
152 
GetNewScoutDest(float3 * dest,int scout)153 void AAIBrain::GetNewScoutDest(float3 *dest, int scout)
154 {
155 	*dest = ZeroVector;
156 
157 	// TODO: take scouts pos into account
158 	float my_rating, best_rating = 0;
159 	AAISector *scout_sector = 0, *sector;
160 
161 	const UnitDef *def = ai->Getcb()->GetUnitDef(scout);
162 	unsigned int scout_movement_type = ai->Getbt()->units_static[def->id].movement_type;
163 
164 	float3 pos = ai->Getcb()->GetUnitPos(scout);
165 
166 	// get continent
167 	int continent = ai->Getmap()->GetSmartContinentID(&pos, scout_movement_type);//ai->Getmap()->GetContinentID(&pos);
168 
169 	for(int x = 0; x < ai->Getmap()->xSectors; ++x)
170 	{
171 		for(int y = 0; y < ai->Getmap()->ySectors; ++y)
172 		{
173 			sector = &ai->Getmap()->sector[x][y];
174 
175 			if(sector->distance_to_base > 0 && scout_movement_type & sector->allowed_movement_types)
176 			{
177 				if(enemy_pressure_estimation > 0.01f && sector->distance_to_base < 2)
178 					my_rating = sector->importance_this_game * sector->last_scout * (1.0f + sector->enemy_combat_units[5]);
179 				else
180 					my_rating = sector->importance_this_game * sector->last_scout;
181 
182 				++sector->last_scout;
183 
184 				if(my_rating > best_rating)
185 				{
186 					// possible scout dest, try to find pos in sector
187 					pos = ZeroVector;
188 
189 					sector->GetMovePosOnContinent(&pos, scout_movement_type, continent);
190 
191 					if(pos.x > 0)
192 					{
193 						best_rating = my_rating;
194 						scout_sector = sector;
195 						*dest = pos;
196 					}
197 				}
198 			}
199 		}
200 	}
201 
202 	// set dest sector as visited
203 	if(dest->x > 0)
204 		scout_sector->last_scout = 1;
205 }
206 
MetalForConstr(int unit,int workertime)207 bool AAIBrain::MetalForConstr(int unit, int workertime)
208 {
209 
210 	int metal = (ai->Getbt()->GetUnitDef(unit).buildTime/workertime) * (ai->Getcb()->GetMetalIncome()-(ai->Getcb()->GetMetalUsage()) + ai->Getcb()->GetMetal());
211 	int total_cost = ai->Getbt()->GetUnitDef(unit).metalCost;
212 
213 	if(metal > total_cost)
214 		return true;
215 
216 	return false;
217 }
218 
EnergyForConstr(int unit,int)219 bool AAIBrain::EnergyForConstr(int unit, int /*wokertime*/)
220 {
221 
222 	// check energy
223 //	int energy =  ai->Getbt()->unitList[unit-1]->buildTime * (ai->Getcb()->GetEnergyIncome()-(ai->Getcb()->GetEnergyUsage()/2));
224 
225 	// TODO: FIXME: add code here
226 
227 	return true;
228 }
229 
RessourcesForConstr(int,int)230 bool AAIBrain::RessourcesForConstr(int /*unit*/, int /*wokertime*/)
231 {
232 	// check metal and energy
233 	/*if(MetalForConstr(unit) && EnergyForConstr(unit))
234 			return true;
235 
236 	return false;*/
237 	return true;
238 }
239 
AddSector(AAISector * sector)240 void AAIBrain::AddSector(AAISector *sector)
241 {
242 	sectors[0].push_back(sector);
243 
244 	sector->SetBase(true);
245 
246 	// update base land/water ratio
247 	baseLandRatio = 0;
248 	baseWaterRatio = 0;
249 
250 	for(list<AAISector*>::iterator s = sectors[0].begin(); s != sectors[0].end(); ++s)
251 	{
252 		baseLandRatio += (*s)->GetFlatRatio();
253 		baseWaterRatio += (*s)->GetWaterRatio();
254 	}
255 
256 	baseLandRatio /= (float)sectors[0].size();
257 	baseWaterRatio /= (float)sectors[0].size();
258 }
259 
RemoveSector(AAISector * sector)260 void AAIBrain::RemoveSector(AAISector *sector)
261 {
262 	sectors[0].remove(sector);
263 
264 	sector->SetBase(false);
265 
266 	// update base land/water ratio
267 	baseLandRatio = 0;
268 	baseWaterRatio = 0;
269 
270 	if(sectors[0].size() > 0)
271 	{
272 		for(list<AAISector*>::iterator s = sectors[0].begin(); s != sectors[0].end(); ++s)
273 		{
274 			baseLandRatio += (*s)->GetFlatRatio();
275 			baseWaterRatio += (*s)->GetWaterRatio();
276 		}
277 
278 		baseLandRatio /= (float)sectors[0].size();
279 		baseWaterRatio /= (float)sectors[0].size();
280 	}
281 }
282 
283 
DefendCommander(int)284 void AAIBrain::DefendCommander(int /*attacker*/)
285 {
286 //	float3 pos = ai->Getcb()->GetUnitPos(ai->Getut()->cmdr);
287 	//float importance = 120;
288 	Command c;
289 
290 	// evacuate cmdr
291 	// TODO: FIXME: check/fix?/implement me?
292 	/*if(ai->cmdr->task != BUILDING)
293 	{
294 		AAISector *sector = GetSafestSector();
295 
296 		if(sector != 0)
297 		{
298 			pos = sector->GetCenter();
299 
300 			if(pos.x > 0 && pos.z > 0)
301 			{
302 				pos.y = ai->Getcb()->GetElevation(pos.x, pos.z);
303 				ai->Getexecute()->MoveUnitTo(ai->cmdr->unit_id, &pos);
304 			}
305 		}
306 	}*/
307 }
308 
UpdateBaseCenter()309 void AAIBrain::UpdateBaseCenter()
310 {
311 	base_center = ZeroVector;
312 
313 	for(list<AAISector*>::iterator sector = sectors[0].begin(); sector != sectors[0].end(); ++sector)
314 	{
315 		base_center.x += (0.5 + (*sector)->x) * ai->Getmap()->xSectorSize;
316 		base_center.z += (0.5 + (*sector)->y) * ai->Getmap()->ySectorSize;
317 	}
318 
319 	base_center.x /= sectors[0].size();
320 	base_center.z /= sectors[0].size();
321 }
322 
UpdateNeighbouringSectors()323 void AAIBrain::UpdateNeighbouringSectors()
324 {
325 	int x,y,neighbours;
326 
327 	// delete old values
328 	for(x = 0; x < ai->Getmap()->xSectors; ++x)
329 	{
330 		for(y = 0; y < ai->Getmap()->ySectors; ++y)
331 		{
332 			if(ai->Getmap()->sector[x][y].distance_to_base > 0)
333 				ai->Getmap()->sector[x][y].distance_to_base = -1;
334 		}
335 	}
336 
337 	for(int i = 1; i < max_distance; ++i)
338 	{
339 		// delete old sectors
340 		sectors[i].clear();
341 		neighbours = 0;
342 
343 		for(list<AAISector*>::iterator sector = sectors[i-1].begin(); sector != sectors[i-1].end(); ++sector)
344 		{
345 			x = (*sector)->x;
346 			y = (*sector)->y;
347 
348 			// check left neighbour
349 			if(x > 0 && ai->Getmap()->sector[x-1][y].distance_to_base == -1)
350 			{
351 				ai->Getmap()->sector[x-1][y].distance_to_base = i;
352 				sectors[i].push_back(&ai->Getmap()->sector[x-1][y]);
353 				++neighbours;
354 			}
355 			// check right neighbour
356 			if(x < (ai->Getmap()->xSectors - 1) && ai->Getmap()->sector[x+1][y].distance_to_base == -1)
357 			{
358 				ai->Getmap()->sector[x+1][y].distance_to_base = i;
359 				sectors[i].push_back(&ai->Getmap()->sector[x+1][y]);
360 				++neighbours;
361 			}
362 			// check upper neighbour
363 			if(y > 0 && ai->Getmap()->sector[x][y-1].distance_to_base == -1)
364 			{
365 				ai->Getmap()->sector[x][y-1].distance_to_base = i;
366 				sectors[i].push_back(&ai->Getmap()->sector[x][y-1]);
367 				++neighbours;
368 			}
369 			// check lower neighbour
370 			if(y < (ai->Getmap()->ySectors - 1) && ai->Getmap()->sector[x][y+1].distance_to_base == -1)
371 			{
372 				ai->Getmap()->sector[x][y+1].distance_to_base = i;
373 				sectors[i].push_back(&ai->Getmap()->sector[x][y+1]);
374 				++neighbours;
375 			}
376 
377 			if(i == 1 && !neighbours)
378 				(*sector)->interior = true;
379 		}
380 	}
381 
382 	//ai->Log("Base has now %i direct neighbouring sectors\n", sectors[1].size());
383 }
384 
SectorInList(list<AAISector * > mylist,AAISector * sector)385 bool AAIBrain::SectorInList(list<AAISector*> mylist, AAISector *sector)
386 {
387 	// check if sector already added to list
388 	for(list<AAISector*>::iterator t = mylist.begin(); t != mylist.end(); ++t)
389 	{
390 		if(*t == sector)
391 			return true;
392 	}
393 	return false;
394 }
395 
GetBaseBuildspaceRatio(unsigned int building_move_type)396 float AAIBrain::GetBaseBuildspaceRatio(unsigned int building_move_type)
397 {
398 	if(building_move_type & MOVE_TYPE_STATIC_LAND)
399 	{
400 		if(baseLandRatio > 0.1f)
401 			return baseLandRatio;
402 		else
403 			return 0;
404 	}
405 	else if(building_move_type & MOVE_TYPE_STATIC_WATER)
406 	{
407 		if(baseWaterRatio > 0.1f)
408 			return baseWaterRatio;
409 		else
410 			return 0;
411 	}
412 	else
413 		return 1.0f;
414 }
415 
CommanderAllowedForConstructionAt(AAISector * sector,float3 * pos)416 bool AAIBrain::CommanderAllowedForConstructionAt(AAISector *sector, float3 *pos)
417 {
418 	// commander is always allowed in base
419 	if(sector->distance_to_base <= 0)
420 		return true;
421 	// allow construction close to base for small bases
422 	else if(sectors[0].size() < 3 && sector->distance_to_base <= 1)
423 		return true;
424 	// allow construction on islands close to base on water maps
425 	else if(ai->Getmap()->map_type == WATER_MAP && ai->Getcb()->GetElevation(pos->x, pos->z) >= 0 && sector->distance_to_base <= 3)
426 		return true;
427 	else
428 		return false;
429 }
430 
MexConstructionAllowedInSector(AAISector * sector)431 bool AAIBrain::MexConstructionAllowedInSector(AAISector *sector)
432 {
433 	return sector->freeMetalSpots && IsSafeSector(sector) && (ai->Getmap()->team_sector_map[sector->x][sector->y] == -1 || ai->Getmap()->team_sector_map[sector->x][sector->y] == ai->Getcb()->GetMyAllyTeam());
434 }
435 
ExpandBase(SectorType sectorType)436 bool AAIBrain::ExpandBase(SectorType sectorType)
437 {
438 	if(sectors[0].size() >= cfg->MAX_BASE_SIZE)
439 		return false;
440 
441 	// now targets should contain all neighbouring sectors that are not currently part of the base
442 	// only once; select the sector with most metalspots and least danger
443 	AAISector *best_sector = NULL;
444 	float best_rating  = 0, my_rating;
445 	int spots;
446 	float dist;
447 
448 	int max_search_dist = 1;
449 
450 	// if aai is looking for a water sector to expand into ocean, allow greater search_dist
451 	if(sectorType == WATER_SECTOR &&  baseWaterRatio < 0.1)
452 		max_search_dist = 3;
453 
454 	for(int search_dist = 1; search_dist <= max_search_dist; ++search_dist)
455 	{
456 		for(list<AAISector*>::iterator t = sectors[search_dist].begin(); t != sectors[search_dist].end(); ++t)
457 		{
458 			// dont expand if enemy structures in sector && check for allied buildings
459 			if(IsSafeSector(*t) && (*t)->allied_structures < 3 && ai->Getmap()->team_sector_map[(*t)->x][(*t)->y] == -1)
460 			{
461 				// rate current sector
462 				spots = (*t)->GetNumberOfMetalSpots();
463 
464 				my_rating = 1.0f + (float)spots;
465 
466 				if(sectorType == LAND_SECTOR)
467 					// prefer flat sectors without water
468 					my_rating += ((*t)->flat_ratio - (*t)->water_ratio) * 16.0f;
469 				else if(sectorType == WATER_SECTOR)
470 				{
471 					// check for continent size (to prevent aai to expand into little ponds instead of big ocean)
472 					if((*t)->water_ratio > 0.1 &&  (*t)->ConnectedToOcean())
473 						my_rating += 8.0f * (*t)->water_ratio;
474 					else
475 						my_rating = 0;
476 				}
477 				else // LAND_WATER_SECTOR
478 					my_rating += ((*t)->flat_ratio + (*t)->water_ratio) * 8.0f;
479 
480 				// minmize distance between sectors
481 				dist = 0.1f;
482 
483 				for(list<AAISector*>::iterator sector = sectors[0].begin(); sector != sectors[0].end(); ++sector) {
484 					dist += fastmath::apxsqrt( ((*t)->x - (*sector)->x) * ((*t)->x - (*sector)->x) + ((*t)->y - (*sector)->y) * ((*t)->y - (*sector)->y) );
485 				}
486 
487 				float3 center = (*t)->GetCenter();
488 				my_rating /= (dist * fastmath::apxsqrt(ai->Getmap()->GetEdgeDistance( &center )) );
489 
490 				// choose higher rated sector
491 				if(my_rating > best_rating)
492 				{
493 					best_rating = my_rating;
494 					best_sector = *t;
495 				}
496 			}
497 		}
498 	}
499 
500 	if(best_sector)
501 	{
502 		// add this sector to base
503 		AddSector(best_sector);
504 
505 		// debug purposes:
506 		if(sectorType == LAND_SECTOR)
507 		{
508 			ai->Log("\nAdding land sector %i,%i to base; base size: " _STPF_, best_sector->x, best_sector->y, sectors[0].size());
509 			ai->Log("\nNew land : water ratio within base: %f : %f\n\n", baseLandRatio, baseWaterRatio);
510 		}
511 		else
512 		{
513 			ai->Log("\nAdding water sector %i,%i to base; base size: " _STPF_, best_sector->x, best_sector->y, sectors[0].size());
514 			ai->Log("\nNew land : water ratio within base: %f : %f\n\n", baseLandRatio, baseWaterRatio);
515 		}
516 
517 		// update neighbouring sectors
518 		UpdateNeighbouringSectors();
519 		UpdateBaseCenter();
520 
521 		// check if further expansion possible
522 		if(sectors[0].size() == cfg->MAX_BASE_SIZE)
523 			expandable = false;
524 
525 		freeBaseSpots = true;
526 
527 		return true;
528 	}
529 
530 
531 	return false;
532 }
533 
UpdateMaxCombatUnitsSpotted(vector<unsigned short> & units_spotted)534 void AAIBrain::UpdateMaxCombatUnitsSpotted(vector<unsigned short>& units_spotted)
535 {
536 	for(int i = 0; i < AAIBuildTable::ass_categories; ++i)
537 	{
538 		// decrease old values
539 		max_combat_units_spotted[i] *= 0.996f;
540 
541 		// check for new max values
542 		if((float)units_spotted[i] > max_combat_units_spotted[i])
543 			max_combat_units_spotted[i] = (float)units_spotted[i];
544 	}
545 }
546 
UpdateAttackedByValues()547 void AAIBrain::UpdateAttackedByValues()
548 {
549 	for(int i = 0; i < AAIBuildTable::ass_categories; ++i)
550 	{
551 		attacked_by[i] *= 0.96f;
552 	}
553 }
554 
AttackedBy(int combat_category_id)555 void AAIBrain::AttackedBy(int combat_category_id)
556 {
557 	// update counter for current game
558 	attacked_by[combat_category_id] += 1;
559 
560 	// update counter for memory dependent on playtime
561 	ai->Getbt()->attacked_by_category_current[GetGamePeriod()][combat_category_id] += 1.0f;
562 }
563 
UpdateDefenceCapabilities()564 void AAIBrain::UpdateDefenceCapabilities()
565 {
566 	for(int i = 0; i < ai->Getbt()->assault_categories.size(); ++i)
567 		defence_power_vs[i] = 0;
568 	fill(defence_power_vs.begin(), defence_power_vs.end(), 0.0f);
569 
570 	if(cfg->AIR_ONLY_MOD)
571 	{
572 		for(list<UnitCategory>::iterator category = ai->Getbt()->assault_categories.begin(); category != ai->Getbt()->assault_categories.end(); ++category)
573 		{
574 			for(list<AAIGroup*>::iterator group = ai->Getgroup_list()[*category].begin(); group != ai->Getgroup_list()[*category].end(); ++group)
575 			{
576 				defence_power_vs[0] += (*group)->GetCombatPowerVsCategory(0);
577 				defence_power_vs[1] += (*group)->GetCombatPowerVsCategory(1);
578 				defence_power_vs[2] += (*group)->GetCombatPowerVsCategory(2);
579 				defence_power_vs[3] += (*group)->GetCombatPowerVsCategory(3);
580 			}
581 		}
582 	}
583 	else
584 	{
585 		// anti air power
586 		for(list<UnitCategory>::iterator category = ai->Getbt()->assault_categories.begin(); category != ai->Getbt()->assault_categories.end(); ++category)
587 		{
588 			for(list<AAIGroup*>::iterator group = ai->Getgroup_list()[*category].begin(); group != ai->Getgroup_list()[*category].end(); ++group)
589 			{
590 				if((*group)->group_unit_type == ASSAULT_UNIT)
591 				{
592 					if((*group)->category == GROUND_ASSAULT)
593 					{
594 						defence_power_vs[0] += (*group)->GetCombatPowerVsCategory(0);
595 						defence_power_vs[2] += (*group)->GetCombatPowerVsCategory(2);
596 					}
597 					else if((*group)->category == HOVER_ASSAULT)
598 					{
599 						defence_power_vs[0] += (*group)->GetCombatPowerVsCategory(0);
600 						defence_power_vs[2] += (*group)->GetCombatPowerVsCategory(2);
601 						defence_power_vs[3] += (*group)->GetCombatPowerVsCategory(3);
602 					}
603 					else if((*group)->category == SEA_ASSAULT)
604 					{
605 						defence_power_vs[2] += (*group)->GetCombatPowerVsCategory(2);
606 						defence_power_vs[3] += (*group)->GetCombatPowerVsCategory(3);
607 						defence_power_vs[4] += (*group)->GetCombatPowerVsCategory(4);
608 					}
609 					else if((*group)->category == SUBMARINE_ASSAULT)
610 					{
611 						defence_power_vs[3] += (*group)->GetCombatPowerVsCategory(3);
612 						defence_power_vs[4] += (*group)->GetCombatPowerVsCategory(4);
613 					}
614 				}
615 				else if((*group)->group_unit_type == ANTI_AIR_UNIT)
616 					defence_power_vs[1] += (*group)->GetCombatPowerVsCategory(1);
617 			}
618 		}
619 	}
620 
621 	// debug
622 	/*ai->Log("Defence capabilities:\n");
623 
624 	for(int i = 0; i < ai->Getbt()->assault_categories.size(); ++i)
625 		ai->Log("%-20s %f\n" , ai->Getbt()->GetCategoryString2(ai->Getbt()->GetAssaultCategoryOfID(i)),defence_power_vs[i]);
626 	*/
627 }
628 
AddDefenceCapabilities(int def_id,UnitCategory category)629 void AAIBrain::AddDefenceCapabilities(int def_id, UnitCategory category)
630 {
631 	if(cfg->AIR_ONLY_MOD)
632 	{
633 		defence_power_vs[0] += ai->Getbt()->units_static[def_id].efficiency[0];
634 		defence_power_vs[1] += ai->Getbt()->units_static[def_id].efficiency[1];
635 		defence_power_vs[2] += ai->Getbt()->units_static[def_id].efficiency[2];
636 		defence_power_vs[3] += ai->Getbt()->units_static[def_id].efficiency[3];
637 	}
638 	else
639 	{
640 		if(ai->Getbt()->GetUnitType(def_id) == ASSAULT_UNIT)
641 		{
642 			if(category == GROUND_ASSAULT)
643 			{
644 				defence_power_vs[0] += ai->Getbt()->units_static[def_id].efficiency[0];
645 				defence_power_vs[2] += ai->Getbt()->units_static[def_id].efficiency[2];
646 			}
647 			else if(category == HOVER_ASSAULT)
648 			{
649 				defence_power_vs[0] += ai->Getbt()->units_static[def_id].efficiency[0];
650 				defence_power_vs[2] += ai->Getbt()->units_static[def_id].efficiency[2];
651 				defence_power_vs[3] += ai->Getbt()->units_static[def_id].efficiency[3];
652 			}
653 			else if(category == SEA_ASSAULT)
654 			{
655 				defence_power_vs[2] += ai->Getbt()->units_static[def_id].efficiency[2];
656 				defence_power_vs[3] += ai->Getbt()->units_static[def_id].efficiency[3];
657 				defence_power_vs[4] += ai->Getbt()->units_static[def_id].efficiency[4];
658 			}
659 			else if(category == SUBMARINE_ASSAULT)
660 			{
661 				defence_power_vs[3] += ai->Getbt()->units_static[def_id].efficiency[3];
662 				defence_power_vs[4] += ai->Getbt()->units_static[def_id].efficiency[4];
663 			}
664 		}
665 		else if(ai->Getbt()->GetUnitType(def_id) == ANTI_AIR_UNIT)
666 			defence_power_vs[1] += ai->Getbt()->units_static[def_id].efficiency[1];
667 	}
668 }
669 
670 /*
671 void AAIBrain::SubtractDefenceCapabilities(int def_id, UnitCategory category)
672 {
673 }
674 */
675 
Affordable()676 float AAIBrain::Affordable()
677 {
678 	return 25.0f /(ai->Getcb()->GetMetalIncome() + 5.0f);
679 }
680 
BuildUnits()681 void AAIBrain::BuildUnits()
682 {
683 	//int side = ai->Getside()-1;
684 	bool urgent = false;
685 	int k;
686 	unsigned int allowed_move_type = 0;
687 
688 	float cost = 1.0f + Affordable()/12.0f;
689 
690 	float ground_eff = 0;
691 	float air_eff = 0;
692 	float hover_eff = 0;
693 	float sea_eff = 0;
694 	float stat_eff = 0;
695 	float submarine_eff = 0;
696 
697 	int anti_air_urgency;
698 	int anti_sea_urgency;
699 	int anti_ground_urgency;
700 	int anti_hover_urgency;
701 	int anti_submarine_urgency;
702 
703 	// determine elapsed game time
704 	int game_period = GetGamePeriod();
705 
706 	float ground = GetAttacksBy(0, game_period);
707 	float air = GetAttacksBy(0, game_period);
708 	float hover = GetAttacksBy(0, game_period);
709 	float sea = GetAttacksBy(0, game_period);
710 	float submarine = GetAttacksBy(0, game_period);
711 
712 	if(cfg->AIR_ONLY_MOD)
713 	{
714 		// determine effectiveness vs several other units
715 		anti_ground_urgency = (int)( 2 + (0.05f + ground) * (2.0f * attacked_by[0] + 1.0f) * (4.0f * max_combat_units_spotted[0] + 0.2f) / (4.0f * defence_power_vs[0] + 1));
716 		anti_air_urgency = (int)( 2 + (0.05f + air) * (2.0f * attacked_by[1] + 1.0f) * (4.0f * max_combat_units_spotted[1] + 0.2f) / (4.0f * defence_power_vs[1] + 1));
717 		anti_hover_urgency = (int)( 2 + (0.05f + hover) * (2.0f * attacked_by[2] + 1.0f) * (4.0f * max_combat_units_spotted[2] + 0.2f) / (4.0f * defence_power_vs[2] + 1));
718 		anti_sea_urgency = (int) (2 + (0.05f + sea) * (2.0f * attacked_by[3] + 1.0f) * (4.0f * max_combat_units_spotted[3] + 0.2f) / (4.0f * defence_power_vs[3] + 1));
719 
720 		for(int i = 0; i < ai->Getexecute()->unitProductionRate; ++i)
721 		{
722 			ground_eff = 0;
723 			air_eff = 0;
724 			hover_eff = 0;
725 			sea_eff = 0;
726 
727 			k = rand()%(anti_ground_urgency + anti_air_urgency + anti_hover_urgency + anti_sea_urgency);
728 
729 			if(k < anti_ground_urgency)
730 			{
731 				ground_eff = 4;
732 			}
733 			else if(k < anti_ground_urgency + anti_air_urgency)
734 			{
735 				air_eff = 4;
736 			}
737 			else if(k < anti_ground_urgency + anti_air_urgency + anti_hover_urgency)
738 			{
739 				hover_eff = 4;
740 			}
741 			else
742 			{
743 				sea_eff = 4;
744 			}
745 
746 			BuildUnitOfMovementType(MOVE_TYPE_AIR, cost, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff, stat_eff, urgent);
747 		}
748 	}
749 	else
750 	{
751 		// choose unit category dependend on map type
752 		if(ai->Getmap()->map_type == LAND_MAP)
753 		{
754 			// determine effectiveness vs several other units
755 			anti_ground_urgency = (int)( 2 + (0.1f + ground) * (attacked_by[0] + 1.0f) * (4.0f * max_combat_units_spotted[0] + 0.2f) / (4.0f * defence_power_vs[0] + 1));
756 			anti_air_urgency = (int)( 2 + (0.1f + air) * (attacked_by[1] + 1.0f) * (4.0f * max_combat_units_spotted[1] + 0.2f) / (4.0f * defence_power_vs[1] + 1));
757 			anti_hover_urgency = (int)( 2 + (0.1f + hover) * (attacked_by[2] + 1.0f) * (4.0f * max_combat_units_spotted[2] + 0.2f) / (4.0f * defence_power_vs[2] + 1));
758 
759 			for(int i = 0; i < ai->Getexecute()->unitProductionRate; ++i)
760 			{
761 				ground_eff = 0;
762 				air_eff = 0;
763 				hover_eff = 0;
764 				stat_eff = 0;
765 
766 				// determine unit type
767 				if(rand()%(cfg->AIRCRAFT_RATE * 100) < 100)
768 				{
769 					allowed_move_type |= MOVE_TYPE_AIR;
770 
771 					k = rand()%1024;
772 
773 					if(k < 384)
774 					{
775 						ground_eff = 4;
776 						hover_eff = 1;
777 					}
778 					else if(k < 640)
779 					{
780 						air_eff = 4;
781 					}
782 					else
783 					{
784 						stat_eff = 4;
785 					}
786 				}
787 				else
788 				{
789 					allowed_move_type |= MOVE_TYPE_GROUND;
790 					allowed_move_type |= MOVE_TYPE_HOVER;
791 
792 					k = rand()%(anti_ground_urgency + anti_air_urgency + anti_hover_urgency);
793 
794 					if(k < anti_ground_urgency)
795 					{
796 						stat_eff = 2;
797 						ground_eff = 5;
798 						hover_eff = 1;
799 					}
800 					else if(k < anti_ground_urgency + anti_air_urgency)
801 					{
802 						air_eff = 4;
803 
804 						if(anti_air_urgency > 2.0f * anti_ground_urgency)
805 							urgent = true;
806 					}
807 					else
808 					{
809 						ground_eff = 1;
810 						hover_eff = 4;
811 					}
812 				}
813 
814 				BuildUnitOfMovementType(allowed_move_type, cost, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff, stat_eff, urgent);
815 			}
816 		}
817 		else if(ai->Getmap()->map_type == LAND_WATER_MAP)
818 		{
819 			// determine effectiveness vs several other units
820 			anti_ground_urgency = (int)( 2 + (0.1f + ground) * (2.0f * attacked_by[0] + 1.0f) * (4.0f * max_combat_units_spotted[0] + 0.2f) / (4.0f * defence_power_vs[0] + 1));
821 			anti_air_urgency = (int)( 2 + (0.1f + air) * (2.0f * attacked_by[1] + 1.0f) * (4.0f * max_combat_units_spotted[1] + 0.2f) / (4.0f * defence_power_vs[1] + 1));
822 			anti_hover_urgency = (int)( 2 + (0.1f + hover) * (2.0f * attacked_by[2] + 1.0f) * (4.0f * max_combat_units_spotted[2] + 0.2f) / (4.0f * defence_power_vs[2] + 1));
823 			anti_sea_urgency = (int) (2 + (0.1f + sea) * (2.0f * attacked_by[3] + 1.0f) * (4.0f * max_combat_units_spotted[3] + 0.2f) / (4.0f * defence_power_vs[3] + 1));
824 			anti_submarine_urgency = (int)( 2 + (0.1f + submarine) * (2.0f * attacked_by[4] + 1.0f) * (4.0f * max_combat_units_spotted[4] + 0.2f) / (4.0f * defence_power_vs[4] + 1));
825 
826 			for(int i = 0; i < ai->Getexecute()->unitProductionRate; ++i)
827 			{
828 				ground_eff = 0;
829 				air_eff = 0;
830 				hover_eff = 0;
831 				sea_eff = 0;
832 				submarine_eff = 0;
833 				stat_eff = 0;
834 
835 
836 				if(rand()%(cfg->AIRCRAFT_RATE * 100) < 100)
837 				{
838 					allowed_move_type |= MOVE_TYPE_AIR;
839 
840 					if(rand()%1000 < 333)
841 					{
842 						ground_eff = 4;
843 						hover_eff = 1;
844 						sea_eff = 2;
845 					}
846 					else if(rand()%1000 < 333)
847 					{
848 						air_eff = 4;
849 					}
850 					else
851 					{
852 						stat_eff = 4;
853 					}
854 
855 				}
856 				else
857 				{
858 					allowed_move_type |= MOVE_TYPE_HOVER;
859 
860 					k = rand()%(anti_ground_urgency + anti_air_urgency + anti_hover_urgency + anti_sea_urgency + anti_submarine_urgency);
861 
862 					if(k < anti_ground_urgency)
863 					{
864 						stat_eff = 2;
865 						ground_eff = 5;
866 						hover_eff = 1;
867 						allowed_move_type |= MOVE_TYPE_GROUND;
868 					}
869 					else if(k < anti_ground_urgency + anti_air_urgency)
870 					{
871 						allowed_move_type |= MOVE_TYPE_GROUND;
872 						allowed_move_type |= MOVE_TYPE_SEA;
873 
874 						air_eff = 4;
875 
876 						if(anti_air_urgency > 2.0f * anti_ground_urgency)
877 							urgent = true;
878 					}
879 					else if(k < anti_ground_urgency + anti_air_urgency + anti_hover_urgency)
880 					{
881 						allowed_move_type |= MOVE_TYPE_GROUND;
882 						allowed_move_type |= MOVE_TYPE_SEA;
883 
884 						ground_eff = 1;
885 						hover_eff = 4;
886 					}
887 					else if(k < anti_ground_urgency + anti_air_urgency + anti_hover_urgency + anti_sea_urgency)
888 					{
889 						allowed_move_type |= MOVE_TYPE_SEA;
890 						hover_eff = 1;
891 						sea_eff = 4;
892 						submarine_eff = 1;
893 					}
894 					else
895 					{
896 						allowed_move_type |= MOVE_TYPE_SEA;
897 						submarine_eff = 4;
898 						sea_eff = 1;
899 					}
900 				}
901 
902 				BuildUnitOfMovementType(allowed_move_type, cost, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff,stat_eff, urgent);
903 			}
904 		}
905 		else if(ai->Getmap()->map_type == WATER_MAP)
906 		{
907 			// determine effectiveness vs several other units
908 			anti_air_urgency = (int)( 2 + (0.1f + air) * (2.0f * attacked_by[1] + 1.0f) * (4.0f * max_combat_units_spotted[1] + 0.2f) / (4.0f * defence_power_vs[1] + 1));
909 			anti_hover_urgency = (int)( 2 + (0.1f + hover) * (2.0f * attacked_by[2] + 1.0f) * (4.0f * max_combat_units_spotted[2] + 0.2f) / (4.0f * defence_power_vs[2] + 1));
910 			anti_sea_urgency = (int) (2 + (0.1f + sea) * (2.0f * attacked_by[3] + 1.0f) * (4.0f * max_combat_units_spotted[3] + 0.2f) / (4.0f * defence_power_vs[3] + 1));
911 			anti_submarine_urgency = (int)( 2 + (0.1f + submarine) * (2.0f * attacked_by[4] + 1.0f) * (4.0f * max_combat_units_spotted[4] + 0.2f) / (4.0f * defence_power_vs[4] + 1));
912 
913 			for(int i = 0; i < ai->Getexecute()->unitProductionRate; ++i)
914 			{
915 				air_eff = 0;
916 				hover_eff = 0;
917 				sea_eff = 0;
918 				submarine_eff = 0;
919 				stat_eff = 0;
920 
921 				if(rand()%(cfg->AIRCRAFT_RATE * 100) < 100)
922 				{
923 					allowed_move_type |= MOVE_TYPE_AIR;
924 
925 					if(rand()%1000 < 333)
926 					{
927 						sea_eff = 4;
928 						hover_eff = 2;
929 					}
930 					else if(rand()%1000 < 333)
931 						air_eff = 4;
932 					else
933 						stat_eff = 4;
934 				}
935 				else
936 				{
937 					allowed_move_type |= MOVE_TYPE_HOVER;
938 					allowed_move_type |= MOVE_TYPE_SEA;
939 
940 					k = rand()%(anti_sea_urgency + anti_air_urgency + anti_hover_urgency + anti_submarine_urgency);
941 
942 					if(k < anti_air_urgency)
943 					{
944 						air_eff = 4;
945 
946 						if(anti_air_urgency > anti_sea_urgency)
947 							urgent = true;
948 					}
949 					else if(k < anti_hover_urgency + anti_air_urgency)
950 					{
951 						sea_eff = 1;
952 						hover_eff = 5;
953 					}
954 					else if(k < anti_hover_urgency + anti_air_urgency + anti_submarine_urgency)
955 					{
956 						submarine_eff = 4;
957 						sea_eff = 1;
958 					}
959 					else
960 					{
961 						hover_eff = 1;
962 						sea_eff = 5;
963 						submarine_eff = 1;
964 					}
965 				}
966 
967 				BuildUnitOfMovementType(allowed_move_type, cost, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff,stat_eff, urgent);
968 			}
969 		}
970 	}
971 }
972 
BuildUnitOfMovementType(unsigned int allowed_move_type,float cost,float ground_eff,float air_eff,float hover_eff,float sea_eff,float submarine_eff,float stat_eff,bool urgent)973 void AAIBrain::BuildUnitOfMovementType(unsigned int allowed_move_type, float cost, float ground_eff, float air_eff, float hover_eff, float sea_eff, float submarine_eff, float stat_eff, bool urgent)
974 {
975 	float speed = 0;
976 	float range = 0;
977 	float power = 2;
978 	float eff = 2;
979 
980 	// determine speed, range & eff
981 	if(rand()%cfg->FAST_UNITS_RATE == 1)
982 	{
983 		if(rand()%2 == 1)
984 			speed = 1;
985 		else
986 			speed = 2;
987 	}
988 	else
989 		speed = 0.1f;
990 
991 	if(rand()%cfg->HIGH_RANGE_UNITS_RATE == 1)
992 	{
993 		const int t = rand()%1000;
994 
995 		if(t < 350)
996 			range = 0.75;
997 		else if(t == 700)
998 			range = 1.3f;
999 		else
1000 			range = 1.7f;
1001 	}
1002 	else
1003 		range = 0.1f;
1004 
1005 	if(rand()%3 == 1)
1006 		power = 4;
1007 
1008 	if(rand()%3 == 1)
1009 		eff = 4;
1010 
1011 	// start selection
1012 	int unit = 0, ground = 0, hover = 0;
1013 
1014 	if(allowed_move_type & MOVE_TYPE_AIR)
1015 	{
1016 		if(rand()%cfg->LEARN_RATE == 1)
1017 			unit = ai->Getbt()->GetRandomUnit(ai->Getbt()->units_of_category[AIR_ASSAULT][ai->Getside()-1]);
1018 		else
1019 		{
1020 			unit = ai->Getbt()->GetAirAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 9, false);
1021 
1022 			if(unit && ai->Getbt()->units_dynamic[unit].constructorsAvailable + ai->Getbt()->units_dynamic[unit].constructorsRequested <= 0)
1023 			{
1024 				ai->Getbt()->BuildFactoryFor(unit);
1025 				unit = ai->Getbt()->GetAirAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 9, true);
1026 			}
1027 		}
1028 	}
1029 
1030 	if(allowed_move_type & MOVE_TYPE_GROUND)
1031 	{
1032 		// choose random unit (to learn more)
1033 		if(rand()%cfg->LEARN_RATE == 1)
1034 			ground = ai->Getbt()->GetRandomUnit(ai->Getbt()->units_of_category[GROUND_ASSAULT][ai->Getside()-1]);
1035 		else
1036 		{
1037 			ground = ai->Getbt()->GetGroundAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 15, false);
1038 
1039 			if(ground && ai->Getbt()->units_dynamic[ground].constructorsAvailable + ai->Getbt()->units_dynamic[ground].constructorsRequested <= 0)
1040 			{
1041 				ai->Getbt()->BuildFactoryFor(ground);
1042 				ground = ai->Getbt()->GetGroundAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 15, true);
1043 			}
1044 		}
1045 	}
1046 
1047 	if(allowed_move_type & MOVE_TYPE_HOVER)
1048 	{
1049 		if(rand()%cfg->LEARN_RATE == 1)
1050 			hover = ai->Getbt()->GetRandomUnit(ai->Getbt()->units_of_category[HOVER_ASSAULT][ai->Getside()-1]);
1051 		else
1052 		{
1053 			hover = ai->Getbt()->GetHoverAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 9, false);
1054 
1055 			if(hover && ai->Getbt()->units_dynamic[hover].constructorsAvailable + ai->Getbt()->units_dynamic[hover].constructorsRequested <= 0)
1056 			{
1057 				ai->Getbt()->BuildFactoryFor(hover);
1058 				hover = ai->Getbt()->GetHoverAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, stat_eff, eff, speed, range, cost, 9, true);
1059 			}
1060 		}
1061 	}
1062 
1063 	if(allowed_move_type & MOVE_TYPE_SEA)
1064 	{
1065 		int ship, submarine;
1066 
1067 		if(rand()%cfg->LEARN_RATE == 1)
1068 		{
1069 			ship = ai->Getbt()->GetRandomUnit(ai->Getbt()->units_of_category[SEA_ASSAULT][ai->Getside()-1]);
1070 			submarine = ai->Getbt()->GetRandomUnit(ai->Getbt()->units_of_category[SUBMARINE_ASSAULT][ai->Getside()-1]);
1071 		}
1072 		else
1073 		{
1074 			ship = ai->Getbt()->GetSeaAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff, stat_eff, eff, speed, range, cost, 9, false);
1075 
1076 			if(ship && ai->Getbt()->units_dynamic[ship].constructorsAvailable + ai->Getbt()->units_dynamic[ship].constructorsRequested <= 0)
1077 			{
1078 				ai->Getbt()->BuildFactoryFor(ship);
1079 				ship = ai->Getbt()->GetSeaAssault(ai->Getside(), power, ground_eff, air_eff, hover_eff, sea_eff, submarine_eff, stat_eff, eff, speed, range, cost, 9, false);
1080 			}
1081 
1082 			submarine = ai->Getbt()->GetSubmarineAssault(ai->Getside(), power, sea_eff, submarine_eff, stat_eff, eff, speed, range, cost, 9, false);
1083 
1084 			if(submarine && ai->Getbt()->units_dynamic[submarine].constructorsAvailable + ai->Getbt()->units_dynamic[submarine].constructorsRequested <= 0)
1085 			{
1086 				ai->Getbt()->BuildFactoryFor(submarine);
1087 				submarine = ai->Getbt()->GetSubmarineAssault(ai->Getside(), power, sea_eff, submarine_eff, stat_eff, eff, speed, range, cost, 9, false);
1088 			}
1089 		}
1090 
1091 		// determine better unit for desired purpose
1092 		if(ship)
1093 		{
1094 			if(submarine)
1095 				unit = ai->Getbt()->DetermineBetterUnit(ship, submarine, 0, air_eff, hover_eff, sea_eff, submarine_eff, speed, range, cost);
1096 			else
1097 				unit = ship;
1098 		}
1099 		else if(submarine)
1100 			unit = submarine;
1101 	}
1102 
1103 	// ground and hover assault
1104 	if(ground)
1105 	{
1106 		if(hover)
1107 			unit = ai->Getbt()->DetermineBetterUnit(ground, hover, ground_eff, air_eff, hover_eff, sea_eff, 0, speed, range, cost);
1108 		else
1109 			unit = ground;
1110 	}
1111 	// hover and sea
1112 	else if(hover)
1113 	{
1114 		if(unit)
1115 			unit =  ai->Getbt()->DetermineBetterUnit(unit, hover, 0, air_eff, hover_eff, sea_eff, submarine_eff, speed, range, cost);
1116 		else
1117 			unit = hover;
1118 	}
1119 
1120 	if(unit)
1121 	{
1122 		if(ai->Getbt()->units_dynamic[unit].constructorsAvailable > 0)
1123 		{
1124 			if(ai->Getbt()->units_static[unit].cost < cfg->MAX_COST_LIGHT_ASSAULT * ai->Getbt()->max_cost[ai->Getbt()->units_static[unit].category][ai->Getside()-1])
1125 			{
1126 				if(ai->Getexecute()->AddUnitToBuildqueue(unit, 3, urgent))
1127 				{
1128 					ai->Getbt()->units_dynamic[unit].requested += 3;
1129 					ai->Getut()->UnitRequested(ai->Getbt()->units_static[unit].category, 3);
1130 				}
1131 			}
1132 			else if(ai->Getbt()->units_static[unit].cost < cfg->MAX_COST_MEDIUM_ASSAULT * ai->Getbt()->max_cost[ai->Getbt()->units_static[unit].category][ai->Getside()-1])
1133 			{
1134 				if(ai->Getexecute()->AddUnitToBuildqueue(unit, 2, urgent))
1135 					ai->Getbt()->units_dynamic[unit].requested += 2;
1136 					ai->Getut()->UnitRequested(ai->Getbt()->units_static[unit].category, 2);
1137 			}
1138 			else
1139 			{
1140 				if(ai->Getexecute()->AddUnitToBuildqueue(unit, 1, urgent))
1141 					ai->Getbt()->units_dynamic[unit].requested += 1;
1142 					ai->Getut()->UnitRequested(ai->Getbt()->units_static[unit].category);
1143 			}
1144 		}
1145 		else if(ai->Getbt()->units_dynamic[unit].constructorsRequested <= 0)
1146 			ai->Getbt()->BuildFactoryFor(unit);
1147 	}
1148 }
1149 
1150 
GetGamePeriod()1151 int AAIBrain::GetGamePeriod()
1152 {
1153 	int tick = ai->Getcb()->GetCurrentFrame();
1154 
1155 	if(tick < 18000)
1156 		return 0;
1157 	else if(tick < 36000)
1158 		return 1;
1159 	else if(tick < 72000)
1160 		return 2;
1161 	else
1162 		return 3;
1163 
1164 }
1165 
IsSafeSector(AAISector * sector)1166 bool AAIBrain::IsSafeSector(AAISector *sector)
1167 {
1168 	// TODO: improve criteria
1169 	return (sector->lost_units[MOBILE_CONSTRUCTOR-COMMANDER] < 0.5
1170 		&& sector->enemy_combat_units[5] < 0.1 && sector->enemy_structures < 0.01
1171 		&& sector->enemies_on_radar == 0);
1172 }
1173 
GetAttacksBy(int combat_category,int game_period)1174 float AAIBrain::GetAttacksBy(int combat_category, int game_period)
1175 {
1176 	return (ai->Getbt()->attacked_by_category_current[game_period][combat_category] + ai->Getbt()->attacked_by_category_learned[ai->Getmap()->map_type][game_period][combat_category]) / 2.0f;
1177 }
1178 
UpdatePressureByEnemy()1179 void AAIBrain::UpdatePressureByEnemy()
1180 {
1181 	enemy_pressure_estimation = 0;
1182 
1183 	// check base and neighbouring sectors for enemies
1184 	for(list<AAISector*>::iterator s = sectors[0].begin(); s != sectors[0].end(); ++s)
1185 		enemy_pressure_estimation += 0.1f * (*s)->enemy_combat_units[5];
1186 
1187 	for(list<AAISector*>::iterator s = sectors[1].begin(); s != sectors[1].end(); ++s)
1188 		enemy_pressure_estimation += 0.1f * (*s)->enemy_combat_units[5];
1189 
1190 	if(enemy_pressure_estimation > 1.0f)
1191 		enemy_pressure_estimation = 1.0f;
1192 }
1193