1 #ifdef _WIN32
2 #include "windows.h"
3 #endif
4 
5 #include "string.h"
6 #include <stdlib.h>
7 #include "stdio.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 /* Artificial Intelligence variables: */
26 /*
27 
28 int *discreetmap;	->	- Will keep a discreet copy of the map, telling whether a robot can occupy a position
29 						or not.
30 						- Each cell of the original map, transform to a set of 2x2 cells of this new map, so
31 						  each 2x2 square of this cells correspond to one of the positions where a robot can
32 						  be.
33 
34 int *bk_discreetmap;	-> just contains the background.
35 
36 AI_OPERATOR *searchmap;	-> In this map is where the search process will be performed.
37 
38 */
39 
40 const int WE_SEARCH_DEPTH=12;	/* Search depth for robots with ELECTRONICS	*/
41 //const int WE_SEARCH_DEPTH=80;	/* Search depth for robots with ELECTRONICS	*/
42 const int WOE_SEARCH_DEPTH=4; /* Search depth for robots without ELECTRONICS	*/
43 
44 const int xd[4]={ 1, 0,-1, 0};
45 const int yd[4]={ 0, 1, 0,-1};
46 const int xd2[4]={ 0, 0,-1, 0};
47 const int yd2[4]={ 0, 0, 0,-1};
48 const int xd3[4]={ 1, 0, 1, 0};
49 const int yd3[4]={ 0, 1, 0, 1};
50 const int dangle[4]={0,90,180,270};
51 
52 
53 extern FILE *debug_fp;
54 
robot_zone(Vector pos,int * x,int * y,int * dx,int * dy)55 void robot_zone(Vector pos,int *x,int *y,int *dx,int *dy)
56 {
57 	*x=int((pos.x-0.5)/0.5);
58 	*y=int((pos.y-0.5)/0.5);
59 
60 	if ((int(pos.x*256)%128)==0) *dx=2;
61 					 	    else *dx=3;
62 	if ((int(pos.y*256)%128)==0) *dy=2;
63 						    else *dy=3;
64 } /* robot_zone */
65 
66 
fill_zone(int * map,int w,int val,int x,int y,int dx,int dy)67 void fill_zone(int *map,int w,int val,int x,int y,int dx,int dy)
68 {
69 	int i,j;
70 
71 	for(i=0;i<dx;i++) {
72 		for(j=0;j<dy;j++) {
73 			map[(y+j)*w+(x+i)]=val;
74 		} /* for */
75 	} /* for */
76 } /* fill_zone */
77 
78 
AI_precomputations(void)79 void NETHER::AI_precomputations(void)
80 {
81 	int i;
82 	int x,y;
83 
84 	discreetmap=new int[(map_w*2)*(map_h*2)];
85 	bk_discreetmap=new int[(map_w*2)*(map_h*2)];
86 	searchmap=new AI_OPERATOR *[(map_w*2)*(map_h*2)];
87 	atackmap=new int[(map_w*2)*(map_h*2)];
88 	for(i=0;i<(map_w*2)*(map_h*2);i++) {
89 		searchmap[i]=new AI_OPERATOR();
90 		searchmap[i]->used=false;
91 		atackmap[i]=0;
92 	} /* for */
93 
94 	/* Setup the terrains for the new map: */
95 	for(y=0;y<map_h;y++) {
96 		for(x=0;x<map_w;x++) {
97 			fill_zone(discreetmap,map_w*2,MapTerrain(float(x),float(y)),x*2,y*2,2,2);
98 			fill_zone(bk_discreetmap,map_w*2,MapTerrain(float(x),float(y)),x*2,y*2,2,2);
99 		} /* for */
100 	} /* for */
101 
102 	/* Transfer all the buildings to the new map: */
103 	{
104 		List<BUILDING> l;
105 		BUILDING *b;
106 
107 		l.Instance(buildings);
108 		l.Rewind();
109 
110 		while(l.Iterate(b)) {
111 			x=int(b->pos.x/0.5);
112 			y=int(b->pos.y/0.5);
113 			fill_zone(discreetmap,map_w*2,T_BUILDING,x,y,2,2);
114 		} /* while */
115 	}
116 } /* NETHER::AI_precomputations */
117 
118 
AI_deleteprecomputations(void)119 void NETHER::AI_deleteprecomputations(void)
120 {
121 	int i;
122 
123 	delete discreetmap;
124 	discreetmap=0;
125 	delete bk_discreetmap;
126 	bk_discreetmap=0;
127 	for(i=0;i<map_w*2*map_h*2;i++) {
128 		delete searchmap[i];
129 		searchmap[i]=0;
130 	} /* for */
131 	delete searchmap;
132 	searchmap=0;
133 } /* NETHER::AI_deleteprecomputations */
134 
135 
AI_removebuilding(Vector pos)136 void NETHER::AI_removebuilding(Vector pos)
137 {
138 	int i,j;
139 	int x,y;
140 
141 	x=int(pos.x/0.5);
142 	y=int(pos.y/0.5);
143 
144 	for(i=0;i<2;i++) {
145 		for(j=0;j<2;j++) {
146 			discreetmap[(y+j)*(map_w*2)+(x+i)]=bk_discreetmap[(y+j)*(map_w*2)+(x+i)];
147 		} /* for */
148 	} /* for */
149 } /* NETHER::AI_removebuilding */
150 
151 
AI_release(void)152 void NETHER::AI_release(void)
153 {
154 	delete discreetmap;
155 	discreetmap=0;
156 } /* NETHER::AI_release */
157 
158 
AI_newrobot(Vector pos,int owner)159 void NETHER::AI_newrobot(Vector pos,int owner)
160 {
161 	int x,y,dx,dy;
162 
163 	robot_zone(pos,&x,&y,&dx,&dy);
164 	if (owner==0) fill_zone(discreetmap,map_w*2,T_ROBOT,x,y,dx,dy);
165 			 else fill_zone(discreetmap,map_w*2,T_EROBOT,x,y,dx,dy);
166 } /* NETHER::AI_newrobot */
167 
168 
AI_killrobot(Vector pos)169 int NETHER::AI_killrobot(Vector pos)
170 {
171 	int i,j;
172 	int x,y,dx,dy;
173 	int owner;
174 
175 	robot_zone(pos,&x,&y,&dx,&dy);
176 	owner=discreetmap[y*(map_w*2)+x];
177 	for(i=0;i<dx;i++) {
178 		for(j=0;j<dy;j++) {
179 			discreetmap[(y+j)*(map_w*2)+(x+i)]=bk_discreetmap[(y+j)*(map_w*2)+(x+i)];
180 		} /* for */
181 	} /* for */
182 
183 	return owner;
184 } /* NETHER::AI_killrobot */
185 
186 
AI_moverobot(Vector oldpos,Vector newpos,int owner)187 void NETHER::AI_moverobot(Vector oldpos,Vector newpos,int owner)
188 {
189 	AI_killrobot(oldpos);
190 	AI_newrobot(newpos,owner);
191 } /* NETHER::AI_moverobot */
192 
193 
AI_availableoperators(Vector pos,int angle,int traction,List<AI_OPERATOR> * l)194 void NETHER::AI_availableoperators(Vector pos,int angle,int traction,List<AI_OPERATOR> *l)
195 {
196 	int i;
197 	int x,y,dx,dy;
198 	int terrain;
199 	int n_turns;
200 	int dif;
201 	int cost;
202 	AI_OPERATOR *op;
203 
204 	robot_zone(pos,&x,&y,&dx,&dy);
205 
206 	for(i=0;i<4;i++) {
207 		terrain=AI_WorseMapTerrain(x+xd2[i],y+yd2[i],2+xd3[i],2+yd3[i]);
208 		if (terrain<=T_HOLE &&
209 			Walkable(traction,terrain)) {
210 
211 			/* Rotation cost: */
212 			dif=dangle[i]-angle;
213 			if (dif>360) dif-=360;
214 			if (dif<0) dif+=360;
215 			n_turns=0;
216 			if (dif==90 || dif==270) n_turns=1;
217 			if (dif==180) n_turns=2;
218 			{
219 				float tmp=float(RobotRotationSpeed(terrain,traction));
220 				cost=n_turns*int(90/tmp);
221 			}
222 
223 			/* Displacement cost: */
224 			terrain=AI_WorseMapTerrain(x+xd[i],y+yd[i],2,2);
225 			{
226 				float tmp=RobotSpeed(terrain,traction);
227 				cost+=int(0.5/tmp);
228 			}
229 
230 			/* Build a new AI_operator: */
231 			op=new AI_OPERATOR();
232 			op->cost=cost;
233 			op->previous=-1;
234 			op->deadend=false;
235 			if (dif==0) op->first_robotop=ROBOTOP_FORWARD;
236 			if (dif==90) op->first_robotop=ROBOTOP_RIGHT;
237 			if (dif==180) op->first_robotop=ROBOTOP_RIGHT;
238 			if (dif==270) op->first_robotop=ROBOTOP_LEFT;
239 			op->newpos=Vector(pos.x+xd[i]*0.5,pos.y+yd[i]*0.5,pos.z);
240 			l->Add(op);
241 		} /* if */
242 	} /* for */
243 } /* NETHER::AI_availableoperators */
244 
245 
AI_expandoperators(int x,int y,int angle,int traction,int previous,int oldcost,int depth)246 bool NETHER::AI_expandoperators(int x,int y,int angle,int traction,int previous,int oldcost,int depth)
247 {
248 	int newpos;
249 	int i;
250 	int terrain,terrain2;
251 	int n_turns;
252 	int dif;
253 	int cost;
254 	bool deadend=true;
255 
256 	for(i=0;i<4;i++) {
257 		newpos=previous+xd[i]+yd[i]*(map_w*2);
258 		if (newpos!=searchmap[previous]->previous) {
259 			terrain=AI_WorseMapTerrain(x+xd2[i],y+yd2[i],2+xd3[i],2+yd3[i]);
260 			if (terrain<=T_HOLE &&
261 				Walkable(traction,terrain)) {
262 				cost=oldcost;
263 
264 				/* Rotation cost: */
265 				dif=dangle[i]-angle;
266 				if (dif>360) dif-=360;
267 				if (dif<0) dif+=360;
268 				n_turns=0;
269 				if (dif==90 || dif==270) n_turns=1;
270 				if (dif==180) n_turns=2;
271 
272 				terrain2=AI_WorseMapTerrain(x,y,2,2);
273 				cost+=n_turns*int(90/float(RobotRotationSpeed(traction,terrain2)));
274 
275 				/* Displacement cost: */
276 				cost+=int(0.5/RobotSpeed(traction,terrain));
277 
278 				/* Replace the an old operator by a new one: */
279 				if (!searchmap[newpos]->used ||
280 					searchmap[newpos]->cost>cost) {
281 
282 					/* Set the new AI_operator: */
283 					searchmap[newpos]->used=true;
284 					searchmap[newpos]->cost=cost;
285 					searchmap[newpos]->previous=previous;
286 					searchmap[newpos]->deadend=false;
287 					if (dif==0) searchmap[newpos]->first_robotop=ROBOTOP_FORWARD;
288 					if (dif==90) searchmap[newpos]->first_robotop=ROBOTOP_RIGHT;
289 					if (dif==180) searchmap[newpos]->first_robotop=ROBOTOP_RIGHT;
290 					if (dif==270) searchmap[newpos]->first_robotop=ROBOTOP_LEFT;
291 					searchmap[newpos]->newpos=Vector((x+xd[i])*0.5,(y+yd[i])*0.5,0);
292 
293 					/* Continue the search process: */
294 					if (depth>0) {
295 						if (!AI_expandoperators(x+xd[i],y+yd[i],dangle[i],traction,newpos,cost,depth-1)) {
296 							deadend=false;
297 						} /* if */
298 					} else {
299 						deadend=false;
300 					} /* if */
301 				} /* if */
302 			} /* if */
303 		} /* if */
304 	} /* for */
305 
306 	searchmap[previous]->deadend=deadend;
307 
308 	return deadend;
309 } /* NETHER::AI_expandoperators */
310 
311 
AI_searchengine(Vector pos,int angle,int goaltype,Vector goalpos,int traction,int depth)312 int NETHER::AI_searchengine(Vector pos,int angle,int goaltype,Vector goalpos,int traction,int depth)
313 {
314 	int offs;
315 	int x,y,dx,dy;
316 
317 #ifdef _WRITE_REPORT_
318 	fprintf(debug_fp,"Expanding de search tree\n");
319 	fflush(debug_fp);
320 #endif
321 
322 	/* Expand the search tree: */
323 	robot_zone(pos,&x,&y,&dx,&dy);
324 
325 	/* Build a new AI_operator: */
326 	offs=y*(map_w*2)+x;
327 	searchmap[offs]->used=true;
328 	searchmap[offs]->cost=0;
329 	searchmap[offs]->previous=-1;
330 	searchmap[offs]->first_robotop=ROBOTOP_NONE;
331 	searchmap[offs]->newpos=pos;
332 	searchmap[offs]->deadend=false;
333 	AI_expandoperators(x,y,angle,traction,y*(map_w*2)+x,0,depth);
334 
335 #ifdef _WRITE_REPORT_
336 	fprintf(debug_fp,"Expanding de search tree finished\n");
337 	fflush(debug_fp);
338 #endif
339 
340 
341 	/* ADVANCE PROGRAM: */
342 	if (goaltype==PROGRAM_ADVANCE) {
343 		int i,j;
344 		double further;
345 		int mincost;
346 		bool first=true;
347 		AI_OPERATOR *op,*bestop=0;
348 
349 		for(i=-depth;i<depth;i++) {
350 			for(j=-depth;j<depth;j++) {
351 				if ((x+i)>=0 && (x+i)<(map_w*2) &&
352 					(y+j)>=0 && (y+j)<(map_h*2) &&
353 					(i!=0 || j!=0)) {
354 					op=searchmap[(y+j)*(map_w*2)+(x+i)];
355 					if (op->used) {
356 						if (first ||
357 							(op->deadend==bestop->deadend &&
358 							 (op->newpos.y>further ||
359 							  (op->newpos.y==further && op->cost<mincost))) ||
360 							 (!op->deadend && bestop->deadend)) {
361 							bestop=op;
362 							further=op->newpos.y;
363 							mincost=op->cost;
364 							first=false;
365 						} /*if */
366 					} /* if */
367 				} /* if */
368 			} /* for */
369 		} /* for */
370 
371 		if (bestop!=0) {
372 			int rop;
373 			AI_OPERATOR *prev;
374 
375 			prev=bestop;
376 			while(bestop->previous!=-1 && searchmap[bestop->previous]->used) {
377 				prev=bestop;
378 				bestop=searchmap[bestop->previous];
379 			} /* while */
380 			rop=prev->first_robotop;
381 
382 			AI_resetsearch(pos,depth);
383 			return rop;
384 		} else {
385 			AI_resetsearch(pos,depth);
386 			return ROBOTOP_NONE;
387 		} /* if */
388 
389 		AI_resetsearch(pos,depth);
390 		if (bestop!=0) return bestop->first_robotop;
391 				  else return ROBOTOP_NONE;
392 	} /* if */
393 
394 	/* RETREAT PROGRAM: */
395 	if (goaltype==PROGRAM_RETREAT) {
396 		int i,j;
397 		double further;
398 		int mincost;
399 		bool first=true;
400 		AI_OPERATOR *op,*bestop=0;
401 
402 		for(i=-depth;i<depth;i++) {
403 			for(j=-depth;j<depth;j++) {
404 				if ((x+i)>=0 && (x+i)<(map_w*2) &&
405 					(y+j)>=0 && (y+j)<(map_h*2) &&
406 					(i!=0 || j!=0)) {
407 					op=searchmap[(y+j)*(map_w*2)+(x+i)];
408 					if (op->used) {
409 						if (first ||
410 							(op->deadend==bestop->deadend &&
411 							 (op->newpos.y<further ||
412 							  (op->newpos.y==further && op->cost<mincost))) ||
413 							(!op->deadend && bestop->deadend)) {
414 							bestop=op;
415 							further=op->newpos.y;
416 							mincost=op->cost;
417 							first=false;
418 						} /*if */
419 					} /* if */
420 				} /* if */
421 			} /* for */
422 		} /* for */
423 
424 		if (bestop!=0) {
425 			int rop;
426 			AI_OPERATOR *prev;
427 
428 			prev=bestop;
429 			while(bestop->previous!=-1 && searchmap[bestop->previous]->used) {
430 				prev=bestop;
431 				bestop=searchmap[bestop->previous];
432 			} /* while */
433 			rop=prev->first_robotop;
434 
435 			AI_resetsearch(pos,depth);
436 			return rop;
437 		} else {
438 			AI_resetsearch(pos,depth);
439 			return ROBOTOP_NONE;
440 		} /* if */
441 
442 		AI_resetsearch(pos,depth);
443 		if (bestop!=0) return bestop->first_robotop;
444 				  else return ROBOTOP_NONE;
445 	} /* if */
446 
447 	/* CAPTURE PROGRAM: */
448 	if (goaltype==PROGRAM_CAPTURE) {
449 		int i,j;
450 		double closer;
451 		int mincost;
452 		bool first=true;
453 		AI_OPERATOR *op,*bestop=0;
454 
455 #ifdef _WRITE_REPORT_
456 	fprintf(debug_fp,"Search engine for CAPTURE START\n");
457 	fflush(debug_fp);
458 #endif
459 
460 		for(i=-depth;i<depth;i++) {
461 			for(j=-depth;j<depth;j++) {
462 				if ((x+i)>=0 && (x+i)<(map_w*2) &&
463 					(y+j)>=0 && (y+j)<(map_h*2) &&
464 					(i!=0 || j!=0)) {
465 					op=searchmap[(y+j)*(map_w*2)+(x+i)];
466 					if (op->used) {
467 						if (first ||
468 							((op->deadend==bestop->deadend || (op->newpos+Vector(0.5,0.5,0)-goalpos).norma()==0) &&
469 							 ((op->newpos+Vector(0.5,0.5,0)-goalpos).norma()<closer ||
470 							  ((op->newpos+Vector(0.5,0.5,0)-goalpos).norma()==closer && op->cost<mincost))) ||
471 							(!op->deadend && bestop->deadend && closer!=0)) {
472 							bestop=op;
473 							closer=(op->newpos+Vector(0.5,0.5,0)-goalpos).norma();
474 							mincost=op->cost;
475 							first=false;
476 						} /*if */
477 					} /* if */
478 				} /* if */
479 			} /* for */
480 		} /* for */
481 
482 #ifdef _WRITE_REPORT_
483 	fprintf(debug_fp,"Search engine for CAPTURE FINISHED\n");
484 	fflush(debug_fp);
485 #endif
486 
487 		if (bestop!=0) {
488 			int rop;
489 			AI_OPERATOR *prev;
490 
491 			prev=bestop;
492 			while(bestop->previous!=-1 && searchmap[bestop->previous]->used) {
493 				prev=bestop;
494 				bestop=searchmap[bestop->previous];
495 			} /* while */
496 			rop=prev->first_robotop;
497 
498 			AI_resetsearch(pos,depth);
499 			return rop;
500 		} else {
501 			AI_resetsearch(pos,depth);
502 			return ROBOTOP_NONE;
503 		} /* if */
504 
505 		AI_resetsearch(pos,depth);
506 		if (bestop!=0) return bestop->first_robotop;
507 				  else return ROBOTOP_NONE;
508 	} /* if */
509 
510 
511 	/* DESTROY PROGRAM: */
512 	if (goaltype==PROGRAM_DESTROY) {
513 		int i,j;
514 		double closer;
515 		AI_OPERATOR *op;
516 		int mincost,mincost2;
517 		bool first=true,first2=true;
518 		AI_OPERATOR *bestop=0;	/* Best operator to get closer to the nearest robot */
519 		AI_OPERATOR *bestop2=0;	/* Best operator to reach an attaking position		*/
520 
521 		for(i=-depth;i<depth;i++) {
522 			for(j=-depth;j<depth;j++) {
523 				if ((x+i)>=0 && (x+i)<(map_w*2) &&
524 					(y+j)>=0 && (y+j)<(map_h*2) &&
525 					(i!=0 || j!=0)) {
526 					op=searchmap[(y+j)*(map_w*2)+(x+i)];
527 					if (op->used) {
528 						if (first ||
529 							((op->deadend==bestop->deadend || (op->newpos+Vector(0.5,0.5,0)-goalpos).norma()==0) &&
530 							 ((op->newpos+Vector(0.5,0.5,0)-goalpos).norma()<closer ||
531 							  ((op->newpos+Vector(0.5,0.5,0)-goalpos).norma()==closer && op->cost<mincost))) ||
532 							(!op->deadend && bestop->deadend && closer!=0)) {
533 							bestop=op;
534 							closer=(op->newpos+Vector(0.5,0.5,0)-goalpos).norma();
535 							mincost=op->cost;
536 							first=false;
537 						} /*if */
538 						if (atackmap[(y+j)*(map_w*2)+(x+i)]!=0 ||
539 							atackmap[(y+j+1)*(map_w*2)+(x+i)]!=0 ||
540 							atackmap[(y+j)*(map_w*2)+(x+i+1)]!=0 ||
541 							atackmap[(y+j+1)*(map_w*2)+(x+i+1)]!=0) {
542 							if (first2 ||
543 								op->cost<mincost2) {
544 								bestop2=op;
545 								mincost2=op->cost;
546 								first2=false;
547 							} /*if */
548 						} /* if */
549 					} /* if */
550 				} /* if */
551 			} /* for */
552 		} /* for */
553 
554 		/* It's better to reach an attacking position if this is possible: */
555 		if (bestop2!=0) bestop=bestop2;
556 
557 		if (bestop!=0) {
558 			int rop;
559 			AI_OPERATOR *prev;
560 
561 			prev=bestop;
562 			while(bestop->previous!=-1 && searchmap[bestop->previous]->used) {
563 				prev=bestop;
564 				bestop=searchmap[bestop->previous];
565 			} /* while */
566 			rop=prev->first_robotop;
567 
568 			AI_resetsearch(pos,depth);
569 			return rop;
570 		} else {
571 			AI_resetsearch(pos,depth);
572 			return ROBOTOP_NONE;
573 		} /* if */
574 
575 		AI_resetsearch(pos,depth);
576 		if (bestop!=0) return bestop->first_robotop;
577 				  else return ROBOTOP_NONE;
578 	} /* if */
579 
580 	return ROBOTOP_NONE;
581 } /* AI_searchengine */
582 
583 
AI_resetsearch(Vector pos,int depth)584 void NETHER::AI_resetsearch(Vector pos,int depth)
585 {
586 	int i,j;
587 	int x,y,dx,dy;
588 
589 	robot_zone(pos,&x,&y,&dx,&dy);
590 
591 	for(i=-depth;i<depth;i++) {
592 		for(j=-depth;j<depth;j++) {
593 			if ((x+i)>=0 && (x+i)<(map_w*2) &&
594 				(y+j)>=0 && (y+j)<(map_h*2)) {
595 				searchmap[(y+j)*(map_w*2)+(x+i)]->used=false;
596 			} /* if */
597 		} /* for */
598 	} /* for */
599 
600 } /* AI_resetsearch */
601 
602 
AI_WorseMapTerrain(int x,int y,int dx,int dy)603 int NETHER::AI_WorseMapTerrain(int x,int y,int dx,int dy)
604 {
605 	int t=T_GRASS,t2;
606 	int i,j;
607 
608 	for(i=0;i<dx;i++) {
609 		for(j=0;j<dy;j++) {
610 			if (x+i<0 || x+i>=map_w*2 ||
611 				y+j<0 || y+j>=map_h*2) return T_OUT;
612 			t2=discreetmap[(y+j)*(map_w*2)+x+i];
613 			if (t2>t) t=t2;
614 		} /* if */
615 	} /* for */
616 
617 	return t;
618 } /* NETHER::AI_WorseMapTerrain */
619 
620 
AI_program_advance(int amount,Vector pos,int angle,int traction,bool electronics,int player,bool * pieces)621 int NETHER::AI_program_advance(int amount,Vector pos,int angle,int traction,bool electronics,int player,bool *pieces)
622 {
623 	/* First of all, delete the robot from the discreet map: */
624 	int op=ROBOTOP_NONE;
625 	int type;
626 	List<AI_OPERATOR> l;
627 	Vector tmp_goal;
628 
629 	op=AI_program_stopdefend(&tmp_goal,pos,angle,traction,electronics,player,pieces);
630 	if (op!=ROBOTOP_NONE) return op;
631 
632 	type=AI_killrobot(pos);
633 
634 	AI_availableoperators(pos,angle,traction,&l);
635 
636 	if (!l.EmptyP()) {
637 		/* Choose one operator: */
638 		AI_OPERATOR *aiop;
639 
640 		if (electronics) {
641 			op=AI_searchengine(pos,angle,PROGRAM_ADVANCE,Vector(0,0,0),traction,WE_SEARCH_DEPTH);
642 		} else {
643 			if ((rand()%4)!=0) {
644 				op=AI_searchengine(pos,angle,PROGRAM_ADVANCE,Vector(0,0,0),traction,WOE_SEARCH_DEPTH);
645 			} else {
646 				AI_rankoperators_advance(&l);
647 				aiop=AI_chooseoperator(&l,8);
648 				op=aiop->first_robotop;
649 			} /* if */
650 		} /* if */
651 	} /* if */
652 
653 	/* Reconstruct the decreet map: */
654 	if (type==T_ROBOT) AI_newrobot(pos,0);
655 				  else AI_newrobot(pos,2);
656 
657 	return op;
658 } /* NETHER::AI_program_advance */
659 
660 
AI_program_retreat(int amount,Vector pos,int angle,int traction,bool electronics,int player,bool * pieces)661 int NETHER::AI_program_retreat(int amount,Vector pos,int angle,int traction,bool electronics,int player,bool *pieces)
662 {
663 	/* First of all, delete the robot from the discreet map: */
664 	int op=ROBOTOP_NONE;
665 	int type;
666 	List<AI_OPERATOR> l;
667 	Vector tmp_goal;
668 
669 	op=AI_program_stopdefend(&tmp_goal,pos,angle,traction,electronics,player,pieces);
670 	if (op!=ROBOTOP_NONE) return op;
671 
672 	type=AI_killrobot(pos);
673 
674 	AI_availableoperators(pos,angle,traction,&l);
675 
676 	if (!l.EmptyP()) {
677 		/* Choose one operator: */
678 		AI_OPERATOR *aiop;
679 
680 		if (electronics) {
681 			op=AI_searchengine(pos,angle,PROGRAM_RETREAT,Vector(0,0,0),traction,WE_SEARCH_DEPTH);
682 		} else {
683 			if ((rand()%4)!=0) {
684 				op=AI_searchengine(pos,angle,PROGRAM_RETREAT,Vector(0,0,0),traction,WOE_SEARCH_DEPTH);
685 			} else {
686 				AI_rankoperators_retreat(&l);
687 				aiop=AI_chooseoperator(&l,8);
688 				op=aiop->first_robotop;
689 			} /* if */
690 		} /* if */
691 	} /* if */
692 
693 	/* Reconstruct the decreet map: */
694 	if (type==T_ROBOT) AI_newrobot(pos,0);
695 				  else AI_newrobot(pos,1);
696 
697 	return op;
698 } /* NETHER::AI_program_retreat */
699 
700 
AI_program_capture(int goal,Vector * program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool * pieces)701 int NETHER::AI_program_capture(int goal,Vector *program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool *pieces)
702 {
703 	/* First of all, delete the robot from the discreet map: */
704 	int op=ROBOTOP_NONE;
705 	int type;
706 	List<AI_OPERATOR> l;
707 
708 #ifdef _WRITE_REPORT_
709 	fprintf(debug_fp,"AI_program_capture START\n");
710 	fflush(debug_fp);
711 #endif
712 
713 	op=AI_program_stopdefend(program_goal,pos,angle,traction,electronics,player,pieces);
714 	if (op!=ROBOTOP_NONE) return op;
715 
716 	type=AI_killrobot(pos);
717 
718 #ifdef _WRITE_REPORT_
719 	fprintf(debug_fp,"Searching available operators\n");
720 	fflush(debug_fp);
721 #endif
722 
723 	AI_availableoperators(pos,angle,traction,&l);
724 
725 	if (!l.EmptyP()) {
726 		/* Choose one operator: */
727 		AI_OPERATOR *aiop;
728 
729 #ifdef _WRITE_REPORT_
730 	fprintf(debug_fp,"Seeking a goal\n");
731 	fflush(debug_fp);
732 #endif
733 
734 		{
735 			/* Seek a goal: */
736 			List<BUILDING> l;
737 			BUILDING *b;
738 			bool anygoal=false;
739 			float distance,minimumdistance;
740 
741 			*program_goal=Vector(-1,-1,-1);
742 
743 			l.Instance(buildings);
744 			l.Rewind();
745 			while(l.Iterate(b)) {
746 				if (goal==P_PARAM_WARBASES &&
747 					b->type==B_WARBASE && b->owner!=player &&
748 					AI_WorseMapTerrain(int((b->pos.x+2.0)/0.5),int(b->pos.y/0.5),2,2)<=T_HOLE) {
749 					distance=float(((b->pos+Vector(2.5,0.5,0))-pos).norma());
750 					if (!anygoal || distance<minimumdistance) {
751 						anygoal=true;
752 						minimumdistance=distance;
753 						*program_goal=b->pos+Vector(2.5,0.5,0);
754 					} /* if */
755 				} /* if */
756 				if (goal==P_PARAM_NFACTORIES &&
757 					(b->type==B_FACTORY_ELECTRONICS ||
758 					 b->type==B_FACTORY_NUCLEAR ||
759 					 b->type==B_FACTORY_PHASERS ||
760 					 b->type==B_FACTORY_MISSILES ||
761 					 b->type==B_FACTORY_CANNONS ||
762 					 b->type==B_FACTORY_CHASSIS) && b->owner==0 &&
763 					AI_WorseMapTerrain(int((b->pos.x+1.0)/0.5),int(b->pos.y/0.5),2,2)<=T_HOLE) {
764 					distance=float(((b->pos+Vector(1.5,0.5,0))-pos).norma());
765 					if (!anygoal || distance<minimumdistance) {
766 						anygoal=true;
767 						minimumdistance=distance;
768 						*program_goal=b->pos+Vector(1.5,0.5,0);
769 					} /* if */
770 				} /* if */
771 				if (goal==P_PARAM_EFACTORIES &&
772 					(b->type==B_FACTORY_ELECTRONICS ||
773 					 b->type==B_FACTORY_NUCLEAR ||
774 					 b->type==B_FACTORY_PHASERS ||
775 					 b->type==B_FACTORY_MISSILES ||
776 					 b->type==B_FACTORY_CANNONS ||
777 					 b->type==B_FACTORY_CHASSIS) && b->owner!=0 && b->owner!=player &&
778 					AI_WorseMapTerrain(int((b->pos.x+1.0)/0.5),int(b->pos.y/0.5),2,2)<=T_HOLE) {
779 					distance=float(((b->pos+Vector(1.5,0.5,0))-pos).norma());
780 					if (!anygoal || distance<minimumdistance) {
781 						anygoal=true;
782 						minimumdistance=distance;
783 						*program_goal=b->pos+Vector(1.5,0.5,0);
784 					} /* if */
785 				} /* if */
786 			} /* while */
787 		}
788 
789 #ifdef _WRITE_REPORT_
790 	fprintf(debug_fp,"Searhing a plan to reach the goal\n");
791 	fflush(debug_fp);
792 #endif
793 
794 		if (program_goal->x!=-1 &&
795 			(*program_goal)!=pos) {
796 			if (electronics) {
797 				op=AI_searchengine(pos,angle,PROGRAM_CAPTURE,*program_goal,traction,WE_SEARCH_DEPTH);
798 			} else {
799 				if ((rand()%4)!=0) {
800 					op=AI_searchengine(pos,angle,PROGRAM_CAPTURE,*program_goal,traction,WOE_SEARCH_DEPTH);
801 				} else {
802 					AI_rankoperators_capture(&l,*program_goal);
803 					aiop=AI_chooseoperator(&l,8);
804 					op=aiop->first_robotop;
805 				} /* if */
806 			} /* if */
807 		} /* if */
808 	} /* if */
809 
810 	/* Reconstruct the decreet map: */
811 	if (type==T_ROBOT) AI_newrobot(pos,0);
812 				  else AI_newrobot(pos,1);
813 
814 #ifdef _WRITE_REPORT_
815 	fprintf(debug_fp,"AI_program_capture FINISHED\n");
816 	fflush(debug_fp);
817 #endif
818 
819 	return op;
820 } /* NETHER::AI_program_capture */
821 
822 
AI_RealShotPaths(int x,int y,int player,int persistence)823 int NETHER::AI_RealShotPaths(int x,int y,int player,int persistence)
824 {
825 	int rsp=0;
826 	int i;
827 //	int persistence=CANNON_PERSISTENCE;
828 
829 	for(i=2;i<int((persistence*BULLET_SPEED)/0.5)+2 && (x+i<map_w*2);i++) {
830 		if (discreetmap[x+i+y*(map_w*2)]==T_BUILDING ||
831 			discreetmap[x+i+(y+1)*(map_w*2)]==T_BUILDING) break;
832 		if (player==1) {
833 			if (discreetmap[x+i+y*(map_w*2)]==T_ROBOT ||
834 				discreetmap[x+i+(y+1)*(map_w*2)]==T_ROBOT) break;
835 			if (discreetmap[x+i+y*(map_w*2)]==T_EROBOT ||
836 				discreetmap[x+i+(y+1)*(map_w*2)]==T_EROBOT) {
837 				rsp|=1;
838 				break;
839 			} /* if */
840 		} else {
841 			if (discreetmap[x+i+y*(map_w*2)]==T_EROBOT ||
842 				discreetmap[x+i+(y+1)*(map_w*2)]==T_EROBOT) break;
843 			if (discreetmap[x+i+y*(map_w*2)]==T_ROBOT ||
844 				discreetmap[x+i+(y+1)*(map_w*2)]==T_ROBOT) {
845 				rsp|=1;
846 				break;
847 			} /* if */
848 		} /* if */
849 	} /* for */
850 
851 	for(i=1;i<int((persistence*BULLET_SPEED)/0.5)+1 && (x-i>=0);i++) {
852 		if (discreetmap[x-i+y*(map_w*2)]==T_BUILDING ||
853 			discreetmap[x-i+(y+1)*(map_w*2)]==T_BUILDING) break;
854 		if (player==1) {
855 			if (discreetmap[x-i+y*(map_w*2)]==T_ROBOT ||
856 				discreetmap[x-i+(y+1)*(map_w*2)]==T_ROBOT) break;
857 			if (discreetmap[x-i+y*(map_w*2)]==T_EROBOT ||
858 				discreetmap[x-i+(y+1)*(map_w*2)]==T_EROBOT) {
859 				rsp|=4;
860 				break;
861 			} /* if */
862 		} else {
863 			if (discreetmap[x-i+y*(map_w*2)]==T_EROBOT ||
864 				discreetmap[x-i+(y+1)*(map_w*2)]==T_EROBOT) break;
865 			if (discreetmap[x-i+y*(map_w*2)]==T_ROBOT ||
866 				discreetmap[x-i+(y+1)*(map_w*2)]==T_ROBOT) {
867 				rsp|=4;
868 				break;
869 			} /* if */
870 		} /* if */
871 	} /* for */
872 
873 	for(i=2;i<int((persistence*BULLET_SPEED)/0.5)+2 && (y+i<map_h*2);i++) {
874 		if (discreetmap[x+(y+i)*(map_w*2)]==T_BUILDING ||
875 			discreetmap[(x+1)+(y+i)*(map_w*2)]==T_BUILDING) break;
876 		if (player==1) {
877 			if (discreetmap[x+(y+i)*(map_w*2)]==T_ROBOT ||
878 				discreetmap[(x+1)+(y+i)*(map_w*2)]==T_ROBOT) break;
879 			if (discreetmap[x+(y+i)*(map_w*2)]==T_EROBOT ||
880 				discreetmap[(x+1)+(y+i)*(map_w*2)]==T_EROBOT) {
881 				rsp|=2;
882 				break;
883 			} /* if */
884 		} else {
885 			if (discreetmap[x+(y+i)*(map_w*2)]==T_EROBOT ||
886 				discreetmap[(x+1)+(y+i)*(map_w*2)]==T_EROBOT) break;
887 			if (discreetmap[x+(y+i)*(map_w*2)]==T_ROBOT ||
888 				discreetmap[(x+1)+(y+i)*(map_w*2)]==T_ROBOT) {
889 				rsp|=2;
890 				break;
891 			} /* if */
892 		} /* if */
893 	} /* for */
894 
895 	for(i=1;i<int((persistence*BULLET_SPEED)/0.5)+1 && (y-i>=0);i++) {
896 		if (discreetmap[x+(y-i)*(map_w*2)]==T_BUILDING ||
897 			discreetmap[(x+1)+(y-i)*(map_w*2)]==T_BUILDING) break;
898 		if (player==1) {
899 			if (discreetmap[x+(y-i)*(map_w*2)]==T_ROBOT ||
900 				discreetmap[(x+1)+(y-i)*(map_w*2)]==T_ROBOT) break;
901 			if (discreetmap[x+(y-i)*(map_w*2)]==T_EROBOT ||
902 				discreetmap[(x+1)+(y-i)*(map_w*2)]==T_EROBOT) {
903 				rsp|=8;
904 				break;
905 			} /* if */
906 		} else {
907 			if (discreetmap[x+(y-i)*(map_w*2)]==T_EROBOT ||
908 				discreetmap[(x+1)+(y-i)*(map_w*2)]==T_EROBOT) break;
909 			if (discreetmap[x+(y-i)*(map_w*2)]==T_ROBOT ||
910 				discreetmap[(x+1)+(y-i)*(map_w*2)]==T_ROBOT) {
911 				rsp|=8;
912 				break;
913 			} /* if */
914 		} /* if */
915 	} /* for */
916 
917 	return rsp;
918 } /* NETHER::AI_RealShotPaths */
919 
920 
AI_program_destroy(int goal,Vector * program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool * pieces)921 int NETHER::AI_program_destroy(int goal,Vector *program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool *pieces)
922 {
923 	/* First of all, delete the robot from the discreet map: */
924 	int op=ROBOTOP_NONE;
925 	int type=AI_killrobot(pos);
926 	List<AI_OPERATOR> lops;
927 
928 	AI_availableoperators(pos,angle,traction,&lops);
929 
930 	if (!lops.EmptyP()) {
931 		/* Choose one operator: */
932 		AI_OPERATOR *aiop;
933 
934 		if (goal!=P_PARAM_ROBOTS) {
935 			/* Seek a goal: */
936 			List<BUILDING> l;
937 			BUILDING *b;
938 			bool anygoal=false;
939 			float distance,minimumdistance;
940 
941 			*program_goal=Vector(-1,-1,-1);
942 
943 			l.Instance(buildings);
944 			l.Rewind();
945 			while(l.Iterate(b)) {
946 				if (goal==P_PARAM_WARBASES &&
947 					b->type==B_WARBASE && b->owner!=player &&
948 					AI_WorseMapTerrain(int((b->pos.x+2.0)/0.5),int(b->pos.y/0.5),2,2)<=T_HOLE) {
949 					distance=float(((b->pos+Vector(2.5,0.5,0))-pos).norma());
950 					if (!anygoal || distance<minimumdistance) {
951 						anygoal=true;
952 						minimumdistance=distance;
953 						*program_goal=b->pos+Vector(2.5,0.5,0);
954 					} /* if */
955 				} /* if */
956 				if (goal==P_PARAM_EFACTORIES &&
957 					(b->type==B_FACTORY_ELECTRONICS ||
958 					 b->type==B_FACTORY_NUCLEAR ||
959 					 b->type==B_FACTORY_PHASERS ||
960 					 b->type==B_FACTORY_MISSILES ||
961 					 b->type==B_FACTORY_CANNONS ||
962 					 b->type==B_FACTORY_CHASSIS) && b->owner!=0 && b->owner!=player &&
963 					AI_WorseMapTerrain(int((b->pos.x+1.0)/0.5),int(b->pos.y/0.5),2,2)<=T_HOLE) {
964 					distance=float(((b->pos+Vector(1.5,0.5,0))-pos).norma());
965 					if (!anygoal || distance<minimumdistance) {
966 						anygoal=true;
967 						minimumdistance=distance;
968 						*program_goal=b->pos+Vector(1.5,0.5,0);
969 					} /* if */
970 				} /* if */
971 			} /* while */
972 
973 			if (program_goal->x!=-1 &&
974 				(*program_goal)!=pos) {
975 				if (electronics) {
976 					op=AI_searchengine(pos,angle,PROGRAM_CAPTURE,*program_goal,traction,WE_SEARCH_DEPTH);
977 				} else {
978 					if ((rand()%4)!=0) {
979 						op=AI_searchengine(pos,angle,PROGRAM_CAPTURE,*program_goal,traction,WOE_SEARCH_DEPTH);
980 					} else {
981 						AI_rankoperators_capture(&lops,*program_goal);
982 						aiop=AI_chooseoperator(&lops,8);
983 						op=aiop->first_robotop;
984 					} /* if */
985 				} /* if */
986 			} else {
987 				if (program_goal->x!=-1) op=ROBOTOP_NUCLEAR;
988 			} /* if */
989 
990 		} else {
991 			/* Find the nearest position to destroy an enemy robot: */
992 			List<ROBOT> l;
993 			ROBOT *r;
994 			int x,y,dx,dy,i,j,k;
995 			bool collided;
996 			bool first=true;
997 			float distance;
998 			int persistence=CANNON_PERSISTENCE;
999 			if (pieces[1]) persistence=MISSILE_PERSISTENCE;
1000 
1001 			*program_goal=Vector(-1,-1,-1);
1002 			for(i=0;i<map_w*2*map_h*2;i++) atackmap[i]=0;
1003 
1004 			/* Find the nearest FIRE position: */
1005 			l.Instance(robots[2-player]);
1006 			l.Rewind();
1007 			while(l.Iterate(r)) {
1008 				if (first ||
1009 					(*program_goal-pos).norma()<distance) {
1010 					first=false;
1011 					distance=float((*program_goal-pos).norma());
1012 					*program_goal=r->pos;
1013 				} /* if */
1014 
1015 				robot_zone(r->pos,&x,&y,&dx,&dy);
1016 				for(i=0;i<dx;i++) {
1017 					for(j=0;j<dy;j++) {
1018 						collided=false;
1019 						for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1020 							if (x+i+k<0 || x+i+k>=map_w*2 ||
1021 								y+j<0 || y+j>=map_h*2 ||
1022 								discreetmap[(y+j)*(map_w*2)+(x+i+k)]>3) {
1023 								collided=true;
1024 							} else {
1025 								atackmap[(y+j)*(map_w*2)+(x+i+k)]|=4;
1026 							} /* if */
1027 						} /* for */
1028 
1029 						collided=false;
1030 						for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1031 							if (x+i-k<0 || x+i-k>=map_w*2 ||
1032 								y+j<0 || y+j>=map_h*2 ||
1033 								discreetmap[(y+j)*(map_w*2)+(x+i-k)]>3) {
1034 								collided=true;
1035 							} else {
1036 								atackmap[(y+j)*(map_w*2)+(x+i-k)]|=1;
1037 							} /* if */
1038 						} /* for */
1039 
1040 						collided=false;
1041 						for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1042 							if (x+i<0 || x+i>=map_w*2 ||
1043 								y+j+k<0 || y+j+k>=map_h*2 ||
1044 								discreetmap[(y+j+k)*(map_w*2)+(x+i)]>3) {
1045 								collided=true;
1046 							} else {
1047 								atackmap[(y+j+k)*(map_w*2)+(x+i)]|=8;
1048 							} /* if */
1049 						} /* for */
1050 
1051 						collided=false;
1052 						for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1053 							if (x+i<0 || x+i>=map_w*2 ||
1054 								y+j-k<0 || y+j-k>=map_h*2 ||
1055 								discreetmap[(y+j-k)*(map_w*2)+(x+i)]>3) {
1056 								collided=true;
1057 							} else {
1058 								atackmap[(y+j-k)*(map_w*2)+(x+i)]|=2;
1059 							} /* if */
1060 						} /* for */
1061 					} /* for */
1062 				} /* for */
1063 			} /* while */
1064 
1065 			if (!first) {
1066 				robot_zone(pos,&x,&y,&dx,&dy);
1067 				if ((atackmap[y*(map_w*2)+x]!=0 ||
1068 					atackmap[(y+1)*(map_w*2)+x]!=0 ||
1069 					atackmap[y*(map_w*2)+x+1]!=0 ||
1070 					atackmap[(y+1)*(map_w*2)+x+1]!=0)) {
1071 					int prsp=0,mrsp=0,crsp=0,rsp=0;
1072 					if (pieces[2]) prsp=AI_RealShotPaths(x,y,player,PHASER_PERSISTENCE);
1073 					if (pieces[1]) mrsp=AI_RealShotPaths(x,y,player,MISSILE_PERSISTENCE);
1074 					if (pieces[0]) crsp=AI_RealShotPaths(x,y,player,CANNON_PERSISTENCE);
1075 					rsp=prsp|mrsp|crsp;
1076 
1077 					if (rsp!=0) {
1078 						int dirmask=0;
1079 						if (angle==0) dirmask=1;
1080 						if (angle==90) dirmask=2;
1081 						if (angle==180) dirmask=4;
1082 						if (angle==270) dirmask=8;
1083 						if ((rsp&dirmask)!=0) {
1084 							if ((prsp&dirmask)!=0) {
1085 								op=ROBOTOP_PHASERS;
1086 							} else {
1087 								if ((mrsp&dirmask)!=0) {
1088 									op=ROBOTOP_MISSILES;
1089 								} else {
1090 									op=ROBOTOP_CANNONS;
1091 								} /* if */
1092 							} /* if */
1093 						} else {
1094 							dirmask*=2;
1095 							if (dirmask>=16) dirmask=1;
1096 							if ((rsp&dirmask)!=0) {
1097 								op=ROBOTOP_RIGHT;
1098 							} else {
1099 								op=ROBOTOP_LEFT;
1100 							} /* if */
1101 						} /* if */
1102 					} else {
1103 						if (electronics) {
1104 							op=AI_searchengine(pos,angle,PROGRAM_DESTROY,*program_goal,traction,WE_SEARCH_DEPTH);
1105 						} else {
1106 							if ((rand()%4)!=0) {
1107 								op=AI_searchengine(pos,angle,PROGRAM_DESTROY,*program_goal,traction,WOE_SEARCH_DEPTH);
1108 							} else {
1109 								AI_rankoperators_capture(&lops,*program_goal);
1110 								aiop=AI_chooseoperator(&lops,8);
1111 								op=aiop->first_robotop;
1112 							} /* if */
1113 						} /* if */
1114 					} /* if */
1115 				} else {
1116 					if (electronics) {
1117 						op=AI_searchengine(pos,angle,PROGRAM_DESTROY,*program_goal,traction,WE_SEARCH_DEPTH);
1118 					} else {
1119 						if ((rand()%4)!=0) {
1120 							op=AI_searchengine(pos,angle,PROGRAM_DESTROY,*program_goal,traction,WOE_SEARCH_DEPTH);
1121 						} else {
1122 							AI_rankoperators_capture(&lops,*program_goal);
1123 							aiop=AI_chooseoperator(&lops,8);
1124 							op=aiop->first_robotop;
1125 						} /* if */
1126 					} /* if */
1127 				} /* if */
1128 			} else {
1129 				/* There are no enemy robots: */
1130 				op=ROBOTOP_NONE;
1131 			} /* if */
1132 		} /* if */
1133 	} /* if */
1134 
1135 	/* Reconstruct the decreet map: */
1136 	if (type==T_ROBOT) AI_newrobot(pos,0);
1137 				  else AI_newrobot(pos,1);
1138 
1139 	return op;
1140 } /* NETHER::AI_program_destroy */
1141 
1142 
AI_program_stopdefend(Vector * program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool * pieces)1143 int NETHER::AI_program_stopdefend(Vector *program_goal,Vector pos,int angle,int traction,bool electronics,int player,bool *pieces)
1144 {
1145 	/* First of all, delete the robot from the discreet map: */
1146 	int op=ROBOTOP_NONE;
1147 	int type=AI_killrobot(pos);
1148 	List<AI_OPERATOR> lops;
1149 
1150 	AI_availableoperators(pos,angle,traction,&lops);
1151 
1152 	if (!lops.EmptyP()) {
1153 		/* Choose one operator: */
1154 
1155 		/* Find the nearest position to destroy an enemy robot: */
1156 		List<ROBOT> l;
1157 		ROBOT *r;
1158 		int x,y,dx,dy,i,j,k;
1159 		bool collided;
1160 		int persistence=CANNON_PERSISTENCE;
1161 		if (pieces[1]) persistence=MISSILE_PERSISTENCE;
1162 
1163 		*program_goal=Vector(-1,-1,-1);
1164 		for(i=0;i<map_w*2*map_h*2;i++) atackmap[i]=0;
1165 
1166 		/* Find the nearest FIRE position: */
1167 		l.Instance(robots[2-player]);
1168 		l.Rewind();
1169 		while(l.Iterate(r)) {
1170 			robot_zone(r->pos,&x,&y,&dx,&dy);
1171 			for(i=0;i<dx;i++) {
1172 				for(j=0;j<dy;j++) {
1173 					collided=false;
1174 					for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1175 						if (x+i+k<0 || x+i+k>=map_w*2 ||
1176 							y+j<0 || y+j>=map_h*2 ||
1177 							discreetmap[(y+j)*(map_w*2)+(x+i+k)]>3) {
1178 							collided=true;
1179 						} else {
1180 							atackmap[(y+j)*(map_w*2)+(x+i+k)]|=4;
1181 						} /* if */
1182 					} /* for */
1183 
1184 					collided=false;
1185 					for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1186 						if (x+i-k<0 || x+i-k>=map_w*2 ||
1187 							y+j<0 || y+j>=map_h*2 ||
1188 							discreetmap[(y+j)*(map_w*2)+(x+i-k)]>3) {
1189 							collided=true;
1190 						} else {
1191 							atackmap[(y+j)*(map_w*2)+(x+i-k)]|=1;
1192 						} /* if */
1193 					} /* for */
1194 
1195 					collided=false;
1196 					for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1197 						if (x+i<0 || x+i>=map_w*2 ||
1198 							y+j+k<0 || y+j+k>=map_h*2 ||
1199 							discreetmap[(y+j+k)*(map_w*2)+(x+i)]>3) {
1200 							collided=true;
1201 						} else {
1202 							atackmap[(y+j+k)*(map_w*2)+(x+i)]|=8;
1203 						} /* if */
1204 					} /* for */
1205 
1206 					collided=false;
1207 					for(k=1;!collided && k<int((persistence*BULLET_SPEED)/0.5);k++) {
1208 						if (x+i<0 || x+i>=map_w*2 ||
1209 							y+j-k<0 || y+j-k>=map_h*2 ||
1210 							discreetmap[(y+j-k)*(map_w*2)+(x+i)]>3) {
1211 							collided=true;
1212 						} else {
1213 							atackmap[(y+j-k)*(map_w*2)+(x+i)]|=2;
1214 						} /* if */
1215 					} /* for */
1216 				} /* for */
1217 			} /* for */
1218 		} /* while */
1219 
1220 
1221 		if (!robots[2-player].EmptyP()) {
1222 			robot_zone(pos,&x,&y,&dx,&dy);
1223 			if ((atackmap[y*(map_w*2)+x]!=0 ||
1224 				atackmap[(y+1)*(map_w*2)+x]!=0 ||
1225 				atackmap[y*(map_w*2)+x+1]!=0 ||
1226 				atackmap[(y+1)*(map_w*2)+x+1]!=0)) {
1227 				int prsp=0,mrsp=0,crsp=0,rsp=0;
1228 				if (pieces[2]) prsp=AI_RealShotPaths(x,y,player,PHASER_PERSISTENCE);
1229 				if (pieces[1]) mrsp=AI_RealShotPaths(x,y,player,MISSILE_PERSISTENCE);
1230 				if (pieces[0]) crsp=AI_RealShotPaths(x,y,player,CANNON_PERSISTENCE);
1231 				rsp=prsp|mrsp|crsp;
1232 
1233 				if (rsp!=0) {
1234 					int dirmask=0;
1235 
1236 					/* This is just to make the program not to think that the robot doesn't have any goal: */
1237 					*program_goal=Vector(0,0,0);
1238 
1239 					if (angle==0) dirmask=1;
1240 					if (angle==90) dirmask=2;
1241 					if (angle==180) dirmask=4;
1242 					if (angle==270) dirmask=8;
1243 					if ((rsp&dirmask)!=0) {
1244 						if ((prsp&dirmask)!=0) {
1245 							op=ROBOTOP_PHASERS;
1246 						} else {
1247 							if ((mrsp&dirmask)!=0) {
1248 								op=ROBOTOP_MISSILES;
1249 							} else {
1250 								op=ROBOTOP_CANNONS;
1251 							} /* if */
1252 						} /* if */
1253 					} else {
1254 						dirmask*=2;
1255 						if (dirmask>=16) dirmask=1;
1256 						if ((rsp&dirmask)!=0) {
1257 							op=ROBOTOP_RIGHT;
1258 						} else {
1259 							op=ROBOTOP_LEFT;
1260 						} /* if */
1261 					} /* if */
1262 				} else {
1263 					/* There are no enemy robots at sight: */
1264 					op=ROBOTOP_NONE;
1265 				} /* if */
1266 			} else {
1267 				/* There are no enemy robots at sight: */
1268 				op=ROBOTOP_NONE;
1269 			} /* if */
1270 		} else {
1271 			/* There are no enemy robots: */
1272 			op=ROBOTOP_NONE;
1273 		} /* if */
1274 
1275 	} /* if */
1276 
1277 	/* Reconstruct the decreet map: */
1278 	if (type==T_ROBOT) AI_newrobot(pos,0);
1279 				  else AI_newrobot(pos,1);
1280 
1281 	return op;
1282 } /* NETHER::AI_program_stopdefend */
1283 
1284 
AI_rankoperators_advance(List<AI_OPERATOR> * l)1285 void NETHER::AI_rankoperators_advance(List<AI_OPERATOR> *l)
1286 {
1287 	AI_OPERATOR *op1,*op2;
1288 	LLink<AI_OPERATOR> *p1,*p2;
1289 	bool changes;
1290 
1291 	/* Bubble sort: */
1292 	do {
1293 		changes=false;
1294 		p1=p2=0;
1295 		l->Rewind();
1296 		while(!l->EndP()) {
1297 			p1=p2;
1298 			p2=l->GetPos();
1299 			if (p1!=0 && p2!=0) {
1300 				op1=p1->GetObj();
1301 				op2=p2->GetObj();
1302 				if ((op2->newpos.y>op1->newpos.y) ||
1303 					(op2->newpos.y==op1->newpos.y && op2->cost<op1->cost)) {
1304 					p1->Setobj(op2);
1305 					p2->Setobj(op1);
1306 					changes=true;
1307 				} /* if */
1308 			} /* if */
1309 			l->Next();
1310 		} /* while */
1311 	}while(changes);
1312 
1313 } /* NETHER::AI_rankoperators_advance */
1314 
1315 
AI_rankoperators_retreat(List<AI_OPERATOR> * l)1316 void NETHER::AI_rankoperators_retreat(List<AI_OPERATOR> *l)
1317 {
1318 	AI_OPERATOR *op1,*op2;
1319 	LLink<AI_OPERATOR> *p1,*p2;
1320 	bool changes;
1321 
1322 	/* Bubble sort: */
1323 	do {
1324 		changes=false;
1325 		p1=p2=0;
1326 		l->Rewind();
1327 		while(!l->EndP()) {
1328 			p1=p2;
1329 			p2=l->GetPos();
1330 			if (p1!=0 && p2!=0) {
1331 				op1=p1->GetObj();
1332 				op2=p2->GetObj();
1333 				if ((op2->newpos.y<op1->newpos.y) ||
1334 					(op2->newpos.y==op1->newpos.y && op2->cost<op1->cost)) {
1335 					p1->Setobj(op2);
1336 					p2->Setobj(op1);
1337 					changes=true;
1338 				} /* if */
1339 			} /* if */
1340 			l->Next();
1341 		} /* while */
1342 	}while(changes);
1343 
1344 } /* NETHER::AI_rankoperators_retreat */
1345 
1346 
AI_rankoperators_capture(List<AI_OPERATOR> * l,Vector goal)1347 void NETHER::AI_rankoperators_capture(List<AI_OPERATOR> *l,Vector goal)
1348 {
1349 	AI_OPERATOR *op1,*op2;
1350 	LLink<AI_OPERATOR> *p1,*p2;
1351 	bool changes;
1352 	float dist1 = 0;
1353 	float dist2 = 0;
1354 	int c1,c2;
1355 
1356 #ifdef _WRITE_REPORT_
1357 	fprintf(debug_fp,"Rank operators START\n");
1358 	fflush(debug_fp);
1359 #endif
1360 
1361 #ifdef _WRITE_REPORT_
1362 	fprintf(debug_fp,"Rank operators START\n");
1363 	fflush(debug_fp);
1364 #endif
1365 
1366 	/* Bubble sort: */
1367 	do {
1368 		changes=false;
1369 		p1=p2=0;
1370 		l->Rewind();
1371 		while(!l->EndP()) {
1372 			p1=p2;
1373 			p2=l->GetPos();
1374 			if (p1!=0 && p2!=0) {
1375 				op1=p1->GetObj();
1376 				op2=p2->GetObj();
1377 				dist1 = (op1->newpos-goal).norma();
1378 				dist2 = (op2->newpos-goal).norma();
1379 				c1=(0.1)<(dist1-dist2);
1380 				c2=0;
1381 				if ((0.1)>(dist1-dist2) &&
1382 					(-0.1)<(dist1-dist2)) c2=op2->cost<op1->cost;
1383 				if (c1 || c2) {
1384 
1385 #ifdef _WRITE_REPORT_
1386 		fprintf(debug_fp,"Change: (%.16f,%i) <> (%.16f,%i) %i %i\n",dist1,op1->cost,dist2,op2->cost,c1,c2);
1387 		fflush(debug_fp);
1388 #endif
1389 					p1->Setobj(op2);
1390 					p2->Setobj(op1);
1391 					changes=true;
1392 				} /* if */
1393 			} /* if */
1394 			l->Next();
1395 		} /* while */
1396 	}while(changes);
1397 
1398 #ifdef _WRITE_REPORT_
1399 	fprintf(debug_fp,"Rank operators FINISHED\n");
1400 	fflush(debug_fp);
1401 #endif
1402 
1403 } /* NETHER::AI_rankoperators_capture */
1404 
1405 
AI_chooseoperator(List<AI_OPERATOR> * l,int factor)1406 AI_OPERATOR *NETHER::AI_chooseoperator(List<AI_OPERATOR> *l,int factor)
1407 {
1408 	if (factor==0) {
1409 		l->Rewind();
1410 		return l->GetObj();
1411 	} else {
1412 		l->Rewind();
1413 		while(!l->LastP() && (rand()%factor)==0) l->Next();
1414 		return l->GetObj();
1415 	} /* if */
1416 } /* NETHER::AI_chooseoperator */
1417 
1418 
AI_robothere(Vector pos)1419 int  NETHER::AI_robothere(Vector pos)
1420 {
1421 	int x,y;
1422 	int robot;
1423 
1424 	x=int(pos.x/0.5);
1425 	y=int(pos.y/0.5);
1426 
1427 	robot=discreetmap[y*(map_w*2)+x];
1428 
1429 	if (robot!=T_ROBOT && robot!=T_EROBOT) robot=0;
1430 
1431 	return robot;
1432 } /* AI_robothere */
1433 
1434 
1435