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