1 /*
2  * XPilot NG, a multiplayer space war game.
3  *
4  * Copyright (C) 1991-2001 by
5  *
6  *      Bj�rn Stabell        <bjoern@xpilot.org>
7  *      Ken Ronny Schouten   <ken@xpilot.org>
8  *      Bert Gijsbers        <bert@xpilot.org>
9  *      Dick Balaska         <dick@xpilot.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25 
26 /* Robot code originally submitted by Maurice Abraham. */
27 /* Rewrite started by Karsten Siegmund - in progress */
28 #include "xpserver.h"
29 
30 #define ROB_LOOK_AH		2
31 
32 #define WITHIN(NOW,THEN,DIFF) (NOW<=THEN && (THEN-NOW)<DIFF)
33 
34 /*
35  * Flags for the suibot (well, default...) robots being in different modes (or moods).
36  */
37 #define RM_ROBOT_IDLE         	(1 << 2)
38 #define RM_EVADE_LEFT         	(1 << 3)
39 #define RM_EVADE_RIGHT          (1 << 4)
40 #define RM_ROBOT_CLIMB          (1 << 5)
41 #define RM_HARVEST            	(1 << 6)
42 #define RM_ATTACK             	(1 << 7)
43 #define RM_TAKE_OFF           	(1 << 8)
44 #define RM_CANNON_KILL		(1 << 9)
45 #define RM_REFUEL		(1 << 10)
46 #define RM_NAVIGATE		(1 << 11)
47 
48 /* long term modes */
49 #define FETCH_TREASURE		(1 << 0)
50 #define TARGET_KILL		(1 << 1)
51 #define NEED_FUEL		(1 << 2)
52 
53 /*
54  * Prototypes for methods of the suibot.
55  */
56 static void Robot_suibot_round_tick(void);
57 static void Robot_suibot_create(player_t *pl, char *str);
58 static void Robot_suibot_go_home(player_t *pl);
59 static void Robot_suibot_play(player_t *pl);
60 static void Robot_suibot_set_war(player_t *pl, int victim_id);
61 static int Robot_suibot_war_on_player(player_t *pl);
62 static void Robot_suibot_message(player_t *pl, const char *str);
63 static void Robot_suibot_destroy(player_t *pl);
64 static void Robot_suibot_invite(player_t *pl, player_t *inviter);
65        int Robot_suibot_setup(robot_type_t *type_ptr);
66 
67 
68 
69 
70 /*
71  * The robot type structure for the suibot - contains the functions
72  * that will be called from robot.c
73  */
74 static robot_type_t robot_suibot_type = {
75     "suibot",
76     Robot_suibot_round_tick,
77     Robot_suibot_create,
78     Robot_suibot_go_home,
79     Robot_suibot_play,
80     Robot_suibot_set_war,
81     Robot_suibot_war_on_player,
82     Robot_suibot_message,
83     Robot_suibot_destroy,
84     Robot_suibot_invite
85 };
86 
87 
88 /*
89  * Local static variables
90  */
91 static double	Visibility_distance;
92 static double	Max_enemy_distance;
93 
94 /*
95  * The only thing we export from this file.
96  * A function to initialize the robot type structure
97  * with our name and the pointers to our action routines.
98  *
99  * Return 0 if all is OK, anything else will ignore this
100  * robot type forever.
101  */
Robot_suibot_setup(robot_type_t * type_ptr)102 int Robot_suibot_setup(robot_type_t *type_ptr)
103 {
104     /* Just init the type structure. */
105 
106     *type_ptr = robot_suibot_type;
107 
108     return 0;
109 }
110 
111 /*
112  * Private functions.
113  */
114 static bool Check_robot_evade(player_t *pl, int mine_i, int ship_i);
115 static bool Detect_ship(player_t *pl, player_t *ship);
116 static int Rank_item_value(player_t *pl, enum Item itemtype);
117 static bool Ball_handler(player_t *pl);
118 static void Robot_move_randomly(player_t *pl);
119 
120 
121 /*
122  * Function to cast from player structure to robot data structure.
123  * This isolates casts (aka. type violations) to a few places.
124  */
Robot_suibot_get_data(player_t * pl)125 static robot_default_data_t *Robot_suibot_get_data(player_t *pl)
126 {
127     return (robot_default_data_t *)pl->robot_data_ptr->private_data;
128 }
129 
130 /*
131  * Create the suibot.
132  */
Robot_suibot_create(player_t * pl,char * str)133 static void Robot_suibot_create(player_t *pl, char *str)
134 {
135     robot_default_data_t *my_data;
136 
137     if (!(my_data = XMALLOC(robot_default_data_t, 1))) {
138 	error("no mem for default robot");
139 	End_game();
140     }
141 
142     pl->turnspeed = 0; /* we play with "mouse" */
143     pl->turnresistance = 0;
144 
145     my_data->robot_mode      = RM_TAKE_OFF;
146     my_data->robot_count     = 0;
147     my_data->robot_lock      = LOCK_NONE;
148     my_data->robot_lock_id   = 0;
149 
150     my_data->longterm_mode	= 0;
151 
152     pl->robot_data_ptr->private_data = (void *)my_data;
153 }
154 
155 /*
156  * A suibot is placed on its homebase.
157  */
Robot_suibot_go_home(player_t * pl)158 static void Robot_suibot_go_home(player_t *pl)
159 {
160     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
161 
162     my_data->robot_mode      = RM_TAKE_OFF;
163     my_data->longterm_mode   = 0;
164 }
165 
166 /*
167  * A default robot is declaring war (or resetting war).
168  */
Robot_suibot_set_war(player_t * pl,int victim_id)169 static void Robot_suibot_set_war(player_t *pl, int victim_id)
170 {
171     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
172 
173     if (victim_id == NO_ID)
174 	CLR_BIT(my_data->robot_lock, LOCK_PLAYER);
175     else {
176 	my_data->robot_lock_id = victim_id;
177 	SET_BIT(my_data->robot_lock, LOCK_PLAYER);
178     }
179 }
180 
181 /*
182  * Return the id of the player a default robot has war against (or NO_ID).
183  */
Robot_suibot_war_on_player(player_t * pl)184 static int Robot_suibot_war_on_player(player_t *pl)
185 {
186     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
187 
188     if (BIT(my_data->robot_lock, LOCK_PLAYER))
189 	return my_data->robot_lock_id;
190     else
191 	return NO_ID;
192 }
193 
194 /*
195  * A default robot receives a message.
196  */
Robot_suibot_message(player_t * pl,const char * message)197 static void Robot_suibot_message(player_t *pl, const char *message)
198 {
199     UNUSED_PARAM(pl); UNUSED_PARAM(message);
200 }
201 
202 /*
203  * A default robot is destroyed.
204  */
Robot_suibot_destroy(player_t * pl)205 static void Robot_suibot_destroy(player_t *pl)
206 {
207     XFREE(pl->robot_data_ptr->private_data);
208 }
209 
210 /*
211  * A default robot is asked to join an alliance
212  */
Robot_suibot_invite(player_t * pl,player_t * inviter)213 static void Robot_suibot_invite(player_t *pl, player_t *inviter)
214 {
215     int war_id = Robot_suibot_war_on_player(pl), i;
216     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
217     double limit;
218     bool we_accept = true;
219 
220     if (pl->alliance != ALLIANCE_NOT_SET) {
221 	/* if there is a human in our alliance, they should decide
222 	   let robots refuse in this case */
223 	for (i = 0; i < NumPlayers; i++) {
224 	    player_t *pl_i = Player_by_index(i);
225 
226 	    if (Player_is_human(pl_i) && Players_are_allies(pl, pl_i)) {
227 		we_accept = false;
228 		break;
229 	    }
230 	}
231 	if (!we_accept) {
232 	    Refuse_alliance(pl, inviter);
233 	    return;
234 	}
235     }
236     limit = MAX(ABS( Get_Score(pl) / MAX((my_data->attack / 10), 10)),
237 		my_data->defense);
238     if (inviter->alliance == ALLIANCE_NOT_SET) {
239 	/* don't accept players we are at war with */
240 	if (inviter->id == war_id)
241 	    we_accept = false;
242 	/* don't accept players who are not active */
243 	if (!Player_is_active(inviter))
244 	    we_accept = false;
245 	/* don't accept players with scores substantially lower than ours */
246 	else if ( Get_Score(inviter) < ( Get_Score(pl) - limit))
247 	    we_accept = false;
248     }
249     else {
250 	double avg_score = 0;
251 	int member_count = Get_alliance_member_count(inviter->alliance);
252 
253 	for (i = 0; i < NumPlayers; i++) {
254 	    player_t *pl_i = Player_by_index(i);
255 	    if (pl_i->alliance == inviter->alliance) {
256 		if (pl_i->id == war_id) {
257 		    we_accept = false;
258 		    break;
259 		}
260 		avg_score +=  Get_Score(pl_i);
261 	    }
262 	}
263 	if (we_accept) {
264 	    avg_score = avg_score / member_count;
265 	    if (avg_score < ( Get_Score(pl) - limit))
266 		we_accept = false;
267 	}
268     }
269     if (we_accept)
270 	Accept_alliance(pl, inviter);
271     else
272 	Refuse_alliance(pl, inviter);
273 }
274 
decide_travel_dir(player_t * pl)275 static inline int decide_travel_dir(player_t *pl)
276 {
277     double gdir;
278 
279     if (pl->velocity <= 0.2) {
280 	vector_t grav = World_gravity(pl->pos);
281 
282 	gdir = findDir(grav.x, grav.y);
283     } else
284 	gdir = findDir(pl->vel.x, pl->vel.y);
285 
286     return MOD2((int) (gdir + 0.5), RES);
287 }
288 
289 
290 static void Robot_take_off_from_base(player_t *pl);
291 
Robot_take_off_from_base(player_t * pl)292 static void Robot_take_off_from_base(player_t *pl)
293 {
294   robot_default_data_t  *my_data = Robot_suibot_get_data(pl);
295   /*Function that could do specific things when robot takes off*/
296 
297   Robot_move_randomly(pl);
298   Thrust(pl, true);
299 
300 
301   if((rfrac())<0.1 ){
302     my_data->robot_mode = RM_ATTACK;
303   }
304 }
305 
306 
307 /*KS: let robot "play mouse" */
308 static void Robot_set_pointing_direction(player_t *pl,double direction);
309 
Robot_set_pointing_direction(player_t * pl,double direction)310 static void Robot_set_pointing_direction(player_t *pl,double direction)
311 {
312   robot_default_data_t	*my_data = Robot_suibot_get_data(pl);
313   int turnvel;
314 
315     if(pl->turnspeed != 0 | pl->turnresistance != 0) End_game();
316 
317 
318    turnvel = (direction - pl->float_dir);
319    pl->turnvel = turnvel;
320 }
321 
322 /*KS: describe func here.....*/
323 /* void Obj_pos_set(object *obj, int cx, int cy); */
324 
325 /* void Obj_pos_set(object *obj, int cx, int cy){ */
326 /*     struct _objposition		*pos = (struct _objposition *)&obj->pos; */
327 
328 
329 
330 /*     pos->cx = cx; */
331 /*     pos->x = CLICK_TO_PIXEL(cx); */
332 /*     pos->bx = pos->x / BLOCK_SZ; */
333 /*     pos->cy = cy; */
334 /*     pos->y = CLICK_TO_PIXEL(cy); */
335 /*     pos->by = pos->y / BLOCK_SZ; */
336 /*     obj->prevpos.x = obj->pos.x; */
337 /*     obj->prevpos.y = obj->pos.y; */
338 
339 /* } */
340 
341 struct collans {
342     int line;
343     int point;
344     clvec_t moved;
345 };
346 
347 static bool Wall_in_between_points(int cx1, int cy1, int cx2, int cy2);
Wall_in_between_points(int cx1,int cy1,int cx2,int cy2)348 static bool Wall_in_between_points(int cx1, int cy1, int cx2, int cy2){ /* Wall between two given points?*/
349 
350   struct collans answer;
351   move_t mv;
352   mv.delta.cx = WRAP_DCX(cx2 - cx1);
353   mv.delta.cy = WRAP_DCY(cy2 - cy1);
354   mv.start.cx = WRAP_XCLICK(cx1);
355   mv.start.cy = WRAP_YCLICK(cy1);
356   mv.obj   = NULL;
357   mv.hitmask  = NONBALL_BIT;
358 
359   while (mv.delta.cx || mv.delta.cy) {
360     Move_point(&mv, &answer);
361     if (answer.line != -1)
362       return true;
363     mv.start.cx = WRAP_XCLICK(mv.start.cx + answer.moved.cx);
364     mv.start.cy = WRAP_YCLICK(mv.start.cy + answer.moved.cy);
365     mv.delta.cx -= answer.moved.cx;
366     mv.delta.cy -= answer.moved.cy;
367   }
368   return false;
369 
370 }
371 
372 
373 bool Robot_evade_shot(player_t *pl);
374 
375 typedef struct {
376   double hit_time;
377   double sqdistance;
378 } object_proximity_t;
379 
380 
381 static bool Get_object_proximity();
Get_object_proximity(player_t * pl,object_t * shot,double sqmaxdist,int maxtime,object_proximity_t * object_proximity)382 static bool Get_object_proximity(player_t *pl, object_t *shot, double sqmaxdist,int maxtime, object_proximity_t *object_proximity){
383    /* get square of closest distance between player and object
384     * compare with sqmaxdist and maxtime and return sqdistance and time
385     * if both are smaller than the maximal wanted values
386     */
387    double delta_velx, delta_vely, delta_x, delta_y, sqdistance;
388    double time_until_closest, shortest_hit_time;
389 
390   /* calculate relative positions and velocities */
391   delta_velx=( shot->vel.x -  pl->vel.x );
392   delta_vely=( shot->vel.y -  pl->vel.y );
393   delta_x=   WRAP_DCX( shot->pos.cx - pl->pos.cx );
394   delta_y=   WRAP_DCY( shot->pos.cy - pl->pos.cy );
395 
396   /* prevent possible division by 0 */
397   if(delta_velx == 0 && delta_vely == 0)
398     return false;
399 
400   /* get time of encounter from deviation of distance function */
401   time_until_closest =
402     -( delta_x * delta_velx + delta_y * delta_vely) /
403     ((sqr(delta_velx) + sqr(delta_vely)));
404 
405   /* ignore if there is enough time to deal with this object  later */
406   if((time_until_closest < 0) || (time_until_closest > maxtime))
407     /*option instead of fixed value: options.dodgetime))*/
408     return;
409 
410   /* get the square of the distance */
411   sqdistance =
412     (sqr(delta_velx) + sqr(delta_vely)) * sqr(time_until_closest)  +
413     2 * (delta_velx * delta_x + delta_vely * delta_y) * time_until_closest +
414     sqr(delta_x) + sqr(delta_y);
415 
416   if(sqdistance>sqmaxdist)
417     return false;
418 
419   object_proximity->hit_time=time_until_closest;
420   object_proximity->sqdistance=sqdistance;
421 
422   return true;
423 
424 }
425 
426 
Robot_evade_shot(player_t * pl)427 bool Robot_evade_shot(player_t *pl){
428 
429 /*  change to use   struct dangerous_shot_data *shotsarray; */
430   int j;
431   object_t *shot, **obj_list;
432   int  obj_count;
433   long killing_shots;
434   //  player_t *opponent;
435 
436       killing_shots = KILLING_SHOTS;
437     if (options.treasureCollisionMayKill)
438         killing_shots |= OBJ_BALL;
439     if (options.wreckageCollisionMayKill)
440         killing_shots |= OBJ_WRECKAGE;
441     if (options.asteroidCollisionMayKill)
442         killing_shots |= OBJ_ASTEROID;
443     if (!options.allowShields)
444 	killing_shots |=  OBJ_PLAYER;
445 
446     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
447 
448     const int                   max_objs = 1000;
449     int shot_dist;
450     double time_shot_closest, shortest_hit_time;
451     double delta_velx, delta_vely, delta_x, delta_y, sqdistance;
452     double sqship_sz;
453     Cell_get_objects(pl->pos, (int)(Visibility_distance / BLOCK_SZ),
454 		     max_objs, &obj_list, &obj_count);
455 
456     /*This is the viewable area for players:
457     #include "connection.h"
458     int hori_blocks, vert_blocks;
459     hori_blocks = (view_width + (BLOCK_SZ - 1)) / (2 * BLOCK_SZ);
460     vert_blocks = (view_height + (BLOCK_SZ - 1)) / (2 * BLOCK_SZ);
461     if (NumObjs >= options.cellGetObjectsThreshold)
462         Cell_get_objects(pl->pos, MAX(hori_blocks, vert_blocks),
463                          num_object_shuffle, &obj_list, &obj_count);*/
464 
465 
466 
467     shortest_hit_time=10000;
468     int closest_shot = -1;
469     int dangerous_shots[obj_count];
470     double dangerous_shots_time[obj_count];
471     int dangerous_shots_ind =0;
472     double dangerous_shots_distance[obj_count];
473 
474     for (j = 0; j < obj_count; j++) { /*for .. obj_count*/
475 
476 	shot = obj_list[j];
477 
478 	/* Get rid of most objects */
479 	if (!BIT(shot->type, killing_shots ))
480 	    continue;
481 
482 	/* calculate relative positions and velocities */
483 	delta_velx=( shot->vel.x -  pl->vel.x );
484 	delta_vely=( shot->vel.y -  pl->vel.y );
485 	delta_x=   WRAP_DCX( shot->pos.cx - pl->pos.cx );
486 	delta_y=   WRAP_DCY( shot->pos.cy - pl->pos.cy );
487 
488 	/* prevent possible division by 0 */
489 	if(delta_velx == 0 && delta_vely == 0)
490 	    continue;
491 
492 	/* get time of encounter from deviation of distance function */
493 	time_shot_closest =
494 	    -( delta_x * delta_velx + delta_y * delta_vely) /
495 	    ((sqr(delta_velx) + sqr(delta_vely)));
496 
497 	/* ignore if there is enough time to dodge this shot in a later frame*/
498 	if((time_shot_closest < 0) || (time_shot_closest > 1000))
499 	    /*option instead of fixed value: options.dodgetime))*/
500 	    continue;
501 
502 	/* look if shot will hit (compare squares of distances and shipsize) */
503 	sqdistance =
504 	    (sqr(delta_velx) + sqr(delta_vely)) * sqr(time_shot_closest)
505 	    + 2 * (delta_velx * delta_x + delta_vely * delta_y)
506 	    * time_shot_closest
507 	    + sqr(delta_x) + sqr(delta_y);
508 
509 #define SQ_SHIP_SZ_11 sqr(1.1 * PIXEL_TO_CLICK(SHIP_SZ))
510 #define SQ_SHIP_SZ_25 sqr(2.5 * PIXEL_TO_CLICK(SHIP_SZ))
511 
512 	if(sqdistance > SQ_SHIP_SZ_25)
513 	    continue;
514 
515 	/* ignore shots that will hit a wall before it hits us */
516 	if(Wall_in_between_points(
517 	       shot->pos.cx ,
518 	       shot->pos.cy ,
519 	       shot->pos.cx + time_shot_closest * shot->vel.x,
520 	       shot->pos.cy + time_shot_closest * shot->vel.y
521 	       ))
522 	    continue;
523 
524 	/*
525 	 * store shot id and time for every shot that hits
526 	 * within the given time
527 	 */
528 
529 	dangerous_shots[dangerous_shots_ind]=j;
530 	dangerous_shots_time[dangerous_shots_ind]=time_shot_closest;
531         dangerous_shots_distance[dangerous_shots_ind]=sqdistance;
532 	dangerous_shots_ind++;
533 
534 	if(sqdistance > SQ_SHIP_SZ_11)
535 	    continue;
536 
537 	if(shortest_hit_time > time_shot_closest){
538 	    shortest_hit_time = time_shot_closest;
539 	    closest_shot=j;
540 	}
541     }
542 
543     /* return, if nothing will hit */
544     if((closest_shot == -1)) {return false; }
545 
546 //printf("Time for closest shot (%i): %.2f\n",closest_shot,shortest_hit_time);
547 //for (j = 0; j < dangerous_shots_ind  ; j++) { /*for .. dangerous_shots_ind*/
548 //printf("dangerous shot %i (%i) impact in %.2f, distance: %.2f\n",j,
549 //dangerous_shots[j],dangerous_shots_time[j],
550  //sqrt(dangerous_shots_distance[j]));
551  //}
552 
553     /* get vector from center of ship to shot at hit time */
554     /* this is orthogonal to delta_vel(x,y) */
555     shot = obj_list[closest_shot];
556     delta_velx=( shot->vel.x -  pl->vel.x );
557     delta_vely=( shot->vel.y -  pl->vel.y );
558     delta_x=   WRAP_DCX( shot->pos.cx - pl->pos.cx );
559     delta_y=   WRAP_DCY( shot->pos.cy - pl->pos.cy );
560 
561 
562 double hit_dx, hit_dy;
563 hit_dx = delta_x + shortest_hit_time * delta_velx;
564 hit_dy = delta_y + shortest_hit_time * delta_vely;
565 double evade_x=-hit_dx;
566 double evade_y=-hit_dy;
567 double direction_evade1;
568 
569 /*printf("delta_x: %.2f delta_y: %.2f evade_x: %.2f evade_y: %.2f product: %.2f\n",
570 	delta_velx, delta_vely, evade_x, evade_y, delta_velx*evade_x+delta_vely*evade_y);*/
571 //XXX
572 //printf("direction hit: %.2f  --- ",direction_evade1);
573 
574     /* if the shot hits the exactly the center, use alternate calculation of orthogonal to shot path */
575 /*    double direction_pl,direction_evade1,direction_evade2;
576     double norm_vel= sqrt(sqr(delta_velx)+sqr(delta_vely));
577     double norm_xy = sqrt(sqr(delta_x)+sqr(delta_y));
578     double evade_x = -(delta_velx / norm_vel  + delta_x / norm_xy);
579     double evade_y = -(delta_vely / norm_vel  + delta_y / norm_xy);
580 */
581     direction_evade1 = Wrap_findDir(evade_x, evade_y );
582 
583     /* Change evade by 180� if wall will be in the way in the chosen direction */
584     if(Wall_in_between_points(
585                   pl->pos.cx + time_shot_closest * (pl->vel.x +  pl->power * cos(direction_evade1) / pl->mass),
586                   pl->pos.cy + time_shot_closest * (pl->vel.y +  pl->power * sin(direction_evade1) / pl->mass),
587                   pl->pos.cx ,
588                   pl->pos.cy
589                   )){
590 	direction_evade1+=RES;
591 	//	printf("Wall!\n");
592 	}
593 
594 
595 //printf("direction old: %.2f\n",direction_evade1);
596 
597   Robot_set_pointing_direction(pl, direction_evade1);
598     Thrust(pl, true);
599 
600     return true;
601 
602 }
603 
604 
Robot_move_randomly(player_t * pl)605 void Robot_move_randomly(player_t *pl){
606   double direction;
607 
608   /* Move randomly */
609   if(rfrac()<0.25)
610     pl->turnvel = ((rfrac()*RES)- RES / 2)*0.3;
611 
612   if(pl->velocity > options.maxUnshieldedWallBounceSpeed){ /* not too fast...*/
613 
614     direction= findDir(-pl->vel.x,-pl->vel.y);
615     Robot_set_pointing_direction(pl, direction);
616     Thrust(pl, true);
617     return;
618   }
619 
620   /* Fire, too */
621   if((rfrac())>0.98 ){
622         Fire_normal_shots(pl);
623   }
624   /* Sometimes thrust */
625   if((rfrac())>0.65 )
626     {
627       Thrust(pl, true);
628     }
629   else{
630     Thrust(pl, false);
631     }
632 
633 }
634 
Robot_ram_object(player_t * pl,object_t * object)635 double Robot_ram_object(player_t *pl,object_t *object){
636 
637     double direction;
638     int x,y,x_tgo, y_tgo;
639     double velx, vely; /* relative positions and velocities */
640     double time, delta_time;
641     double sqr_a, sqr_b, sqr_c, b_dot_c, function, deviation;
642     int i=0;
643     int j=0;
644 
645     velx = ( object->vel.x -  pl->vel.x ) * CLICK;
646     vely = ( object->vel.y -  pl->vel.y ) * CLICK;
647     /* multiply with CLICK to get clicks/time, but keep as float */
648     x    = WRAP_DCX( object->pos.cx - pl->pos.cx );
649     y    = WRAP_DCY( object->pos.cy - pl->pos.cy );
650 
651 
652 
653 
654 #define DD false /* debug */
655 
656     /* use squares of length, so sqrt doesnt need to be calculated */
657     sqr_a   = sqr(pl->power / pl->mass * CLICK);       /* acceleration */
658     sqr_b   = sqr(velx)+sqr(vely);  /* velocity     */
659     sqr_c   = sqr(x)+sqr(y);        /* distance     */
660     b_dot_c = velx*x + vely*y;      /* dot product b�c */
661 
662 /*     for (i = 0; i < 500; i++){ */
663 /*       time=i/10.0; */
664 /*       double tmp_x = (int)(x + velx * time); */
665 /*       double tmp_y = (int)(y + vely * time); */
666 
667 /*       double tmp_length= */
668 /* 	abs(LENGTH(tmp_x,tmp_y)- 0.5 * (CLICK * pl->power / pl->mass) * sqr(time)); */
669 /*       if(tmp_length < 3000) */
670 /* 	printf("time %.2f  length %.2f\n",time,tmp_length); */
671 /*     } */
672 
673     time = 1;
674     //time=sqrt(2*LENGTH(x,y)/(pl->power/pl->mass));
675     /* exact: time=sqrt(2*LENGTH(x,y)/pl->power*pl->mass);*/
676     delta_time=5000; /* set high value so convercence criterion isnt met */
677 
678     if(DD){printf("time %.3f\n",time);}
679 
680     for (i = 0; i < 30; i++) { /* allow only limited amount of iterations */
681 
682 	/* Newton iterations to get the time of impact */
683 	function =
684 	    -0.25 * sqr_a * sqr(sqr(time))
685 	    + sqr_b * sqr(time)
686 	    + 2 * b_dot_c * time
687 	    + sqr_c;
688 	deviation=
689 	    -sqr_a * sqr(time) * time
690 	    + 2 * sqr_b * time
691 	    + 2 * b_dot_c;
692 
693 	delta_time=function/deviation;
694 
695         if(delta_time > time){
696 	  if(j>2)
697 	    break; /* setting time=0 failed, give up */
698 	  time*=0;
699 	  j++;
700 	}else{
701 	  time-=delta_time;
702 	}
703 
704 
705 	if(DD)
706 	    printf("time %.3f function: %e delta_time %E\n",time, function, delta_time);
707 
708 
709 	 int tmp_x = (int)(x + velx * time);
710 	 int tmp_y = (int)(y + vely * time);
711 
712 
713 //	if( abs(delta_time)< 0.001* abs(time))
714       if(abs(function) < 10)
715 //	if(abs(LENGTH(tmp_x,tmp_y)- 0.5 * (CLICK * pl->power/pl->mass) * sqr(time)) < 10 )
716 	    break;
717     }
718 
719     if(DD){
720 	printf("time: %.2f\n",time);
721 	printf("test1: %.4f %.4f %.4f\n",
722 	       - 0.25 * sqr_a * sqr(sqr(time)),
723 	       + sqr_b * sqr(time)
724 	       + 2 * b_dot_c * time
725 	       + sqr_c,
726 	       -sqr_a/4 * sqr(sqr(time))
727 	       + sqr_b * sqr(time)
728 	       + 2 * b_dot_c * time
729 	       + sqr_c
730 	    );
731     }
732 /*
733 
734     velx=( object->vel.x -  pl->vel.x );
735     vely=( object->vel.y -  pl->vel.y );
736     x=   WRAP_DCX( object->pos.cx - pl->pos.cx );
737     y=   WRAP_DCY( object->pos.cy - pl->pos.cy );
738 */
739     /* prevent possible division by 0 */
740 /*    if(velx == 0 || vely == 0)
741 	time =0;
742     else
743 	time =
744 	    -( x * velx + y * vely) /
745 	    ((sqr(velx) + sqr(vely)));
746 */
747     if(DD){
748     printf("x %i y %.i\n",x,y);
749     printf("velx %.2f * time %.2f = %.2f\n",velx,time,velx*time);
750     }
751 
752 
753     x_tgo = (int)(x + velx * time);
754     y_tgo = (int)(y + vely * time);
755 
756     if(DD) {
757 	printf("nx %i ny %i, length %.3f\n",x_tgo,y_tgo,LENGTH(x_tgo,y_tgo));
758 	printf("            difference: %.3f\n",LENGTH(x_tgo,y_tgo)- 0.5 * sqrt(sqr_a) * sqr(time));
759 
760     }
761 
762     /*
763      * if vector to ball at time-to-go (tgo) points away from the ball
764      * something is wrong - better use the vector of current LOS (line of sight)
765      */
766 //    if(sqr_c > sqr(x+x_tgo)+sqr(y+y_tgo)){
767 //	x_tgo=x;
768 //	y_tgo=y;
769 //	}
770 
771 
772     direction=(Wrap_cfindDir(x_tgo,y_tgo));
773 
774     if(DD)
775     printf("                         direction %.2f, direction %i\n",direction, (int)direction);
776 
777     Robot_set_pointing_direction(pl, direction);
778     Thrust(pl, true);
779     return time;
780 }
781 
782 
783 #define NO_DIR -1
784 void Robot_find_shooting_dir(player_t *pl, player_t *pl_to_suicide);
Robot_find_shooting_dir(player_t * pl,player_t * pl_to_suicide)785 void Robot_find_shooting_dir(player_t *pl, player_t *pl_to_suicide){
786 
787 
788 
789 }
790 
791 void Robot_attack_player(player_t *pl, player_t *opponent);
Robot_attack_player(player_t * pl,player_t * opponent)792 void Robot_attack_player(player_t *pl, player_t *opponent){/*attack_player*/
793 
794     int        dcx,dcy;
795     double     direction;
796     double     velx,vely;
797     double     tmp_a,tmp_b,tmp_c,t1,t,t2;
798 
799     /* check if we can fire or have to wait because of repeat rate */
800     /* same check as in Fire_normal_shots(pl)                      */
801     if (frame_time
802 	<= pl->shot_time + options.fireRepeatRate
803 	- timeStep + 1e-3){
804 	Robot_ram_object(pl, OBJ_PTR(opponent));
805 	return;
806     }
807 
808 
809     dcx   = WRAP_DCX(opponent->pos.cx - pl->pos.cx);
810     dcy   = WRAP_DCY(opponent->pos.cy - pl->pos.cy);
811     velx  = (opponent->vel.x - pl->vel.x) * CLICK;
812     vely  = (opponent->vel.y - pl->vel.y) * CLICK;
813 
814 
815     /*Find direction, where a shot will hit a ship with constant velocity*/
816     /* use tmp_vars to try to keep it readable */
817     tmp_a = dcx * velx + dcy * vely;
818 
819     tmp_b = sqr(velx) + sqr(vely) - sqr(options.shotSpeed * CLICK);
820 
821     tmp_c = sqr(tmp_a) - tmp_b * (sqr(dcx) + sqr(dcy));
822 
823 	t  = -1; /* -1 for no solution */
824 
825 	if( tmp_c >= 0) { /* square-root only if number positive*/
826 
827 	tmp_c = sqrt(tmp_c);
828 
829 	t1 = (-tmp_a - tmp_c) / tmp_b;
830 	t2 = (-tmp_a + tmp_c) / tmp_b;
831 
832 
833 	/* t (=time) must be greater than 0, but as small as possible...
834 	   if problem can't be solved call ram_object*/
835 
836 	if (t1 >= 0 && t2 >= 0) {
837 	    if (t1 > t2){ t = t2;} else {t = t1;}
838 	    Fire_normal_shots(pl);
839 	}
840 	else if( t2 >= 0 ) {t = t2; Fire_normal_shots(pl);}
841 	else if( t1 >= 0 ) {t = t1; Fire_normal_shots(pl);}
842 	}
843 
844 	/* t = -1 for no solution */
845 	if(t<0){
846 	    /* try to get closer */
847 	    Robot_ram_object(pl, OBJ_PTR(opponent));
848 
849 	    if(rfrac() >0.5){ Fire_normal_shots(pl);}
850 	    return;
851 	}
852 
853 #define D2 false
854     if(D2)
855     printf("no:  dcx %i = dcx %i + t %.2f * velx %.2f\n",
856 	   (int)(dcx + t * velx), dcx, t, velx);
857 
858     dcx = (int) (dcx + t * velx);
859     dcy = (int) (dcy + t * vely);
860 
861     /* slightly bias shooting towads where a player thrusts */
862 
863     if(false && rfrac() > 0.75){
864 	dcx = dcx + opponent->acc.x * t * sqr(sqr(rfrac()));
865 	dcy = dcy + opponent->acc.y * t * sqr(sqr(rfrac()));
866 
867 	/* actually, it should be acc * sqr(time);
868 	 * but this is much too much for even relatively
869 	 * small times
870 	 */
871     }
872 
873     direction = findDir((double)dcx,(double)dcy);
874     if(D2)
875       printf("no: dir= %i\n",direction);
876 
877     if(rfrac() > 0.8) /* spread shots */
878       direction += ((rfrac()-0.5 )*10);
879 
880         Robot_set_pointing_direction(pl, direction);
881         Thrust(pl, true);
882 }
883 
884 
885 
886 /*
887  * Calculate minimum of length of hypotenuse in triangle with sides
888  * 'dcx' and 'dcy' and 'min', taking into account wrapping.
889  * Unit is clicks.
890  */
Wrap_length_min(double dcx,double dcy,double min)891 static inline double Wrap_length_min(double dcx, double dcy, double min)
892 {
893     double len;
894 
895     dcx = WRAP_DCX(dcx), dcx = ABS(dcx);
896     if (dcx >= min)
897 	return min;
898     dcy = WRAP_DCY(dcy), dcy = ABS(dcy);
899     if (dcy >= min)
900 	return min;
901 
902     len = LENGTH(dcx, dcy);
903 
904     return MIN(len, min);
905 }
906 
907 
Robotdef_fire_laser(player_t * pl)908 static void Robotdef_fire_laser(player_t *pl)
909 {
910     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
911     double x2, y2, x3, y3, x4, y4, x5, y5;
912     double ship_dist, dir3, dir4, dir5;
913     clpos_t m_gun;
914     player_t *ship;
915 
916     if (BIT(my_data->robot_lock, LOCK_PLAYER)
917 	&& Player_is_active(Player_by_id(my_data->robot_lock_id)))
918 	ship = Player_by_id(my_data->robot_lock_id);
919     else if (BIT(pl->lock.tagged, LOCK_PLAYER))
920 	ship = Player_by_id(pl->lock.pl_id);
921     else
922 	return;
923 
924     /* kps - this should be Player_is_alive() ? */
925     if (!Player_is_active(ship))
926 	return;
927 
928     m_gun = Ship_get_m_gun_clpos(pl->ship, pl->dir);
929     x2 = CLICK_TO_PIXEL(pl->pos.cx) + pl->vel.x
930 	+ CLICK_TO_PIXEL(m_gun.cx);
931     y2 = CLICK_TO_PIXEL(pl->pos.cy) + pl->vel.y
932 	+ CLICK_TO_PIXEL(m_gun.cy);
933     x3 = CLICK_TO_PIXEL(ship->pos.cx) + ship->vel.x;
934     y3 = CLICK_TO_PIXEL(ship->pos.cy) + ship->vel.y;
935 
936     ship_dist = Wrap_length(PIXEL_TO_CLICK(x3 - x2),
937 			    PIXEL_TO_CLICK(y3 - y2)) / CLICK;
938 
939     if (ship_dist >= options.pulseSpeed * options.pulseLife + SHIP_SZ)
940 	return;
941 
942     dir3 = Wrap_findDir(x3 - x2, y3 - y2);
943     Robot_set_pointing_direction(pl, dir3);
944 
945 	SET_BIT(pl->used, HAS_LASER);
946 }
947 
Detect_ship(player_t * pl,player_t * ship)948 static bool Detect_ship(player_t *pl, player_t *ship)
949 {
950     double distance;
951 
952     /* can't go after non-playing ships */
953     if (!Player_is_alive(ship))
954 	return false;
955 
956     /* can't do anything with phased ships */
957     if (Player_is_phasing(ship))
958 	return false;
959 
960     /* trivial */
961     if (pl->visibility[GetInd(ship->id)].canSee)
962 	return true;
963 
964     /*
965      * can't see it, so it must be cloaked
966      * maybe we can detect it's presence from other clues?
967      */
968     distance = Wrap_length(ship->pos.cx - pl->pos.cx,
969 			   ship->pos.cy - pl->pos.cy) / CLICK;
970     /* can't detect ships beyond visual range */
971     if (distance > Visibility_distance)
972 	return false;
973 
974     if (Player_is_thrusting(ship)
975 	&& options.cloakedExhaust)
976 	return true;
977 
978     if (BIT(ship->used, HAS_SHOT)
979 	|| BIT(ship->used, HAS_LASER)
980 	|| Player_is_refueling(ship)
981 	|| Player_is_repairing(ship)
982 	|| Player_uses_connector(ship)
983 	|| Player_uses_tractor_beam(ship))
984 	return true;
985 
986     if (BIT(ship->have, HAS_BALL))
987 	return true;
988 
989     /* the sky seems clear.. */
990     return false;
991 }
992 
993 /*
994  * Determine how important an item is to a given player.
995  * Return one of the following 3 values:
996  */
997 #define ROBOT_MUST_HAVE_ITEM	2	/* must have */
998 #define ROBOT_HANDY_ITEM	1	/* handy */
999 #define ROBOT_IGNORE_ITEM	0	/* ignore */
1000 /*
1001  */
Rank_item_value(player_t * pl,enum Item itemtype)1002 static int Rank_item_value(player_t *pl, enum Item itemtype)
1003 {
1004     robot_default_data_t *my_data = Robot_suibot_get_data(pl);
1005 
1006     if (itemtype == ITEM_AUTOPILOT)
1007 	return ROBOT_IGNORE_ITEM;		/* never useful for robots */
1008     if (pl->item[itemtype] >= world->items[itemtype].limit)
1009 	return ROBOT_IGNORE_ITEM;		/* already full */
1010     if ((IsDefensiveItem(itemtype)
1011 	 && CountDefensiveItems(pl) >= options.maxDefensiveItems)
1012 	|| (IsOffensiveItem(itemtype)
1013 	 && CountOffensiveItems(pl) >= options.maxOffensiveItems))
1014 	return ROBOT_IGNORE_ITEM;
1015     if (itemtype == ITEM_FUEL) {
1016 	if (pl->fuel.sum >= pl->fuel.max * 0.90)
1017 	    return ROBOT_IGNORE_ITEM;		/* already (almost) full */
1018 	else if ((pl->fuel.sum < (BIT(world->rules->mode, TIMING))
1019 		  ? my_data->fuel_l1
1020 		  : my_data->fuel_l2))
1021 	    return ROBOT_MUST_HAVE_ITEM;		/* ahh fuel at last */
1022 	else
1023 	    return ROBOT_HANDY_ITEM;
1024     }
1025     if (BIT(world->rules->mode, TIMING)) {
1026 	switch (itemtype) {
1027 	case ITEM_FUEL:		/* less refuel stops */
1028 	case ITEM_REARSHOT:	/* shoot competitors behind you */
1029 	case ITEM_AFTERBURNER:	/* the more speed the better */
1030 	case ITEM_TRANSPORTER:	/* steal fuel when you overtake someone */
1031 	case ITEM_MINE:		/* blows others off the track */
1032 	case ITEM_ECM:		/* blinded players smash into walls */
1033 	case ITEM_EMERGENCY_THRUST:	/* makes you go really fast */
1034 	case ITEM_EMERGENCY_SHIELD:	/* could be useful when ramming */
1035 	    return ROBOT_MUST_HAVE_ITEM;
1036 	case ITEM_WIDEANGLE:	/* not important in racemode */
1037 	case ITEM_CLOAK:	/* not important in racemode */
1038 	case ITEM_SENSOR:	/* who cares about seeing others? */
1039 	case ITEM_TANK:		/* makes you heavier */
1040 	case ITEM_MISSILE:	/* likely to hit self */
1041 	case ITEM_LASER:	/* cost too much fuel */
1042 	case ITEM_TRACTOR_BEAM:	/* pushes/pulls owner off the track too */
1043 	case ITEM_AUTOPILOT:	/* probably not useful */
1044 	case ITEM_DEFLECTOR:	/* cost too much fuel */
1045 	case ITEM_HYPERJUMP:	/* likely to end up in wrong place */
1046 	case ITEM_PHASING:	/* robots don't know how to use them yet */
1047 	case ITEM_MIRROR:	/* not important in racemode */
1048 	case ITEM_ARMOR:	/* makes you heavier */
1049 	    return ROBOT_IGNORE_ITEM;
1050 	default:		/* unknown */
1051 	    warn("Rank_item_value: unknown item %ld.", itemtype);
1052 	    return ROBOT_IGNORE_ITEM;
1053 	}
1054     } else {
1055 	switch (itemtype) {
1056 	case ITEM_EMERGENCY_SHIELD:
1057 	case ITEM_DEFLECTOR:
1058 	case ITEM_ARMOR:
1059 	    if (BIT(pl->have, HAS_SHIELD))
1060 		return ROBOT_HANDY_ITEM;
1061 	    else
1062 		return ROBOT_MUST_HAVE_ITEM;
1063 
1064 	case ITEM_REARSHOT:
1065 	case ITEM_WIDEANGLE:
1066 	    if (options.maxPlayerShots <= 0
1067 		|| options.shotLife <= 0
1068 		|| !options.allowPlayerKilling)
1069 		return ROBOT_HANDY_ITEM;
1070 	    else
1071 		return ROBOT_MUST_HAVE_ITEM;
1072 
1073 	case ITEM_MISSILE:
1074 	    if (options.maxPlayerShots <= 0
1075 		|| options.shotLife <= 0
1076 		|| !options.allowPlayerKilling)
1077 		return ROBOT_IGNORE_ITEM;
1078 	    else
1079 		return ROBOT_MUST_HAVE_ITEM;
1080 
1081 	case ITEM_MINE:
1082 	case ITEM_CLOAK:
1083 	    return ROBOT_MUST_HAVE_ITEM;
1084 
1085 	case ITEM_LASER:
1086 	    if (options.allowPlayerKilling)
1087 		return ROBOT_MUST_HAVE_ITEM;
1088 	    else
1089 		return ROBOT_HANDY_ITEM;
1090 
1091 	case ITEM_PHASING:	/* robots don't know how to use them yet */
1092 	    return ROBOT_IGNORE_ITEM;
1093 
1094 	default:
1095 	    break;
1096 	}
1097     }
1098     return ROBOT_HANDY_ITEM;
1099 }
1100 
Robot_suibot_play(player_t * pl)1101 static void Robot_suibot_play(player_t *pl)
1102 {
1103   player_t *ship;
1104   int direction;
1105   double distance, ship_dist, enemy_dist, speed, x_speed, y_speed;
1106   int item_dist, mine_dist, item_i, mine_i;
1107   int j, ship_i, item_imp, enemy_i, shoot_time;
1108   bool harvest_checked, evade_checked, navigate_checked;
1109   robot_default_data_t *my_data = Robot_suibot_get_data(pl);
1110 
1111   double ship_dist_closest;
1112   player_t *closest_opponent;
1113   closest_opponent= NULL;
1114   const int maxdist =  1200; /* maximum distance from which to try to pop ball*/
1115   double ball_dist;
1116 
1117   pl->turnspeed = 0;
1118   pl->turnacc = 0;
1119   pl->power = MAX_PLAYER_POWER;
1120 
1121   if(my_data->robot_mode == RM_TAKE_OFF){
1122     Robot_take_off_from_base(pl);
1123     return;
1124   }
1125   /* important goal is not to be shot */
1126   if(Robot_evade_shot(pl)){
1127     return;
1128   }
1129 
1130   /* Try not to crash into walls */
1131 
1132 
1133   if(pl->velocity > options.maxUnshieldedWallBounceSpeed){
1134       double time;
1135       time= (pl->velocity
1136 	     - options.maxUnshieldedWallBounceSpeed)/(pl->power / pl->mass);
1137       time=time*0.05;
1138 
1139       if(Wall_in_between_points(pl->pos.cx,
1140 				pl->pos.cy,
1141 				pl->pos.cx + pl->vel.x * time,
1142 				pl->pos.cy + pl->vel.y * time)) {
1143       direction= (int)findDir(-pl->vel.x, -pl->vel.y);
1144       Robot_set_pointing_direction(pl, direction);
1145       printf("avoiding wall\n");
1146       Thrust(pl, true);
1147       return;
1148       }
1149   }
1150 
1151 
1152       Thrust(pl, false);
1153 
1154   ship_dist_closest= 2* World.hypotenuse;
1155   for (ship_i = 0; ship_i < NumPlayers; ship_i++) {
1156    player_t *ship = Player_by_index(ship_i);
1157     ship_dist =
1158       CLICK_TO_PIXEL((int)
1159 	(Wrap_length((pl->pos.cx - ship->pos.cx),
1160 	       (pl->pos.cy - ship->pos.cy))));
1161 
1162     if(BIT(ship->have, HAS_BALL ))
1163       ship_dist = ship_dist/3.0;
1164     /*
1165      * Player with ball is considered as "much closer"
1166      *
1167      * this is rather arbitrary
1168      * the reasoning goes: dont try to attack player
1169      * with ball who is really far off
1170      * while some other player is really really close
1171      */
1172 
1173     if ((ship->id != pl->id)
1174 	&& Player_is_alive(ship)
1175 	&& ship_dist < ship_dist_closest
1176 	&& (pl->team != ship->team)
1177       	&& ((!BIT(ship->used, HAS_SHIELD))
1178 	    || Wrap_length(ship->pos.cx - pl->pos.cx,
1179 			   ship->pos.cy - pl->pos.cy) < 8000)
1180 	)
1181       {
1182 	ship_dist_closest = ship_dist;
1183 	closest_opponent = ship;
1184       }
1185   }
1186 
1187   if(ship_dist_closest <  maxdist && ! closest_opponent){
1188       char msg[MSG_LEN];
1189       /* if not true, there's a bug */
1190       warn(" Robotdef.c: opponent very close, but variable empty!\n");
1191       sprintf (msg,"Bug: Chasing a non-existant opponent! [%s]",pl->name);
1192       Set_message(msg);
1193       return;
1194   }
1195 
1196   if(ship_dist_closest <  maxdist && BIT(closest_opponent->used, HAS_SHIELD)){
1197       direction = Wrap_cfindDir(-closest_opponent->pos.cx + pl->pos.cx,
1198 				-closest_opponent->pos.cy + pl->pos.cy);
1199       Robot_set_pointing_direction(pl, (int)(abs(direction+0.5)));
1200       Thrust(pl, true);
1201       return;
1202   }
1203 
1204 
1205 
1206 
1207   /* Closest_ball - should be function, but how do I return a ball + a dist?*/
1208 
1209  ballobject_t *closest_ball, *ball;
1210  object_t **obj_list, *object;
1211  //robot_default_data_t *my_data = Robot_suibot_get_data(pl);
1212 
1213  double     closest_ball_dist;
1214  int     i;
1215  int     obj_count;
1216  const int                   max_objs = 1000;
1217 
1218  ball_dist = 2 * maxdist;
1219  closest_ball_dist= 2* maxdist;
1220  closest_ball=NULL;
1221 
1222  Cell_get_objects(pl->pos, (int)(Visibility_distance / BLOCK_SZ),
1223 		  max_objs, &obj_list, &obj_count);
1224 
1225  for (i = 0; i < obj_count; i++) { /*for .. obj_count*/
1226    object = obj_list[i];
1227    if (object->type == OBJ_BALL) {
1228      ball= BALL_PTR(object);
1229      ball_dist = Wrap_length(pl->pos.cx - ball->pos.cx,
1230 			     pl->pos.cy - ball->pos.cy) / CLICK;
1231      if (ball_dist < closest_ball_dist) {
1232        closest_ball_dist = ball_dist;
1233        closest_ball = ball;
1234      }
1235    }
1236  }
1237  ball =  closest_ball;
1238 
1239  if(ball){
1240    if (Wall_in_between_points((pl->pos.cx),(pl->pos.cy),(ball->pos.cx),
1241 			      (ball->pos.cy)))
1242      ball_dist = 2*  World.hypotenuse;
1243  }
1244 
1245 
1246  if(ship_dist_closest <  maxdist
1247     && ship_dist_closest < (2.5 * ball_dist)
1248     && (Wall_in_between_points((pl->pos.cx),
1249 			       (pl->pos.cy),
1250 			       (closest_opponent->pos.cx),
1251 			       (closest_opponent->pos.cy)) == 0)
1252     && (!BIT(pl->have, HAS_BALL))
1253      ) {
1254    Robot_attack_player(pl,closest_opponent);
1255    return;
1256  }
1257 
1258  if( ball
1259      && ball_dist < maxdist
1260      && Wrap_length(ball->pos.cx - ball->ball_treasure->pos.cx,
1261      		    ball->pos.cy - ball->ball_treasure->pos.cy
1262 	 ) > 10000
1263      ){
1264      Robot_ram_object(pl, OBJ_PTR(ball));
1265      return;
1266  }
1267 
1268  /* Helps to get stuck on walls less frequently
1269     10 propably only works ok with framerate of 50 fps
1270     plan: a) make value depend on framerate,
1271     b) use better algorithm than that
1272     ---> probably no problem anymore because of turnpush.
1273     Robots should be able to get free anyways now.
1274  */
1275 
1276  if((pl->last_wall_touch + 11) >= frame_loops) {
1277      direction= (int)findDir(pl->vel.x,pl->vel.y);
1278      Robot_set_pointing_direction(pl, direction);
1279 
1280      Thrust(pl, false);
1281      return;
1282  }
1283 
1284  if((pl->last_wall_touch + 14) >= frame_loops){
1285      direction= (int)findDir(pl->vel.x,pl->vel.y);
1286      Robot_set_pointing_direction(pl, direction);
1287      if(!Wall_in_between_points(pl->pos.cx, pl->pos.cy,
1288 				pl->pos.cx + pl->vel.x * 10,
1289 				pl->pos.cy + pl->vel.y * 10)){
1290 	 Thrust(pl, true);
1291      }
1292  }
1293 
1294 /* nothing sensible to to at the moment */
1295  Robot_move_randomly(pl);
1296 }
1297 
1298 
1299 
1300 /*
1301  * This is called each round.
1302  * It allows us to adjust our file local parameters.
1303  */
1304 
Robot_suibot_round_tick(void)1305 static void Robot_suibot_round_tick(void)
1306 {
1307     double min_visibility = 256.0;
1308     double min_enemy_distance = 512.0;
1309 
1310     /* reduce visibility when there are a lot of robots. */
1311     Visibility_distance = VISIBILITY_DISTANCE;
1312 	/*min_visibility
1313 	+ (((VISIBILITY_DISTANCE - min_visibility)
1314 	    * (NUM_IDS - NumRobots)) / NUM_IDS);*/
1315 
1316 
1317     /* limit distance to allowable enemies. */
1318     Max_enemy_distance = world->hypotenuse;
1319     if (world->hypotenuse > Visibility_distance)
1320 	Max_enemy_distance =  world->hypotenuse;
1321 /*	min_enemy_distance
1322 	    + (((world->hypotenuse - min_enemy_distance)
1323 		* (NUM_IDS - NumRobots)) / NUM_IDS);*/
1324 }
1325