1 #ifdef _WIN32
2 #include "windows.h"
3 #endif
4 
5 #include "string.h"
6 #include "stdio.h"
7 #include "stdlib.h"
8 #include "math.h"
9 
10 #include "GL/gl.h"
11 #include "GL/glu.h"
12 #include "GL/glut.h"
13 #include "SDL/SDL.h"
14 #include "SDL/SDL_mixer.h"
15 
16 #include "list.h"
17 #include "vector.h"
18 #include "cmc.h"
19 #include "3dobject.h"
20 #include "shadow3dobject.h"
21 #include "piece3dobject.h"
22 #include "myglutaux.h"
23 #include "nether.h"
24 
25 //FILE *fp;
26 extern int level;
27 
28 /* Only 1 action per turn will be allowed: */
29 
AI_enemy(void)30 void NETHER::AI_enemy(void)
31 {
32 	BUILDING *in_danger_warbase=0;
33 	int state=AI_STATE_EXPANDING;
34 	int nrobots[3]={0,0,0};	/* EXPANDING / ATTACING / DEFENDING */
35 	Vector mean_factory_position;
36 	BUILDING *closest_to_factories_warbase=0;
37 	float distance_to_factories;
38 	BUILDING *closest_to_enemy_warbase=0;
39 	float distance_to_enemy;
40 	int factories[3]={0,0,0};
41 
42 //	if (fp==0) {
43 //		fp=fopen("enemyai.txt","w+");
44 //	} /* if */
45 
46 //	fprintf(fp,"---------------------------------- \n");
47 //	fprintf(fp,"G: %i\nE: %i\nN: %i\nP: %i\nM: %i\nC: %i\nC: %i\n",
48 //			resources[1][0],resources[1][1],resources[1][2],
49 //			resources[1][3],resources[1][4],resources[1][5],resources[1][6]);
50 
51 	/* Analize the situation and determine strategy: */
52 	/*
53 	AI_STATE_EXPANDING
54 	AI_STATE_FIGHTING
55 	AI_STATE_DEFENDING
56 	AI_STATE_CONQUERING
57 	*/
58 	/* Rules: */
59 	/*
60 	1.- If there is a robot force near a WARBASE (closer than 10 squares) -> state = AI_STATE_DEFENDING
61 	2.- If there is no WARBASE in danger, and there are available FACTORIES near -> state = AI_STATE_EXPANDING
62 	2.- If there is no WARBASE in danger and there are enough CAPTURING robots working and
63 		there are more player robots than computer robots -> state = AI_FIGHTING
64 	4.- If there is no WARBASE in danger and there are enough CAPTURING robots working and
65 		there are less player robots than computer robots -> state = AI_CONQUERING
66 	*/
67 
68 	ROBOT *tmpr;	// To test is the entrance to Warbases is free
69 
70 	tmpr=new ROBOT();
71 	tmpr->traction=0;
72 	tmpr->pieces[0]=true;
73 	tmpr->pieces[1]=false;
74 	tmpr->pieces[2]=false;
75 	tmpr->pieces[3]=false;
76 	tmpr->pieces[4]=false;
77 	tmpr->angle=0;
78 	tmpr->program=PROGRAM_FORWARD;
79 	tmpr->op=ROBOTOP_NONE;
80 	tmpr->cmc=RobotCMC(tmpr,1);
81 	tmpr->shipover=false;
82 
83 
84 	{
85 		List<BUILDING> l;
86 		BUILDING *b;
87 		List<ROBOT> rl;
88 		ROBOT *r;
89 		int i;
90 		int forces[2]={0,0};
91 
92 		l.Instance(buildings);
93 		l.Rewind();
94 		mean_factory_position=Vector(0,0,0);
95 		while(l.Iterate(b)) {
96 			if (b->type==B_FACTORY_ELECTRONICS ||
97 				b->type==B_FACTORY_NUCLEAR ||
98 				b->type==B_FACTORY_PHASERS ||
99 				b->type==B_FACTORY_MISSILES ||
100 				b->type==B_FACTORY_CANNONS) {
101 				factories[b->owner]++;
102 				if (b->owner!=2) mean_factory_position=mean_factory_position+b->pos;
103 			} /* if */
104 		} /* while */
105 		mean_factory_position=mean_factory_position/(factories[0]+factories[1]);
106 
107 //		fprintf(fp,"Factories: %i %i %i\n", factories[0],factories[1],factories[2]);
108 
109 		l.Instance(buildings);
110 		l.Rewind();
111 		while(l.Iterate(b)) {
112 			if (b->type==B_WARBASE &&
113 				b->owner==2) {
114 				forces[0]=0;
115 				forces[1]=0;
116 
117 				tmpr->pos=b->pos+Vector(2.5,0.5,0);
118 				if (!RobotCollision(tmpr,true)) {
119 					/* Find the closest WARBASE to the available FACTORIES: */
120 					if (closest_to_factories_warbase==0 ||
121 						(closest_to_factories_warbase->pos-b->pos).norma()<distance_to_factories) {
122 						closest_to_factories_warbase=b;
123 						distance_to_factories=float((closest_to_factories_warbase->pos-b->pos).norma());
124 					} /* if */
125 
126 					/* Find the closest WARBASE to the enemy: */
127 					if (closest_to_enemy_warbase==0 ||
128 						closest_to_enemy_warbase->pos.y<distance_to_enemy) {
129 						closest_to_enemy_warbase=b;
130 						distance_to_enemy=float(closest_to_enemy_warbase->pos.y);
131 					} /* if */
132 				} /* if */
133 
134 				/* Test for WARBASEs in danger: */
135 				for(i=0;i<2;i++) {
136 					rl.Instance(robots[i]);
137 					rl.Rewind();
138 					while(rl.Iterate(r)) {
139 						if ((r->pos-b->pos).norma()<10.0) {
140 							/* Robot near: */
141 							forces[i]+=RobotCost(r);
142 
143 							if (i==1) {
144 								if (forces[0]>forces[1] &&
145 									(r->program!=PROGRAM_DESTROY ||
146 									 r->program_parameter!=P_PARAM_ROBOTS)) {
147 
148 //									fprintf(fp,"Program of <%g,%g,%g> -> DESTROY ROBOTS\n",r->pos.x,r->pos.y,r->pos.z);
149 
150 									r->program=PROGRAM_DESTROY;
151 									r->program_parameter=P_PARAM_ROBOTS;
152 									return;
153 								} /* if */
154 							} /* if */
155 						} /* if */
156 					} /* while */
157 				} /* for */
158 				if (forces[0]>forces[1]) {
159 					state=AI_STATE_DEFENDING;
160 					in_danger_warbase=b;
161 				} /* if */
162 
163 			} /* if */
164 		} /* while */
165 	}
166 
167 
168 	/* If the warbase in danger id blocked, build robots from another warbase: */
169 	if (in_danger_warbase!=0) {
170 		tmpr->pos=in_danger_warbase->pos+Vector(2.0,0.5,0);
171 		if (RobotCollision(tmpr,true)) in_danger_warbase=closest_to_enemy_warbase;
172 	} /* if */
173 
174 	delete tmpr;
175 	tmpr=0;
176 
177 	/* If the enemy has no WARBASES, he cannot do anything: (???) */
178 	if (closest_to_factories_warbase==0) return;
179 
180 
181 	/* Count the number of robots: */
182 	{
183 		List<ROBOT> rl;
184 		ROBOT *r;
185 
186 		rl.Instance(robots[1]);
187 		rl.Rewind();
188 		while(rl.Iterate(r)) {
189 			if (r->program==PROGRAM_CAPTURE) nrobots[0]++;
190 			if (r->program==PROGRAM_DESTROY) nrobots[1]++;
191 			if (r->program==PROGRAM_STOPDEFEND) nrobots[2]++;
192 		} /* while */
193 	}
194 
195 	if (in_danger_warbase!=0 &&
196 		(level>=2 ||
197 		 (level==1 && (rand()%2)==0) ||
198 		 (level==0 && (rand()%4)==0))) {
199 		ROBOT *r;
200 		/* Try to build a ROBOT to defend the WARBASE */
201 
202 //		fprintf(fp,"Trying to BUILD a robot to DEFEND the WARBASE \n");
203 
204 		r=AI_enemy_newrobot(AI_STATE_DEFENDING,in_danger_warbase->pos+Vector(2.5,0.5,0));
205 		if (r!=0) {
206 
207 //			fprintf(fp,"Achieved.\n");
208 
209 			r->program=PROGRAM_DESTROY;
210 			r->program_parameter=P_PARAM_ROBOTS;
211 		} /* if */
212 	} else {
213 		if (nrobots[2]>0 &&
214 			(level>=2 ||
215 			(level==1 && (rand()%2)==0) ||
216 			(level==0 && (rand()%4)==0))) {
217 			/* There are too many robots in STOP & DEFEND: */
218 			List<ROBOT> rl;
219 			ROBOT *r;
220 
221 			rl.Instance(robots[1]);
222 			rl.Rewind();
223 			while(rl.Iterate(r)) {
224 				if (r->program==PROGRAM_STOPDEFEND) {
225 					if (nrobots[0]<6 && factories[2]<(factories[1]+factories[0]) &&
226 						(robots[0].Length()*2)<=nrobots[1]) {
227 						/* Convert the robot to a conquering one: */
228 						if (factories[1]>factories[0]) {
229 							r->program=PROGRAM_CAPTURE;
230 							r->program_parameter=P_PARAM_EFACTORIES;
231 							return;
232 						} else {
233 							r->program=PROGRAM_CAPTURE;
234 							r->program_parameter=P_PARAM_NFACTORIES;
235 							return;
236 						} /* if */
237 					} else {
238 						if ((robots[0].Length()*2)>nrobots[1]) {
239 							r->program=PROGRAM_DESTROY;
240 							r->program_parameter=P_PARAM_ROBOTS;
241 							return;
242 						} else {
243 							r->program=PROGRAM_CAPTURE;
244 							r->program_parameter=P_PARAM_WARBASES;
245 							return;
246 						} /* if */
247 					} /* if */
248 				} /* if */
249 			} /* while */
250 		} /* if */
251 		/* Test for near FACTORIES and CAPTURING ROBOTS: */
252 		if (nrobots[0]<6 && factories[2]<(factories[1]+factories[0]) &&
253 			(robots[0].Length()*2)<=nrobots[1]) {
254 			/* I need more conquering robots: */
255 
256 			/* Try to make better robots as time passes: */
257 			switch(level) {
258 			case 0:
259 				if (nrobots[0]>=1 && resources[1][0]+resources[1][6]<20) return;
260 				if (nrobots[0]>=1 && resources[1][0]+resources[1][6]<25) return;
261 				if (nrobots[0]>=2 && resources[1][0]+resources[1][6]<30) return;
262 				break;
263 			case 1:
264 				if (nrobots[0]>=1 && resources[1][0]+resources[1][6]<20) return;
265 				if (nrobots[0]>=2 && resources[1][0]+resources[1][6]<25) return;
266 				if (nrobots[0]>=3 && resources[1][0]+resources[1][6]<30) return;
267 				break;
268 			default:
269 				if (nrobots[0]>=2 && resources[1][0]+resources[1][6]<20) return;
270 				if (nrobots[0]>=3 && resources[1][0]+resources[1][6]<25) return;
271 				if (nrobots[0]>=4 && resources[1][0]+resources[1][6]<30) return;
272 				break;
273 			} /* switch */
274 
275 			ROBOT *r=AI_enemy_newrobot(AI_STATE_EXPANDING,closest_to_factories_warbase->pos+Vector(2.5,0.5,0));
276 //			fprintf(fp,"Trying to BUILD a robot to CONQUER FACTORIES \n");
277 			if (r!=0) {
278 				if (factories[1]>factories[0]) {
279 
280 //					fprintf(fp,"Achieved, it will conquer ENEMY FACTORIES\n");
281 
282 					r->program=PROGRAM_CAPTURE;
283 					r->program_parameter=P_PARAM_EFACTORIES;
284 				} else {
285 
286 //					fprintf(fp,"Achieved, it will conquer NEUTRAL FACTORIES\n");
287 
288 					r->program=PROGRAM_CAPTURE;
289 					r->program_parameter=P_PARAM_NFACTORIES;
290 				} /* if */
291 			} /* if */
292 		} else {
293 			/* I've enough conquering robots: */
294 			if (nrobots[1]>10) {
295 				/* I've enough attacking robots, let's build a conquering one: */
296 //				fprintf(fp,"Trying to BUILD a robot to CONQUER WARBASES \n");
297 
298 				if (resources[1][0]+resources[1][6]<40) return;
299 				ROBOT *r=AI_enemy_newrobot(AI_STATE_CONQUERING,closest_to_enemy_warbase->pos+Vector(2.5,0.5,0));
300 				if (r!=0) {
301 
302 //					fprintf(fp,"Achieved.\n");
303 
304 					r->program=PROGRAM_CAPTURE;
305 					r->program_parameter=P_PARAM_WARBASES;
306 				} /* if */
307 			} else {
308 				/* I need more attacking robots: */
309 
310 				/* Try to make better robots as time passes: */
311 				switch(level) {
312 				case 0:
313 					if (nrobots[1]>=1 && resources[1][0]+resources[1][6]<20) return;
314 					if (nrobots[1]>=1 && resources[1][0]+resources[1][6]<25) return;
315 					if (nrobots[1]>=2 && resources[1][0]+resources[1][6]<30) return;
316 					break;
317 				case 1:
318 					if (nrobots[1]>=1 && resources[1][0]+resources[1][6]<20) return;
319 					if (nrobots[1]>=2 && resources[1][0]+resources[1][6]<25) return;
320 					if (nrobots[1]>=3 && resources[1][0]+resources[1][6]<30) return;
321 					break;
322 				default:
323 					if (nrobots[1]>=2 && resources[1][0]+resources[1][6]<20) return;
324 					if (nrobots[1]>=3 && resources[1][0]+resources[1][6]<25) return;
325 					if (nrobots[1]>=4 && resources[1][0]+resources[1][6]<30) return;
326 					break;
327 				} /* switch */
328 
329 				ROBOT *r=AI_enemy_newrobot(AI_STATE_FIGHTING,closest_to_enemy_warbase->pos+Vector(2.5,0.5,0));
330 
331 //				fprintf(fp,"Trying to BUILD a robot to ATTACK ROBOTS \n");
332 
333 				if (r!=0) {
334 
335 //					fprintf(fp,"Achieved.\n");
336 
337 					r->program=PROGRAM_DESTROY;
338 					r->program_parameter=P_PARAM_ROBOTS;
339 				} /* if */
340 			} /* if */
341 		} /* if */
342 	} /* if */
343 
344 } /* NETHER::AI_enemy */
345 
346 
AI_enemy_newrobot(int state,Vector pos)347 ROBOT *NETHER::AI_enemy_newrobot(int state,Vector pos)
348 {
349 	int traction=0;
350 	bool pieces[5]={false,false,false,false,false};
351 	int rg=resources[1][R_GENERAL];
352 
353 	if (rg+resources[1][R_CHASSIS]>30 &&
354 			(level>=2 ||
355 			(level==1 && (rand()%2)==0) ||
356 			(level==0 && (rand()%4)==0))) {
357 		traction=2;
358 		rg-=10;
359 	} else {
360 		if (rg+resources[1][R_CHASSIS]>20 &&
361 			(level>=2 ||
362 			(level==1 && (rand()%2)==0) ||
363 			(level==0 && (rand()%4)==0))) {
364 			traction=1;
365 			rg-=5;
366 		} else {
367 			traction=0;
368 			rg-=2;
369 		} /* if */
370 	} /* if */
371 
372 	switch(state) {
373 	case AI_STATE_EXPANDING:
374 		if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>40 &&
375 			(level>=2 ||
376 			(level==1 && (rand()%2)==0) ||
377 			(level==0 && (rand()%4)==0))) {
378 			pieces[2]=true;
379 		} else {
380 			if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>20 &&
381 				(level>=2 ||
382 				(level==1 && (rand()%2)==0) ||
383 				(level==0 && (rand()%4)==0))) {
384 				pieces[1]=true;
385 			} else {
386 				pieces[0]=true;
387 			} /* if */
388 		} /* if */
389 
390 		if (rg+resources[1][R_ELECTRONICS]>10) pieces[4]=true;
391 		break;
392 	case AI_STATE_DEFENDING:
393 		if (rg+resources[1][R_PHASERS]>20 &&
394 			(level>=2 ||
395 			(level==1 && (rand()%2)==0) ||
396 			(level==0 && (rand()%4)==0))) pieces[2]=true;
397 		if (rg+resources[1][R_MISSILES]>20 &&
398 			(level>=2 ||
399 			(level==1 && (rand()%2)==0) ||
400 			(level==0 && (rand()%4)==0))) pieces[1]=true;
401 		if (rg+resources[1][R_CANNONS]>20 &&
402 			(level>=2 ||
403 			(level==1 && (rand()%2)==0) ||
404 			(level==0 && (rand()%4)==0))) pieces[0]=true;
405 		if (!pieces[0] && !pieces[1] && !pieces[2]) pieces[0]=true;
406 
407 		if (rg+resources[1][R_ELECTRONICS]>30) pieces[4]=true;
408 		break;
409 	case AI_STATE_FIGHTING:
410 		if (rg+resources[1][R_PHASERS]>20 &&
411 			(level>=2 ||
412 			(level==1 && (rand()%2)==0) ||
413 			(level==0 && (rand()%4)==0))) pieces[2]=true;
414 		if (rg+resources[1][R_MISSILES]>20 &&
415 			(level>=2 ||
416 			(level==1 && (rand()%2)==0) ||
417 			(level==0 && (rand()%4)==0))) pieces[1]=true;
418 		if (rg+resources[1][R_CANNONS]>20 &&
419 			(level>=2 ||
420 			(level==1 && (rand()%2)==0) ||
421 			(level==0 && (rand()%4)==0))) pieces[0]=true;
422 		if (!pieces[0] && !pieces[1] && !pieces[2]) pieces[0]=true;
423 
424 		if (rg+resources[1][R_ELECTRONICS]>20) pieces[4]=true;
425 		break;
426 	case AI_STATE_CONQUERING:
427 		if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>40 &&
428 			(level>=2 ||
429 			(level==1 && (rand()%2)==0) ||
430 			(level==0 && (rand()%4)==0))) {
431 			pieces[2]=true;
432 		} else {
433 			if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>20 &&
434 				(level>=2 ||
435 				(level==1 && (rand()%2)==0) ||
436 				(level==0 && (rand()%4)==0))) {
437 				pieces[1]=true;
438 			} else {
439 				pieces[0]=true;
440 			} /* if */
441 		} /* if */
442 
443 		if (rg+resources[1][R_ELECTRONICS]>10) pieces[4]=true;
444 		break;
445 	case AI_STATE_DESTROYING:
446 		if (rg+resources[1][R_NUCLEAR]>40) pieces[3]=true;
447 		if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>40 &&
448 			(level>=2 ||
449 			(level==1 && (rand()%2)==0) ||
450 			(level==0 && (rand()%4)==0))) {
451 			pieces[2]=true;
452 		} else {
453 			if (rg+resources[1][R_CANNONS]+resources[1][R_MISSILES]+resources[1][R_PHASERS]>20 &&
454 				(level>=2 ||
455 				(level==1 && (rand()%2)==0) ||
456 				(level==0 && (rand()%4)==0))) {
457 				pieces[1]=true;
458 			} else {
459 				pieces[0]=true;
460 			} /* if */
461 		} /* if */
462 
463 		if (rg+resources[1][R_ELECTRONICS]>10 &&
464 			(level>=2 ||
465 			(level==1 && (rand()%2)==0) ||
466 			(level==0 && (rand()%4)==0))) pieces[4]=true;
467 		break;
468 	} /* switch */
469 
470 	/* Build the robot: */
471 	{
472 		int i;
473 		ROBOT *r;
474 		int cost[7];
475 
476 		r=new ROBOT();
477 		r->traction=traction;
478 		r->pieces[0]=pieces[0];
479 		r->pieces[1]=pieces[1];
480 		r->pieces[2]=pieces[2];
481 		r->pieces[3]=pieces[3];
482 		r->pieces[4]=pieces[4];
483 		RobotCost(1,r,cost);
484 
485 		for(i=0;i<7;i++) {
486 			if (resources[1][i]<cost[i]) {
487 				/* Not enough resources! */
488 				return 0;
489 			} /* if */
490 		} /* for */
491 
492 
493 		/* Valid robot, build it: */
494 		r->pos=pos;
495 		r->angle=0;
496 		r->program=PROGRAM_FORWARD;
497 		r->op=ROBOTOP_NONE;
498 		r->cmc=RobotCMC(r,1);
499 		r->shipover=false;
500 
501 		if (!RobotCollision(r,true)) {
502 			robots[1].Add(r);
503 			AI_newrobot(r->pos,0);
504 
505 			for(i=0;i<7;i++) resources[1][i]-=cost[i];
506 
507 			return r;
508 		} else {
509 			delete r;
510 		} /* if */
511 	}
512 
513 	return 0;
514 
515 } /* AI_enemy_newrobot */
516 
517 
518