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