00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023
00024 #include <fcntl.h>
00025 #include <unistd.h>
00026 #include <signal.h>
00027 #include <iostream>
00028 #include <fstream>
00029 #include <math.h>
00030
00031 using namespace std;
00032
00033 #ifdef TIME_WITH_SYS_TIME
00034 # include <sys/time.h>
00035 # include <time.h>
00036 #else
00037 # if HAVE_SYS_TIME_H
00038 # include <sys/time.h>
00039 # else
00040 # include <time.h>
00041 # endif
00042 #endif
00043
00044 #include <sys/resource.h>
00045 #include <sys/stat.h>
00046 #include <stdarg.h>
00047 #include <stdio.h>
00048
00049 #include "Robot.h"
00050 #include "String.h"
00051 #include "ArenaController.h"
00052 #include "ArenaRealTime.h"
00053 #include "ArenaReplay.h"
00054 #include "Various.h"
00055 #include "Options.h"
00056 #include "Wall.h"
00057 #include "Shot.h"
00058 #include "Extras.h"
00059 #include "ArenaWindow.h"
00060
00061 #ifndef NO_GRAPHICS
00062 # include "ScoreWindow.h"
00063 #endif
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 Robot::Robot(const String& filename)
00074 {
00075 velocity = Vector2D(0.0, 0.0);
00076 acceleration = 0.0;
00077 robot_filename = filename;
00078
00079 int nr;
00080 if( ( nr = robot_filename.find( '/', 0, true) ) == -1 )
00081 robot_plain_filename = robot_filename;
00082 else
00083 robot_plain_filename = get_segment(robot_filename, nr+1, -1);
00084
00085
00086 network_robot = false;
00087
00088
00089 plain_robot_name = "";
00090 robot_name = "";
00091 robot_name_uniqueness_number = 0;
00092
00093 extra_air_resistance = 0.0;
00094 process_running = false;
00095
00096 send_usr_signal = false;
00097 signal_to_send = 0;
00098 send_rotation_reached = 0;
00099 alive = false;
00100 dead_but_stats_not_set = false;
00101
00102
00103 has_competed = false;
00104
00105 id = the_arena.increase_robot_count();
00106
00107 instreamp = NULL;
00108 outstreamp = NULL;
00109 pipes[0] = pipes[1] = -1;
00110 pid = -1;
00111 last_drawn_robot_center = Vector2D(infinity,infinity);
00112
00113 use_non_blocking = get_default_non_blocking_state();
00114 }
00115
00116
00117
00118 Robot::Robot(const int r_id, const long int col, const String& name)
00119 {
00120 id = r_id;
00121 robot_name = name;
00122 set_colour( col );
00123
00124 process_running = false;
00125 alive = false;
00126
00127
00128 has_competed = false;
00129
00130 last_drawn_robot_center = Vector2D(infinity,infinity);
00131 radius = the_opts.get_d(OPTION_ROBOT_RADIUS);
00132 }
00133
00134
00135 Robot::~Robot()
00136 {
00137 if( the_arena_controller.is_realtime() )
00138 {
00139 if( is_process_running() ) kill_process_forcefully();
00140 delete_pipes();
00141 }
00142 }
00143
00144 void
00145 Robot::start_process()
00146 {
00147 int pipe_in[2], pipe_out[2];
00148 if (pipe (pipe_in))
00149 Error(true, "Couldn't setup pipe_in for robot " + robot_filename, "Robot::start_process");
00150
00151 if (pipe (pipe_out))
00152 Error(true, "Couldn't setup pipe_out for robot " + robot_filename, "Robot::start_process");
00153
00154 if( (pid = fork()) < 0 )
00155 Error(true, "Couldn't fork childprocess for robot " + robot_filename, "Robot::start_process");
00156
00157 if(pid == 0)
00158 {
00159
00160 close(pipe_out[1]);
00161 dup2(pipe_out[0], STDIN_FILENO);
00162
00163
00164 dup2(pipe_in[1],STDOUT_FILENO);
00165 close(pipe_in[0]);
00166
00167
00168
00169 if( use_non_blocking )
00170 {
00171 int pd_flags;
00172 if( (pd_flags = fcntl(pipe_out[0], F_GETFL, 0)) == -1 )
00173 Error(true, "Couldn't get pd_flags for pipe_out in robot " + robot_filename,
00174 "Robot::start_process, child");
00175 pd_flags |= O_NONBLOCK;
00176 if( fcntl(pipe_out[0], F_SETFL, pd_flags) == -1 )
00177 Error(true, "Couldn't change pd_flags for pipe_out in robot " + robot_filename,
00178 "Robot::start_process, child");
00179
00180
00181 if( (pd_flags = fcntl(pipe_in[1], F_GETFL, 0)) == -1 )
00182 Error(true, "Couldn't get pd_flags for pipe_in in robot " + robot_filename,
00183 "Robot::start_process, child");
00184 pd_flags |= O_NONBLOCK;
00185 if( fcntl(pipe_in[1], F_SETFL, pd_flags) == -1 )
00186 Error(true, "Couldn't change pd_flags for pipe_in in robot " + robot_filename,
00187 "Robot::start_process, child");
00188 }
00189
00190
00191
00192 struct stat filestat;
00193 if( 0 != stat( robot_filename.chars(), &filestat ) )
00194 Error(true, "Couldn't get stats for robot " + robot_filename, "Robot::start_process, child");
00195 if( !S_ISREG( filestat.st_mode) )
00196 Error(true, "Robot file isn't regular, error for robot " + robot_filename,
00197 "Robot::start_process, child");
00198 if( !(filestat.st_mode & S_IXOTH) )
00199 Error(true, "Robot file isn't executable for user, error for robot " + robot_filename,
00200 "Robot::start_process, child");
00201 if( (filestat.st_mode & S_ISUID) )
00202 Error(true, "Set user ID is not allowed, error for robot " + robot_filename,
00203 "Robot::start_process, child");
00204
00205
00206
00207 int old;
00208 if( (old = getpriority (PRIO_PROCESS, 0)) == -1 )
00209 Error(true, "Couldn't get priority for robot " + robot_filename, "Robot::start_process, child");
00210 if( setpriority (PRIO_PROCESS, 0, old + 1) == -1)
00211 Error(true, "Couldn't set priority for robot " + robot_filename, "Robot::start_process, child");
00212
00213
00214
00215 Robot* robotp;
00216
00217 ListIterator<Robot> li;
00218 for( the_arena.get_all_robots_in_sequence()->first(li); li.ok(); li++ )
00219 {
00220 robotp = li();
00221 if( robotp != this ) robotp->delete_pipes();
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 if( execl(robot_filename.chars(), robot_filename.chars(), NULL) == -1 )
00258 Error(true, "Couldn't open robot " + robot_filename, "Robot::start_process, child");
00259
00260 Error(true, "Robot didn't execute, SHOULD NEVER HAPPEN!, error for " + robot_filename,
00261 "Robot::start_process, child");
00262 }
00263 else
00264 {
00265 close(pipe_out[0]);
00266 close(pipe_in[1]);
00267
00268 pipes[0] = pipe_out[1];
00269 pipes[1] = pipe_in[0];
00270
00271
00272 int pd_flags;
00273 if( (pd_flags = fcntl(pipe_in[0], F_GETFL, 0)) == -1 )
00274 Error(true, "Couldn't get pd_flags for pipe_in in robot " + robot_filename,
00275 "Robot::start_process, parent");
00276 pd_flags |= O_NONBLOCK;
00277 if( fcntl(pipe_in[0], F_SETFL, pd_flags) == -1 )
00278 Error(true, "Couldn't change pd_flags for pipe_in in robot " + robot_filename,
00279 "Robot::start_process, parent");
00280 if( (pd_flags = fcntl(pipe_out[1], F_GETFL, 0)) == -1 )
00281 Error(true, "Couldn't get pd_flags for pipe_out in robot " + robot_filename,
00282 "Robot::start_process, parent");
00283 pd_flags |= O_NONBLOCK;
00284 if( fcntl(pipe_out[1], F_SETFL, pd_flags) == -1 )
00285 Error(true, "Couldn't change pd_flags for pipe_out in robot " + robot_filename,
00286 "Robot::start_process, parent");
00287
00288
00289
00290
00291
00292
00293 outstreamp = new boost::fdostream(pipe_out[1]);
00294 instreamp = new boost::fdistream(pipe_in[0]);
00295
00296 }
00297
00298
00299
00300 struct timeval timeout;
00301 timeout.tv_sec = 0;
00302 timeout.tv_usec = 40000;
00303
00304 select(FD_SETSIZE, NULL, NULL, NULL, &timeout);
00305
00306 set_values_at_process_start_up();
00307 }
00308
00309 bool
00310 Robot::is_process_running()
00311 {
00312 return process_running;
00313 }
00314
00315 void
00316 Robot::update_cpu_time_used()
00317 {
00318 if( network_robot || !process_running ) return;
00319
00320 String procfilename = "/proc/" + String(pid) + "/stat";
00321 ifstream procfile(procfilename.chars());
00322 if( !procfile ) return;
00323
00324 char buf[64];
00325
00326
00327 for(int i=0; i<15; i++)
00328 procfile >> buf;
00329
00330
00331 double current_cpu = 0.0;
00332 int jiffies;
00333 for(int i=0; i<4; i++)
00334 {
00335 procfile >> jiffies;
00336 current_cpu += (double)jiffies / 100.0;
00337 }
00338
00339
00340
00341
00342
00343
00344 cpu_used += current_cpu - last_cpu;
00345
00346 last_cpu = current_cpu;
00347 }
00348
00349 void
00350 Robot::reset_cpu_time()
00351 {
00352 if( network_robot ) return;
00353
00354 update_cpu_time_used();
00355 cpu_used = 0;
00356 }
00357
00358 void
00359 Robot::check_process()
00360 {
00361
00362
00363 if( !is_process_running() || !alive || network_robot ) return;
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 update_cpu_time_used();
00382
00383 double tot_time = the_arena.get_total_time() + time_survived_in_sequence;
00384 if( cpu_used > cpu_limit )
00385 {
00386 if( tot_time >= cpu_timeout )
00387 {
00388
00389 reset_cpu_time();
00390 cpu_limit = the_opts.get_d(OPTION_CPU_EXTRA);
00391 cpu_warning_limit = cpu_limit * the_opts.get_d(OPTION_CPU_WARNING_PERCENT);
00392 cpu_timeout = tot_time + the_opts.get_d(OPTION_CPU_PERIOD);
00393 }
00394 else
00395 {
00396 die();
00397
00398
00399 reset_cpu_time();
00400 cpu_limit = the_opts.get_d(OPTION_CPU_START_LIMIT);
00401 cpu_warning_limit = cpu_limit * the_opts.get_d(OPTION_CPU_WARNING_PERCENT);
00402 cpu_timeout = 0.0;
00403 }
00404 }
00405 else if( cpu_used > cpu_warning_limit && tot_time < cpu_timeout )
00406 {
00407 send_message( WARNING, PROCESS_TIME_LOW, String(cpu_limit - cpu_used).chars());
00408 cpu_warning_limit = cpu_limit;
00409 }
00410 }
00411
00412
00413 void
00414 Robot::end_process()
00415 {
00416 send_message(EXIT_ROBOT);
00417 send_signal();
00418 }
00419
00420 void
00421 Robot::send_signal()
00422 {
00423 if( send_usr_signal )
00424 {
00425 if( network_robot )
00426 *outstreamp << "@S" << signal_to_send << endl;
00427 else if( pid > 0 )
00428 kill(pid, signal_to_send);
00429 }
00430 }
00431
00432 void
00433 Robot::kill_process_forcefully()
00434 {
00435 if( network_robot )
00436 *outstreamp << "@K" << endl;
00437 else if( pid > 0 )
00438 kill(pid, SIGKILL);
00439
00440 delete_pipes();
00441 process_running = false;
00442 }
00443
00444 void
00445 Robot::delete_pipes()
00446 {
00447 if( ! network_robot )
00448 {
00449 if( instreamp != NULL ) delete instreamp;
00450 instreamp = NULL;
00451 if( outstreamp != NULL ) delete outstreamp;
00452 outstreamp = NULL;
00453 }
00454
00455 if( pipes[0] != -1 )
00456 {
00457 close(pipes[0]);
00458 pipes[0] = -1;
00459 }
00460 if( pipes[1] != -1 )
00461 {
00462 close(pipes[1]);
00463 pipes[1] = -1;
00464 }
00465 }
00466
00467 void
00468 Robot::live()
00469 {
00470 alive = true;
00471 dead_but_stats_not_set = false;
00472 }
00473
00474 void
00475 Robot::die()
00476 {
00477 if( alive )
00478 {
00479 alive = false;
00480 dead_but_stats_not_set = true;
00481 #ifndef NO_GRAPHICS
00482 if( !no_graphics )
00483 {
00484 the_gui.get_arenawindow_p()->
00485 draw_circle( last_drawn_center, last_drawn_radius,
00486 *(the_gui.get_bg_gdk_colour_p()), true );
00487 last_drawn_robot_center = Vector2D( infinity, infinity );
00488 }
00489 #endif
00490 }
00491 }
00492
00493 void
00494
00495 Robot::set_stats(const int robots_killed_same_time, const bool timeout)
00496 {
00497 dead_but_stats_not_set = false;
00498
00499 int adjust = robots_killed_same_time - 1;
00500 if( timeout ) adjust *= 2;
00501
00502 position_this_game = the_arena.get_robots_left() + 1;
00503
00504 double points = the_arena.get_robots_per_game() - the_arena.get_robots_left() -
00505 ((double)adjust) * 0.5;
00506
00507 time_survived_in_sequence += the_arena.get_total_time();
00508
00509 send_message(DEAD);
00510 send_signal();
00511
00512 realtime_arena.print_to_logfile('D', (int)'R', id, points, position_this_game);
00513
00514
00515 stat_t* statp = new stat_t
00516 (
00517 the_arena.get_sequence_nr(),
00518 the_arena.get_game_nr(),
00519 position_this_game,
00520 points,
00521 the_arena.get_total_time(),
00522 get_total_points() + points
00523 );
00524
00525 statistics.insert_last( statp );
00526
00527 #ifndef NO_GRAPHICS
00528 if( !no_graphics ) display_score();
00529 #endif
00530 }
00531
00532
00533
00534 void
00535 Robot::set_stats(const double pnts, const int pos, const double time_survived,
00536 const bool make_stats)
00537 {
00538 position_this_game = pos;
00539 time_survived_in_sequence += time_survived;
00540
00541 if( make_stats )
00542 {
00543 ListIterator<stat_t> li;
00544 statistics.last(li);
00545 double total_points = ( li.ok() ? li()->total_points : 0.0 );
00546
00547 stat_t* statp = new stat_t
00548 (
00549 the_arena.get_sequence_nr(),
00550 the_arena.get_game_nr(),
00551 pos,
00552 pnts,
00553 time_survived,
00554 total_points + pnts
00555 );
00556
00557 statistics.insert_last( statp );
00558 }
00559 #ifndef NO_GRAPHICS
00560 if( !no_graphics && !make_stats ) display_score();
00561 #endif
00562 }
00563
00564 void
00565 Robot::change_position( const double x, const double y,
00566 const double robot_a, const double cannon_a,
00567 const double radar_a, const double en )
00568 {
00569 center = Vector2D(x, y);
00570 robot_angle.pos = robot_a;
00571 cannon_angle.pos = cannon_a;
00572 radar_angle.pos = radar_a;
00573 energy = en;
00574 #ifndef NO_GRAPHICS
00575 if( !no_graphics ) display_score();
00576 #endif
00577 }
00578
00579 void
00580 Robot::check_name_uniqueness()
00581 {
00582 Robot* robotp = NULL;
00583 int first_avail = 0;
00584
00585 robot_name = plain_robot_name;
00586
00587 ListIterator<Robot> li;
00588 for( the_arena.get_all_robots_in_tournament()->first(li); li.ok(); li++ )
00589 {
00590 robotp = li();
00591 if( robotp != this && plain_robot_name == robotp->plain_robot_name )
00592 {
00593 if( robotp->robot_name_uniqueness_number == 0 )
00594 {
00595 robotp->robot_name_uniqueness_number = 1;
00596 robotp->robot_name += "(1)";
00597 }
00598
00599 first_avail = max( robotp->robot_name_uniqueness_number + 1, first_avail );
00600
00601 if( robot_name_uniqueness_number == robotp->robot_name_uniqueness_number
00602 || robot_name_uniqueness_number == 0 )
00603 robot_name_uniqueness_number = first_avail;
00604 }
00605 }
00606
00607 if( robot_name_uniqueness_number > 0 )
00608 robot_name += ('(' + (String)robot_name_uniqueness_number + ')');
00609 }
00610
00611 double
00612 Robot::get_total_points()
00613 {
00614 ListIterator<stat_t> li;
00615 double total_pnts;
00616
00617 if( the_arena_controller.is_realtime() || replay_arena.is_log_from_stdin() )
00618 {
00619 statistics.last(li);
00620
00621 total_pnts = ( li.ok() ? li()->total_points : 0.0 );
00622
00623 if( is_alive() )
00624 total_pnts += the_arena.get_robots_per_game() - the_arena.get_robots_left();
00625
00626
00627 }
00628 else
00629 {
00630 ListIterator<stat_t> li=get_current_game_stats();
00631
00632 if( is_alive() )
00633 {
00634 total_pnts = li()->total_points - li()->points +
00635 the_arena.get_robots_per_game() - the_arena.get_robots_left();
00636 }
00637 else
00638 total_pnts = li()->total_points;
00639 }
00640
00641 return total_pnts;
00642 }
00643
00644
00645
00646 int
00647 Robot::get_last_position()
00648 {
00649 ListIterator<stat_t> li;
00650
00651 if( the_arena_controller.is_realtime() || replay_arena.is_log_from_stdin() )
00652 {
00653
00654 statistics.last(li);
00655
00656 if( !li.ok() ) return 0;
00657
00658 if( li()->game_nr < the_arena.get_game_nr() )
00659 return li()->position;
00660 }
00661 else
00662 {
00663 li = get_current_game_stats();
00664 }
00665
00666 if( !li.ok() ) return 0;
00667 li--;
00668 if( !li.ok() ) return 0;
00669
00670 if( li()->sequence_nr == the_arena.get_sequence_nr() )
00671 return li()->position;
00672 else
00673 return 0;
00674 }
00675
00676 ListIterator<stat_t>
00677 Robot::get_current_game_stats()
00678 {
00679 if( !current_game_stats.ok() ||
00680 current_game_stats()->sequence_nr != the_arena.get_sequence_nr() ||
00681 current_game_stats()->game_nr != the_arena.get_game_nr() )
00682 {
00683 ListIterator<stat_t> li;
00684 for( statistics.first(li); li.ok(); li++ )
00685 {
00686 if( li()->sequence_nr == the_arena.get_sequence_nr() &&
00687 li()->game_nr == the_arena.get_game_nr() )
00688 {
00689 current_game_stats = li;
00690 return current_game_stats;
00691 }
00692 }
00693 Error(true, "Couldn't find stats", "Robot::get_current_game_stats");
00694 }
00695
00696 return current_game_stats;
00697 }
00698
00699
00700 bool
00701 Robot::update_rotation(rotation_t& angle, const double timestep)
00702 {
00703 angle.pos += timestep * angle.vel;
00704 bool rot_reached = false;
00705
00706 if( angle.pos >= angle.right && angle.mode == ROTATE_TO_RIGHT )
00707 {
00708 angle.set_rot( angle.right, 0.0, -infinity, infinity, NORMAL_ROT);
00709 if( send_rotation_reached >= 1 ) rot_reached = true;
00710 }
00711
00712 if( angle.pos >= angle.right && angle.mode == SWEEP_RIGHT )
00713 {
00714 angle.set_rot( angle.right, -angle.vel, angle.left, angle.right, SWEEP_LEFT);
00715 if( send_rotation_reached >= 2 ) rot_reached = true;
00716 }
00717
00718 if( angle.pos <= angle.left && angle.mode == ROTATE_TO_LEFT )
00719 {
00720 angle.set_rot( angle.left, 0.0, -infinity, infinity, NORMAL_ROT);
00721 if( send_rotation_reached >= 1 ) rot_reached = true;
00722 }
00723
00724 if( angle.pos <= angle.left && angle.mode == SWEEP_LEFT )
00725 {
00726 angle.set_rot( angle.left, -angle.vel, angle.left, angle.right, SWEEP_RIGHT);
00727 if( send_rotation_reached >= 2 ) rot_reached = true;
00728 }
00729
00730 return rot_reached;
00731 }
00732
00733 void
00734 Robot::update_radar_and_cannon(const double timestep)
00735 {
00736 int rot_reached = 0;
00737 if( update_rotation(robot_angle, timestep) ) rot_reached += 1;
00738 if( update_rotation(cannon_angle, timestep) ) rot_reached += 2;
00739 if( update_rotation(radar_angle, timestep) ) rot_reached += 4;
00740
00741 if( rot_reached > 0 ) send_message(ROTATION_REACHED, rot_reached);
00742
00743 shot_energy = min( the_opts.get_d(OPTION_SHOT_MAX_ENERGY),
00744 shot_energy+timestep*the_opts.get_d(OPTION_SHOT_ENERGY_INCREASE_SPEED) );
00745
00746 object_type closest_arenaobject;
00747 Shape* col_obj;
00748 double dist = the_arena.
00749 get_shortest_distance(center, angle2vec(radar_angle.pos+robot_angle.pos),
00750 0.0, closest_arenaobject, col_obj, this);
00751
00752 send_message(RADAR, dist, closest_arenaobject, radar_angle.pos);
00753 if( closest_arenaobject == ROBOT )
00754 {
00755 double lvls = (double)the_opts.get_l(OPTION_ROBOT_ENERGY_LEVELS);
00756 double en = ((Robot*)col_obj)->get_energy();
00757 send_message(ROBOT_INFO, rint( en / lvls ) * lvls, 0);
00758 }
00759
00760 if( the_opts.get_l(OPTION_SEND_ROBOT_COORDINATES) == 1 )
00761 send_message(COORDINATES, center[0] - start_pos[0], center[1] - start_pos[1],
00762 robot_angle.pos - start_angle);
00763
00764 if( the_opts.get_l(OPTION_SEND_ROBOT_COORDINATES) == 2 )
00765 send_message(COORDINATES, center[0], center[1], robot_angle.pos);
00766
00767 send_message(INFO, the_arena.get_total_time(), length(velocity), cannon_angle.pos);
00768
00769 }
00770
00771 void
00772 Robot::bounce_on_wall(const double bounce_c, const double hardness_c, const Vector2D& normal)
00773 {
00774 double h, p, b;
00775
00776 if( -dot(normal, angle2vec(robot_angle.pos)) > cos(the_opts.get_d(OPTION_ROBOT_FRONTSIZE)*0.5) )
00777 {
00778 h = the_opts.get_d(OPTION_ROBOT_FRONT_HARDNESS);
00779 b = the_opts.get_d(OPTION_ROBOT_FRONT_BOUNCE_COEFF);
00780 p = the_opts.get_d(OPTION_ROBOT_FRONT_PROTECTION);
00781 }
00782 else
00783 {
00784 h = the_opts.get_d(OPTION_ROBOT_HARDNESS);
00785 b = the_opts.get_d(OPTION_ROBOT_BOUNCE_COEFF);
00786 p = the_opts.get_d(OPTION_ROBOT_PROTECTION);
00787 }
00788
00789 double e = b * bounce_c;
00790 Vector2D start_vel = velocity;
00791 velocity -= (1.0 + e) * dot(normal, velocity) * normal;
00792
00793 double en_diff = 0.5 * the_opts.get_d(OPTION_ROBOT_MASS) * lengthsqr(start_vel - velocity);
00794 double injury = en_diff * 0.5 * (h + hardness_c ) * (1.0-e) * (1.0-p);
00795 change_energy(-injury);
00796
00797 send_message(COLLISION, WALL, vec2angle(-normal)-robot_angle.pos);
00798 }
00799
00800 void
00801 bounce_on_robot(Robot& robot1, Robot& robot2, const Vector2D& normal)
00802 {
00803 double h1, h2, p1, p2, b1, b2;
00804 Vector2D dir1_2 = unit(robot2.center - robot1.center);
00805
00806 if( dot(dir1_2, angle2vec(robot1.robot_angle.pos)) > cos(the_opts.get_d(OPTION_ROBOT_FRONTSIZE)*0.5) )
00807 {
00808 h1 = the_opts.get_d(OPTION_ROBOT_FRONT_HARDNESS);
00809 b1 = the_opts.get_d(OPTION_ROBOT_FRONT_BOUNCE_COEFF);
00810 p1 = the_opts.get_d(OPTION_ROBOT_FRONT_PROTECTION);
00811 }
00812 else
00813 {
00814 h1 = the_opts.get_d(OPTION_ROBOT_HARDNESS);
00815 b1 = the_opts.get_d(OPTION_ROBOT_BOUNCE_COEFF);
00816 p1 = the_opts.get_d(OPTION_ROBOT_PROTECTION);
00817 }
00818
00819 if( -dot(dir1_2, angle2vec(robot2.robot_angle.pos)) > cos(the_opts.get_d(OPTION_ROBOT_FRONTSIZE)*0.5) )
00820 {
00821 h2 = the_opts.get_d(OPTION_ROBOT_FRONT_HARDNESS);
00822 b2 = the_opts.get_d(OPTION_ROBOT_FRONT_BOUNCE_COEFF);
00823 p2 = the_opts.get_d(OPTION_ROBOT_FRONT_PROTECTION);
00824 }
00825 else
00826 {
00827 h2 = the_opts.get_d(OPTION_ROBOT_HARDNESS);
00828 b2 = the_opts.get_d(OPTION_ROBOT_BOUNCE_COEFF);
00829 p2 = the_opts.get_d(OPTION_ROBOT_PROTECTION);
00830 }
00831
00832 double e = b1*b2;
00833 Vector2D start_vel1 = robot1.velocity;
00834 Vector2D start_vel2 = robot2.velocity;
00835 double mass = the_opts.get_d(OPTION_ROBOT_MASS);
00836 Vector2D tmp = ((1.0 + e) / 2.0) * dot(robot2.velocity - robot1.velocity, normal) * normal;
00837 robot1.velocity += tmp;
00838 robot2.velocity -= tmp;
00839
00840 double an = vec2angle(-normal);
00841 double en_diff = 0.5 * mass * lengthsqr(start_vel1 - robot1.velocity);
00842 double injury = en_diff * 0.5 * (h1 + h2) * (1.0-e) * (1.0-p1);
00843 robot1.change_energy(-injury);
00844 robot1.send_message(COLLISION, ROBOT, an-robot1.robot_angle.pos);
00845
00846 an = vec2angle(normal);
00847 en_diff = 0.5 * mass * lengthsqr(start_vel2 - robot2.velocity);
00848 injury = en_diff * 0.5 * (h1 + h2) * (1.0-e) * (1.0-p2);
00849 robot2.change_energy(-injury);
00850 robot2.send_message(COLLISION, ROBOT, an-robot2.robot_angle.pos);
00851 }
00852
00853 void
00854 Robot::set_values_before_game(const Vector2D& pos, const double angle)
00855 {
00856 center = pos;
00857 start_pos = pos;
00858 start_angle = angle;
00859 robot_angle.set_rot (angle, 0.0, -infinity, infinity, NORMAL_ROT);
00860 cannon_angle.set_rot(0.0, 0.0, -infinity, infinity, NORMAL_ROT);
00861 radar_angle.set_rot (0.0, 0.0, -infinity, infinity, NORMAL_ROT);
00862 shot_energy = 0.0;
00863 radius = the_opts.get_d(OPTION_ROBOT_RADIUS);
00864 energy = the_opts.get_d(OPTION_ROBOT_START_ENERGY);
00865 velocity = Vector2D(0.0, 0.0);
00866 position_this_game = 0;
00867
00868 brake_percent = 0.0;
00869 acceleration = 0.0;
00870 }
00871
00872 void
00873 Robot::set_values_at_process_start_up()
00874 {
00875 process_running = true;
00876
00877 if( !network_robot )
00878 {
00879 reset_cpu_time();
00880 cpu_limit = the_opts.get_d(OPTION_CPU_START_LIMIT);
00881 cpu_warning_limit = cpu_limit * the_opts.get_d(OPTION_CPU_WARNING_PERCENT);
00882 cpu_timeout = 0.0;
00883 }
00884
00885 time_survived_in_sequence = 0.0;
00886
00887 if( statistics.is_empty() )
00888 {
00889 send_message(INITIALIZE, 1);
00890 colour_given = false;
00891 name_given = false;
00892 }
00893 else
00894 {
00895 send_message(INITIALIZE, 0);
00896 send_message(YOUR_NAME, robot_name.chars());
00897 int long col = rgb_colour;
00898 int long newcol = realtime_arena.find_free_colour(col, col, this);
00899 if( col != newcol ) set_colour( newcol );
00900
00901 send_message(YOUR_COLOUR, newcol);
00902 }
00903 }
00904
00905 void
00906 Robot::change_velocity(const double timestep)
00907 {
00908 Vector2D dir = angle2vec(robot_angle.pos);
00909 double gt = the_opts.get_d(OPTION_GRAV_CONST) * timestep;
00910 double fric = the_opts.get_d(OPTION_ROLL_FRICTION) * (1.0 - brake_percent) +
00911 the_opts.get_d(OPTION_SLIDE_FRICTION) * brake_percent;
00912 velocity = -velocity* min(the_opts.get_d(OPTION_AIR_RESISTANCE) * timestep, 0.5) +
00913 timestep*acceleration*dir +
00914 dot(velocity, dir) * max(0.0, 1.0-gt*fric) * dir +
00915 vedge(dir, velocity) * max(0.0, 1.0-gt*the_opts.get_d(OPTION_SLIDE_FRICTION)) * rotate90(dir);
00916 }
00917
00918 void
00919 Robot::move(const double timestep)
00920 {
00921 move(timestep, 1, timestep / 50.0);
00922
00923 if( is_alive() )
00924 realtime_arena.print_to_logfile('R', id, center[0], center[1],
00925 robot_angle.pos, cannon_angle.pos,
00926 radar_angle.pos, energy);
00927
00928 }
00929
00930 void
00931 Robot::move(const double timestep, int iterstep, const double eps)
00932 {
00933 object_type closest_shape;
00934 Shape* colliding_object;
00935 double time_to_collision =
00936 the_arena.get_shortest_distance(center, velocity, radius,
00937 closest_shape, colliding_object, this);
00938 if( time_to_collision > timestep )
00939 {
00940 center += timestep*velocity;
00941 }
00942 else
00943 {
00944 if( iterstep > 10 ) time_to_collision = max( time_to_collision , eps );
00945 double time_remaining = timestep - time_to_collision;
00946 center += time_to_collision*velocity;
00947
00948
00949
00950 switch( closest_shape )
00951 {
00952 case WALL:
00953 {
00954 Vector2D normal = colliding_object->get_normal(center);
00955 bounce_on_wall(colliding_object->get_bounce_coeff(),
00956 colliding_object->get_hardness_coeff(), normal);
00957 center += normal*eps;
00958 }
00959 break;
00960 case ROBOT:
00961 {
00962 Vector2D normal = ((Robot*)colliding_object)->get_normal(center);
00963 bounce_on_robot(*this, *(Robot*)colliding_object, normal);
00964 time_remaining = 0.0;
00965 }
00966 break;
00967 case SHOT:
00968 {
00969 Shot* shotp =(Shot*)colliding_object;
00970 double en = -shotp->get_energy();
00971 change_energy( en );
00972 send_message(COLLISION, SHOT, vec2angle(shotp->get_center()-center)-robot_angle.pos);
00973 shotp->die();
00974 the_arena.get_object_lists()[SHOT].remove( shotp );
00975 }
00976 break;
00977 case COOKIE:
00978 {
00979 Cookie* cookiep =(Cookie*)colliding_object;
00980 double en = cookiep->get_energy();
00981 change_energy( en );
00982 send_message(COLLISION, COOKIE, vec2angle(cookiep->get_center()-center)-robot_angle.pos);
00983 cookiep->die();
00984 the_arena.get_object_lists()[COOKIE].remove( cookiep );
00985 }
00986 break;
00987 case MINE:
00988 {
00989 Mine* minep =(Mine*)colliding_object;
00990 double en = -minep->get_energy();
00991 change_energy( en );
00992 send_message(COLLISION, MINE, vec2angle(minep->get_center()-center)-robot_angle.pos);
00993 minep->die();
00994 the_arena.get_object_lists()[MINE].remove( minep );
00995 }
00996 break;
00997 default:
00998 Error(true, "Collided with unknown object", "Robot::move");
00999 break;
01000 }
01001
01002
01003
01004
01005
01006 if( iterstep > 65 ) Error(true, "Too many bounces, must be a bug!", "Robot::move");
01007 if( alive && time_remaining > 0.0 ) move( time_remaining, iterstep + 1, eps );
01008 }
01009 }
01010
01011 void
01012 Robot::send_message(const message_to_robot_type msg_type ...)
01013 {
01014 va_list args;
01015 va_start(args, msg_type);
01016
01017 *outstreamp << message_to_robot[msg_type].msg << " ";
01018 for(int i=0; i<message_to_robot[msg_type].number_of_args; i++)
01019 {
01020 switch(message_to_robot[msg_type].arg_type[i])
01021 {
01022 case NONE:
01023 Error(true, "Couldn't send message, no arg_type", "Robot::send_message");
01024 break;
01025 case INT:
01026 *outstreamp << va_arg(args, int) << " ";
01027 break;
01028 case DOUBLE:
01029 *outstreamp << va_arg(args, double) << " ";
01030 break;
01031 case STRING:
01032 *outstreamp << va_arg(args, char*) << " ";
01033 break;
01034 case HEX:
01035 *outstreamp << std::hex << va_arg(args, int) << " ";
01036 break;
01037 default:
01038 Error(true, "Couldn't send message, unknown arg_type", "Robot::send_message");
01039 }
01040 }
01041 *outstreamp << endl;
01042
01043 }
01044
01045
01046
01047
01048
01049 void
01050 Robot::get_messages()
01051 {
01052 char buffer[81];
01053 char text[161];
01054 char msg_name[81];
01055 message_from_robot_type msg_t;
01056
01057 *instreamp >> ws;
01058 instreamp->clear();
01059 instreamp->peek();
01060
01061
01062
01063 while( !(*instreamp >> msg_name).eof() )
01064 {
01065
01066
01067
01068 msg_t = name2msg_from_robot_type(msg_name);
01069
01070
01071
01072
01073 *instreamp >> ws;
01074
01075 switch(msg_t)
01076 {
01077 case UNKNOWN_MESSAGE_FROM_ROBOT:
01078
01079 send_message(WARNING, UNKNOWN_MESSAGE, msg_name);
01080 instreamp->get(buffer, 80, '\n');
01081 break;
01082 case ROBOT_OPTION:
01083 if( check_state_for_message(msg_t, STARTING_ROBOTS) )
01084 {
01085 int opt_nr, val;
01086 *instreamp >> opt_nr;
01087 switch(opt_nr)
01088 {
01089 case SEND_SIGNAL:
01090 *instreamp >> val;
01091 send_usr_signal = (val == true);
01092 signal_to_send = SIGUSR1;
01093 send_signal();
01094 break;
01095 case SIGNAL:
01096 *instreamp >> val;
01097 if( val > 0 && val < NSIG )
01098 {
01099 signal_to_send = val;
01100 send_usr_signal = true;
01101 send_signal();
01102
01103 }
01104 else
01105 {
01106 if( val >= NSIG ) send_message(WARNING, UNKNOWN_OPTION, msg_name);
01107 signal_to_send = 0;
01108 send_usr_signal = false;
01109 }
01110 break;
01111
01112 case SEND_ROTATION_REACHED:
01113 *instreamp >> val;
01114 if( val < 0 ) val = 0;
01115 if( val > 2 ) val = 2;
01116 send_rotation_reached = val;
01117 break;
01118
01119 case USE_NON_BLOCKING:
01120 *instreamp >> val;
01121 if( network_robot )
01122 {
01123 *outstreamp << '@' << ( val ? 'N' : 'B' ) << endl;
01124 send_message(INITIALIZE, 1);
01125 }
01126 else
01127 set_non_blocking_state( val );
01128 break;
01129
01130 default:
01131 send_message(WARNING, UNKNOWN_OPTION, msg_name);
01132 break;
01133 }
01134 }
01135 break;
01136 case NAME:
01137 if( check_state_for_message(msg_t, STARTING_ROBOTS) )
01138 {
01139 instreamp->get(text, 80, '\n');
01140 plain_robot_name = text;
01141 check_name_uniqueness();
01142 name_given = true;
01143 }
01144 break;
01145 case COLOUR:
01146 if( check_state_for_message(msg_t, STARTING_ROBOTS) )
01147 {
01148 long home_colour, away_colour;
01149
01150 *instreamp >> std::hex >> home_colour >> away_colour >> std::dec;
01151
01152
01153 set_colour( realtime_arena.find_free_colour(home_colour, away_colour, this) );
01154 colour_given = true;
01155 }
01156 break;
01157 case ROTATE:
01158 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01159 {
01160 int bits;
01161 double rot_speed;
01162 *instreamp >> bits >> rot_speed;
01163
01164 double rot_sign = sgn(rot_speed);
01165 rot_speed = fabs(rot_speed);
01166 if( bits & 1 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01167 if( bits & 2 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01168 if( bits & 4 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_RADAR_MAX_ROTATE) );
01169 rot_speed *= rot_sign;
01170
01171 if( bits & 1 )
01172 robot_angle.set_rot( robot_angle.pos, rot_speed,
01173 -infinity, infinity, NORMAL_ROT );
01174 if( bits & 2 )
01175 cannon_angle.set_rot( cannon_angle.pos, rot_speed,
01176 -infinity, infinity, NORMAL_ROT );
01177 if( bits & 4 )
01178 radar_angle.set_rot( radar_angle.pos, rot_speed,
01179 -infinity, infinity, NORMAL_ROT );
01180 }
01181 break;
01182
01183 case ROTATE_TO:
01184 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01185 {
01186 int bits;
01187 double rot_speed, rot_end_angle, rot_amount;
01188 *instreamp >> bits >> rot_speed >> rot_end_angle;
01189 rot_end_angle = max(min(rot_end_angle, infinity), -infinity);
01190
01191 rot_speed = fabs(rot_speed);
01192 if( bits & 2 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01193 if( bits & 4 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_RADAR_MAX_ROTATE) );
01194
01195 if( bits & 2 )
01196 {
01197 cannon_angle.pos -= rint( (cannon_angle.pos-rot_end_angle) / (2.0*M_PI) ) * 2.0 * M_PI;
01198 rot_amount = rot_end_angle - cannon_angle.pos;
01199 if( rot_amount > 0 )
01200 cannon_angle.set_rot( cannon_angle.pos, rot_speed,
01201 -infinity, cannon_angle.pos + rot_amount,
01202 ROTATE_TO_RIGHT );
01203 else
01204 cannon_angle.set_rot( cannon_angle.pos, -rot_speed,
01205 cannon_angle.pos + rot_amount, infinity,
01206 ROTATE_TO_LEFT );
01207 }
01208 if( bits & 4 )
01209 {
01210 radar_angle.pos -= rint( (radar_angle.pos-rot_end_angle) / (2.0*M_PI) ) * 2.0 * M_PI;
01211 rot_amount = rot_end_angle - radar_angle.pos;
01212 if( rot_amount > 0 )
01213 radar_angle.set_rot( radar_angle.pos, rot_speed,
01214 -infinity, radar_angle.pos + rot_amount,
01215 ROTATE_TO_RIGHT );
01216 else
01217 radar_angle.set_rot( radar_angle.pos, -rot_speed,
01218 radar_angle.pos + rot_amount, infinity,
01219 ROTATE_TO_LEFT );
01220 }
01221 }
01222 break;
01223
01224 case ROTATE_AMOUNT:
01225 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01226 {
01227 int bits;
01228 double rot_speed, rot_amount;
01229 *instreamp >> bits >> rot_speed >> rot_amount;
01230
01231 rot_speed = fabs(rot_speed);
01232 if( bits & 1 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01233 if( bits & 2 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01234 if( bits & 4 ) rot_speed = min( rot_speed, the_opts.get_d(OPTION_ROBOT_RADAR_MAX_ROTATE) );
01235
01236 if( bits & 1 )
01237 {
01238 if( rot_amount > 0 )
01239 robot_angle.set_rot( robot_angle.pos, rot_speed,
01240 -infinity, robot_angle.pos + rot_amount,
01241 ROTATE_TO_RIGHT );
01242 else
01243 robot_angle.set_rot( robot_angle.pos, -rot_speed,
01244 robot_angle.pos + rot_amount, infinity,
01245 ROTATE_TO_LEFT );
01246 }
01247 if( bits & 2 )
01248 {
01249 if( rot_amount > 0 )
01250 cannon_angle.set_rot( cannon_angle.pos, rot_speed,
01251 -infinity, cannon_angle.pos + rot_amount,
01252 ROTATE_TO_RIGHT );
01253 else
01254 cannon_angle.set_rot( cannon_angle.pos, -rot_speed,
01255 cannon_angle.pos + rot_amount, infinity,
01256 ROTATE_TO_LEFT );
01257 }
01258 if( bits & 4 )
01259 {
01260 if( rot_amount > 0 )
01261 radar_angle.set_rot( radar_angle.pos, rot_speed,
01262 -infinity, radar_angle.pos + rot_amount,
01263 ROTATE_TO_RIGHT );
01264 else
01265 radar_angle.set_rot( radar_angle.pos, -rot_speed,
01266 radar_angle.pos + rot_amount, infinity,
01267 ROTATE_TO_LEFT );
01268 }
01269 }
01270 break;
01271 case SWEEP:
01272 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01273 {
01274 int bits;
01275 double rot_speed, sweep_left, sweep_right;
01276 *instreamp >> bits >> rot_speed >> sweep_left >> sweep_right;
01277 sweep_left = max(min(sweep_left, infinity), -infinity);
01278 sweep_right = max(min(sweep_right, infinity), -infinity);
01279 rotation_mode_t rot_dir;
01280 rot_dir = ( rot_speed < 0 ? SWEEP_LEFT : SWEEP_RIGHT );
01281
01282 if( bits & 2 ) rot_speed = min( fabs(rot_speed), the_opts.get_d(OPTION_ROBOT_CANNON_MAX_ROTATE) );
01283 if( bits & 4 ) rot_speed = min( fabs(rot_speed), the_opts.get_d(OPTION_ROBOT_RADAR_MAX_ROTATE) );
01284
01285 if( bits & 2 )
01286 {
01287 cannon_angle.pos -= rint( (cannon_angle.pos - 0.5*(sweep_left+sweep_right)) /
01288 (2.0*M_PI) ) * 2.0 * M_PI;
01289 if( fabs(cannon_angle.vel) > 1e-10 )
01290 rot_dir = ( cannon_angle.vel < 0 ? SWEEP_LEFT : SWEEP_RIGHT );
01291
01292 if( cannon_angle.pos <= sweep_left ) rot_dir = SWEEP_RIGHT;
01293 if( cannon_angle.pos >= sweep_right ) rot_dir = SWEEP_LEFT;
01294
01295 double cannon_speed = rot_speed;
01296 if( rot_dir == SWEEP_LEFT ) cannon_speed = -rot_speed;
01297 cannon_angle.set_rot( cannon_angle.pos, cannon_speed,
01298 sweep_left, sweep_right, rot_dir );
01299 }
01300 if( bits & 4 )
01301 {
01302 radar_angle.pos -= rint( (radar_angle.pos - 0.5*(sweep_left+sweep_right)) /
01303 (2.0*M_PI) ) * 2.0 * M_PI;
01304 if( fabs(radar_angle.vel) > 1e-10 )
01305 rot_dir = ( radar_angle.vel < 0 ? SWEEP_LEFT : SWEEP_RIGHT );
01306
01307 if( radar_angle.pos <= sweep_left ) rot_dir = SWEEP_RIGHT;
01308 if( radar_angle.pos >= sweep_right ) rot_dir = SWEEP_LEFT;
01309
01310 double radar_speed = rot_speed;
01311 if( rot_dir == SWEEP_LEFT ) radar_speed = -rot_speed;
01312 radar_angle.set_rot( radar_angle.pos, radar_speed,
01313 sweep_left, sweep_right, rot_dir );
01314 }
01315 }
01316 break;
01317 case PRINT:
01318 {
01319 instreamp->get(text, 160, '\n');
01320 realtime_arena.print_to_logfile('P', id, text);
01321 the_arena.print_message( robot_name, text );
01322 }
01323 break;
01324
01325 case DEBUG:
01326 {
01327 instreamp->get(text, 160, '\n');
01328 if( realtime_arena.get_game_mode() == ArenaBase::DEBUG_MODE )
01329 {
01330 realtime_arena.print_to_logfile('P', id, text);
01331 the_arena.print_message( robot_name, text );
01332 }
01333 }
01334 break;
01335
01336 case DEBUG_LINE:
01337 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01338 {
01339 if( !the_arena.is_max_debug_level() )
01340 {
01341 send_message(WARNING, MESSAGE_SENT_IN_ILLEGAL_STATE,
01342 message_from_robot[msg_t].msg);
01343 }
01344 #ifndef NO_GRAPHICS
01345 else if( !no_graphics )
01346 {
01347 double a1, d1, a2, d2;
01348 *instreamp >> a1 >> d1 >> a2 >> d2;
01349
01350 Vector2D start = d1 * angle2vec(a1 + robot_angle.pos);
01351 Vector2D direction = d2 * angle2vec(a2 + robot_angle.pos) - start;
01352
01353 the_gui.get_arenawindow_p()->
01354 draw_line(start + center, direction, 1.0, gdk_colour);
01355 }
01356 #endif
01357 }
01358 break;
01359
01360 case DEBUG_CIRCLE:
01361 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01362 {
01363 if( !the_arena.is_max_debug_level() )
01364 {
01365 send_message(WARNING, MESSAGE_SENT_IN_ILLEGAL_STATE,
01366 message_from_robot[msg_t].msg);
01367 }
01368 #ifndef NO_GRAPHICS
01369 else if( !no_graphics )
01370 {
01371 double a, d, r;
01372 *instreamp >> a >> d >> r;
01373
01374 Vector2D c = d * angle2vec(a + robot_angle.pos) + center;
01375
01376 the_gui.get_arenawindow_p()->
01377 draw_circle(c, r, gdk_colour, false);
01378 }
01379 #endif
01380 }
01381 break;
01382
01383 case SHOOT:
01384 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01385 {
01386 double en;
01387 *instreamp >> en;
01388 en = min(en, shot_energy);
01389 if( en < the_opts.get_d(OPTION_SHOT_MIN_ENERGY) ) break;
01390 shot_energy -= en;
01391
01392 Vector2D dir = angle2vec(cannon_angle.pos+robot_angle.pos);
01393 double shot_radius = the_opts.get_d(OPTION_SHOT_RADIUS);
01394 Vector2D shot_center = center + (radius+1.5*shot_radius)*dir;
01395 Vector2D shot_vel = velocity + dir * the_opts.get_d(OPTION_SHOT_SPEED);
01396
01397 if( realtime_arena.space_available( shot_center, shot_radius*1.00001 ) )
01398 {
01399 Shot* shotp = new Shot( shot_center, shot_vel, en );
01400 realtime_arena.get_object_lists()[SHOT].insert_last( shotp );
01401
01402 realtime_arena.print_to_logfile('S', shotp->get_id(), shot_center[0], shot_center[1],
01403 shot_vel[0], shot_vel[1]);
01404 }
01405 else
01406 {
01407 Shape* col_obj;
01408 object_type cl_shape;
01409 double dist;
01410 if( (dist = realtime_arena.get_shortest_distance
01411 ( center, dir, shot_radius*1.00001,
01412 cl_shape, col_obj, this)) > radius+1.5*shot_radius )
01413 {
01414 cerr << "dist: " << dist << " r+1.5sh_r: " << radius+1.5*shot_radius << endl;
01415 cerr << "col_shape: " << (int)cl_shape << endl;
01416 Error(false, "Shot has space available after all?", "Robot::get_messages");
01417 }
01418 switch(cl_shape)
01419 {
01420 case WALL:
01421 break;
01422 case ROBOT:
01423 {
01424 Robot* robotp = (Robot*)col_obj;
01425 robotp->change_energy(-en);
01426 robotp->send_message(COLLISION, SHOT,
01427 vec2angle(center+dir*radius-robotp->get_center()) - robotp->get_robot_angle().pos);
01428 }
01429 break;
01430 case SHOT:
01431 shot_collision((Shot*)col_obj, shot_vel, en);
01432 break;
01433 case COOKIE:
01434 {
01435 Cookie* cookiep =(Cookie*)col_obj;
01436 cookiep->die();
01437 the_arena.get_object_lists()[COOKIE].remove( cookiep );
01438 }
01439 break;
01440 case MINE:
01441 {
01442 Mine* minep =(Mine*)col_obj;
01443 minep->die();
01444 the_arena.get_object_lists()[MINE].remove( minep );
01445 }
01446 break;
01447 default:
01448 Error(true, "Shot on unknown object", "Robot::get_messages");
01449 }
01450 }
01451 change_energy(-en * realtime_arena.get_shooting_penalty() );
01452 }
01453 break;
01454 case ACCELERATE:
01455 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01456 {
01457 double acc;
01458 *instreamp >> acc;
01459 acc = max( acc, the_opts.get_d(OPTION_ROBOT_MIN_ACCELERATION) );
01460 acc = min( acc, the_opts.get_d(OPTION_ROBOT_MAX_ACCELERATION) );
01461 acceleration = acc;
01462 }
01463 break;
01464 case BREAK:
01465 send_message(WARNING, OBSOLETE_KEYWORD, msg_name);
01466 case BRAKE:
01467 if( check_state_for_message(msg_t, GAME_IN_PROGRESS) )
01468 {
01469 double brk;
01470 *instreamp >> brk;
01471 brk = max( brk, 0.0);
01472 brk = min( brk, 1.0);
01473 brake_percent = brk;
01474 }
01475 break;
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505 default:
01506 Error(true, "Message_type not implemented, " + (String)msg_name, "Robot::get_messages");
01507 }
01508
01509 *instreamp >> ws;
01510 instreamp->clear();
01511 instreamp->peek();
01512 }
01513
01514
01515 }
01516
01517 message_from_robot_type
01518 Robot::name2msg_from_robot_type(char* msg_name)
01519 {
01520 for(int i=0; message_from_robot[i].msg[0] != '\0'; i++)
01521 {
01522 if( strcmp(message_from_robot[i].msg, msg_name) == 0 )
01523 return (message_from_robot_type)i;
01524 }
01525 return UNKNOWN_MESSAGE_FROM_ROBOT;
01526 }
01527
01528 bool
01529 Robot::check_state_for_message(const message_from_robot_type msg_t, const state_t state1, const state_t state2)
01530 {
01531 if( the_arena.get_state() != state1 && the_arena.get_state() != state2 )
01532 {
01533
01534
01535 if( the_arena.get_state() != BEFORE_GAME_START )
01536 send_message(WARNING, MESSAGE_SENT_IN_ILLEGAL_STATE,
01537 message_from_robot[msg_t].msg);
01538 char buffer[80];
01539 instreamp->get(buffer, 80, '\n');
01540 return false;
01541 }
01542
01543 return true;
01544 }
01545
01546 bool
01547 Robot::get_default_non_blocking_state()
01548 {
01549 String filename = the_opts.get_s( OPTION_TMP_RTB_DIR ) +
01550 "/" + robot_plain_filename;
01551
01552 int fd;
01553 if( ( fd = open(filename.chars(), O_RDONLY) ) != -1 )
01554 {
01555 close(fd);
01556 return false;
01557 }
01558
01559 return true;
01560 }
01561
01562
01563
01564 void
01565 Robot::set_non_blocking_state(const bool non_bl)
01566 {
01567 if( non_bl == use_non_blocking ) return;
01568
01569 String filename = the_opts.get_s( OPTION_TMP_RTB_DIR ) +
01570 "/" + robot_plain_filename;
01571
01572 create_tmp_rtb_dir();
01573
01574 if( non_bl )
01575 remove( filename.chars() );
01576 else
01577 {
01578 int fd = open(filename.chars(), O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
01579 if( fd != -1 ) close( fd );
01580 }
01581
01582
01583 use_non_blocking = non_bl;
01584
01585
01586
01587 kill_process_forcefully();
01588 start_process();
01589 }
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693 void
01694 Robot::change_energy(const double energy_diff)
01695 {
01696 energy = min(energy+energy_diff, the_opts.get_d(OPTION_ROBOT_MAX_ENERGY));
01697 #ifndef NO_GRAPHICS
01698 if( !no_graphics ) display_score();
01699 #endif
01700 if( energy <= 0.0 ) die();
01701 }
01702
01703 #ifndef NO_GRAPHICS
01704
01705 void
01706 Robot::reset_last_displayed()
01707 {
01708 last_displayed_energy = -1;
01709 last_displayed_place = 0;
01710 last_displayed_last_place = 0;
01711 last_displayed_score = -1;
01712 }
01713
01714 void
01715 Robot::display_score()
01716 {
01717 int p;
01718
01719 if( last_displayed_energy != (int)energy )
01720 {
01721 last_displayed_energy = (int)energy;
01722 gtk_clist_set_text(GTK_CLIST(the_gui.get_scorewindow_p()->get_clist()),
01723 row_in_score_clist,
01724 2, String((int)energy).non_const_chars());
01725 }
01726
01727 if( last_displayed_place != position_this_game )
01728 {
01729 String str;
01730 if( position_this_game != 0 ) str = String(position_this_game);
01731 last_displayed_place = position_this_game;
01732 gtk_clist_set_text(GTK_CLIST(the_gui.get_scorewindow_p()->get_clist()),
01733 row_in_score_clist,
01734 3, str.non_const_chars());
01735 }
01736
01737 p = get_last_position();
01738 if( p != 0 && p != last_displayed_last_place )
01739 {
01740 last_displayed_last_place = p;
01741 gtk_clist_set_text(GTK_CLIST(the_gui.get_scorewindow_p()->get_clist()),
01742 row_in_score_clist,
01743 4, String(p).non_const_chars());
01744 }
01745
01746
01747 double pnts = get_total_points();
01748 if( last_displayed_score != (int)(10 * pnts) )
01749 {
01750 last_displayed_score = (int)(10 * pnts);
01751 gtk_clist_set_text(GTK_CLIST(the_gui.get_scorewindow_p()->get_clist()),
01752 row_in_score_clist,
01753 5, String(pnts).non_const_chars());
01754 }
01755 }
01756
01757 void
01758 Robot::draw_radar_and_cannon()
01759 {
01760 double scale = the_gui.get_arenawindow_p()->get_drawing_area_scale();
01761
01762 if( radius*scale < 2.5 ) return;
01763
01764 the_gui.get_arenawindow_p()->
01765 draw_line( center,
01766 angle2vec(cannon_angle.pos+robot_angle.pos),
01767 radius - the_opts.get_d(OPTION_SHOT_RADIUS) - 1.0 / scale,
01768 the_opts.get_d(OPTION_SHOT_RADIUS),
01769 *(the_gui.get_fg_gdk_colour_p()) );
01770
01771
01772 Vector2D radar_dir = angle2vec(radar_angle.pos+robot_angle.pos);
01773 the_gui.get_arenawindow_p()->
01774 draw_line( center - radius * 0.25 * radar_dir,
01775 rotate( radar_dir, M_PI / 4.0 ),
01776 radius / 1.5,
01777 radius / 20.0,
01778 *(the_gui.get_fg_gdk_colour_p()) );
01779 the_gui.get_arenawindow_p()->
01780 draw_line( center - radius * 0.25 * radar_dir,
01781 rotate( radar_dir, - (M_PI / 4.0) ),
01782 radius / 1.5,
01783 radius / 20.0,
01784 *(the_gui.get_fg_gdk_colour_p()) );
01785
01786
01787 the_gui.get_arenawindow_p()->
01788 draw_line( center,
01789 angle2vec(robot_angle.pos),
01790 radius * 0.9 - 2.0 / scale,
01791 *(the_gui.get_fg_gdk_colour_p()) );
01792 }
01793
01794 void
01795 Robot::get_score_pixmap( GdkWindow* win, GdkPixmap*& pixm, GdkBitmap*& bitm )
01796 {
01797 score_pixmap.get_pixmap( gdk_colour, win, pixm, bitm );
01798 }
01799
01800 void
01801 Robot::get_stat_pixmap( GdkWindow* win, GdkPixmap*& pixm, GdkBitmap*& bitm )
01802 {
01803 stat_pixmap.get_pixmap( gdk_colour, win, pixm, bitm );
01804 }
01805
01806 #endif