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 <list>
11 
12 #include "AAIAirForceManager.h"
13 
14 #include "AAIMap.h"
15 #include "AAI.h"
16 #include "AAIBuildTable.h"
17 #include "AAIUnitTable.h"
18 #include "AAIConfig.h"
19 #include "AAIGroup.h"
20 #include "AAISector.h"
21 
22 #include "LegacyCpp/UnitDef.h"
23 using namespace springLegacyAI;
24 
25 
AAIAirForceManager(AAI * ai)26 AAIAirForceManager::AAIAirForceManager(AAI *ai)
27 {
28 	this->ai = ai;
29 
30 	my_team = ai->Getcb()->GetMyTeam();
31 	num_of_targets = 0;
32 
33 	targets.resize(cfg->MAX_AIR_TARGETS);
34 
35 	for(int i = 0; i < cfg->MAX_AIR_TARGETS; ++i)
36 		targets[i].unit_id = -1;
37 
38 	air_groups = &ai->Getgroup_list()[AIR_ASSAULT];
39 }
40 
~AAIAirForceManager(void)41 AAIAirForceManager::~AAIAirForceManager(void)
42 {
43 
44 }
45 
CheckTarget(int unit_id,const UnitDef * def)46 void AAIAirForceManager::CheckTarget(int unit_id, const UnitDef *def)
47 {
48 	// do not attack own units
49 	if(my_team != ai->Getcb()->GetUnitTeam(unit_id))
50 	{
51 		float3 pos = ai->Getcb()->GetUnitPos(unit_id);
52 
53 		// calculate in which sector unit is located
54 		int x = pos.x/ai->Getmap()->xSectorSize;
55 		int y = pos.z/ai->Getmap()->ySectorSize;
56 
57 		// check if unit is within the map
58 		if(x >= 0 && x < ai->Getmap()->xSectors && y >= 0 && y < ai->Getmap()->ySectors)
59 		{
60 			// check for anti air defences if low on units
61 			if(ai->Getmap()->sector[x][y].lost_units[AIR_ASSAULT-COMMANDER] >= cfg->MAX_AIR_GROUP_SIZE && ai->Getgroup_list()[AIR_ASSAULT].size() < 5)
62 				return;
63 
64 			AAIGroup *group;
65 			int max_groups;
66 
67 			UnitCategory category = ai->Getbt()->units_static[def->id].category;
68 
69 			if(ai->Getbt()->GetUnitDef(def->id).health > 8000)
70 				max_groups = 3;
71 			else if(ai->Getbt()->GetUnitDef(def->id).health > 4000)
72 				max_groups = 2;
73 			else
74 				max_groups = 1;
75 
76 			for(int i = 0; i < max_groups; ++i)
77 			{
78 				if(category == AIR_ASSAULT)
79 				{
80 					group = GetAirGroup(100.0, ANTI_AIR_UNIT);
81 
82 					if(group)
83 						group->DefendAirSpace(&pos);
84 				}
85 				else if(category <= METAL_MAKER)
86 				{
87 					group = GetAirGroup(100.0, BOMBER_UNIT);
88 
89 					if(group)
90 						group->BombTarget(unit_id, &pos);
91 				}
92 				else
93 				{
94 					group = GetAirGroup(100.0, ASSAULT_UNIT);
95 
96 					if(group)
97 						group->AirRaidUnit(unit_id);
98 				}
99 			}
100 		}
101 	}
102 }
103 
CheckBombTarget(int unit_id,int def_id)104 void AAIAirForceManager::CheckBombTarget(int unit_id, int def_id)
105 {
106 	// dont continue if target list already full
107 	if(num_of_targets >= cfg->MAX_AIR_TARGETS)
108 		return;
109 
110 	// do not add own units or units that ar already on target list
111 	if(my_team != ai->Getcb()->GetUnitTeam(unit_id) && !IsTarget(unit_id))
112 	{
113 		float3 pos = ai->Getcb()->GetUnitPos(unit_id);
114 
115 		// calculate in which sector unit is located
116 		int x = pos.x/ai->Getmap()->xSectorSize;
117 		int y = pos.z/ai->Getmap()->ySectorSize;
118 
119 		// check if unit is within the map
120 		if(x >= 0 && x < ai->Getmap()->xSectors && y >= 0 && y < ai->Getmap()->ySectors)
121 		{
122 			AddTarget(unit_id, def_id);
123 		}
124 	}
125 }
126 
AddTarget(int unit_id,int def_id)127 void AAIAirForceManager::AddTarget(int unit_id, int def_id)
128 {
129 	for(int i = 0; i < cfg->MAX_AIR_TARGETS; ++i)
130 	{
131 		if(targets[i].unit_id == -1)
132 		{
133 			ai->LogConsole("Target added...");
134 
135 			targets[i].pos = ai->Getcb()->GetUnitPos(unit_id);
136 			targets[i].def_id = def_id;
137 			targets[i].cost = ai->Getbt()->units_static[def_id].cost;
138 			targets[i].health = ai->Getcb()->GetUnitHealth(unit_id);
139 			targets[i].category = ai->Getbt()->units_static[def_id].category;
140 
141 			ai->Getut()->units[unit_id].status = BOMB_TARGET;
142 
143 			++num_of_targets;
144 
145 			return;
146 		}
147 	}
148 
149 	// could not add target, randomly overwrite one of the existing targets
150 	/*i = rand()%cfg->MAX_AIR_TARGETS;
151 	targets[i].pos.x = pos.x;
152 	targets[i].pos.z = pos.z;
153 	targets[i].def_id = def_id;
154 	targets[i].cost = cost;
155 	targets[i].health = health;
156 	targets[i].category = category;*/
157 }
158 
RemoveTarget(int unit_id)159 void AAIAirForceManager::RemoveTarget(int unit_id)
160 {
161 	for(int i = 0; i < cfg->MAX_AIR_TARGETS; ++i)
162 	{
163 		if(targets[i].unit_id == unit_id)
164 		{
165 			ai->LogConsole("Target removed...");
166 
167 			targets[i].unit_id = -1;
168 
169 			ai->Getut()->units[unit_id].status = ENEMY_UNIT;
170 
171 			--num_of_targets;
172 
173 			return;
174 		}
175 	}
176 }
177 
BombBestUnit(float cost,float danger)178 void AAIAirForceManager::BombBestUnit(float cost, float danger)
179 {
180 	float best = 0, current;
181 	int best_target = -1;
182 	int x, y, i;
183 
184 	for(i = 0; i < cfg->MAX_AIR_TARGETS; ++i)
185 	{
186 		if(targets[i].unit_id != -1)
187 		{
188 			x = targets[i].pos.x/ai->Getmap()->xSectorSize;
189 			y = targets[i].pos.z/ai->Getmap()->ySectorSize;
190 
191 			current = pow(targets[i].cost, cost) / (1.0f + ai->Getmap()->sector[x][y].enemy_stat_combat_power[1] * danger) * targets[i].health / ai->Getbt()->GetUnitDef(targets[i].def_id).health ;
192 
193 			if(current > best)
194 			{
195 				best = current;
196 				best_target = i;
197 			}
198 		}
199 	}
200 
201 	if(best_target != -1)
202 	{
203 		AAIGroup *group = GetAirGroup(100.0, BOMBER_UNIT);
204 
205 		if(group)
206 		{
207 			//ai->LogConsole("Bombing...");
208 			group->BombTarget(targets[i].unit_id, &targets[i].pos);
209 
210 			targets[i].unit_id = -1;
211 			--num_of_targets;
212 		}
213 	}
214 }
215 
GetAirGroup(float importance,UnitType group_type)216 AAIGroup* AAIAirForceManager::GetAirGroup(float importance, UnitType group_type)
217 {
218 	if(cfg->AIR_ONLY_MOD)
219 	{
220 		for(list<AAIGroup*>::iterator group = air_groups->begin(); group != air_groups->end(); ++group)
221 		{
222 			if((*group)->task_importance < importance && group_type == (*group)->group_unit_type  && (*group)->units.size() > (*group)->maxSize/2)
223 				return *group;
224 		}
225 	}
226 	else
227 	{
228 		for(list<AAIGroup*>::iterator group = air_groups->begin(); group != air_groups->end(); ++group)
229 		{
230 			if((*group)->task_importance < importance && group_type == (*group)->group_unit_type && (*group)->units.size() >= (*group)->maxSize)
231 				return *group;
232 		}
233 	}
234 
235 	return 0;
236 }
237 
IsTarget(int unit_id)238 bool AAIAirForceManager::IsTarget(int unit_id)
239 {
240 	for(int i = 0; i < cfg->MAX_AIR_TARGETS; ++i)
241 	{
242 		if(targets[i].unit_id == unit_id)
243 			return true;
244 	}
245 
246 	return false;
247 }
248