Robot.cc

Go to the documentation of this file.
00001 /*
00002 RealTimeBattle, a robot programming game for Unix
00003 Copyright (C) 1998-2000  Erik Ouchterlony and Ragnar Ouchterlony
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software Foundation,
00017 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 //  #include "Gui.h"
00067 //  #include "MovingObject.h"
00068 //  #include "Arena.h"
00069 //  #include "Extras.h"
00070 //  #include "Options.h"
00071 //  #include "Messagetypes.h"
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   //  robot_dir= getenv("RTB_ROBOTDIR");
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   //  total_points = 0.0;
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 // Constructor used by ArenaReplay. No process needed.
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   //  total_points = 0.0;
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)   // Child process, to be the new robot
00158     {
00159       // Make pipe_out the standard input for the robot
00160       close(pipe_out[1]);
00161       dup2(pipe_out[0], STDIN_FILENO);
00162 
00163       // Make pipe_in the standard output
00164       dup2(pipe_in[1],STDOUT_FILENO);
00165       close(pipe_in[0]);
00166 
00167       // Make the pipes non-blocking
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       // Check file attributes
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       // Lower priority by one
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       // Close all pipes not belonging to the robot
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       // file access and child process creation are now allowed
00225 
00226       //      if( the_arena.get_game_mode() != ArenaBase::DEBUG_MODE )
00227       //        {
00228           //          struct rlimit res_limit;
00229 
00230           //        // Deny file access
00231           
00232           //            if( getrlimit( RLIMIT_NOFILE, &res_limit ) == -1 )
00233           //              Error(true, "Couldn't get file limits for robot " + robot_filename, 
00234           //                    "Robot::start_process, child");
00235           
00236           //            //res_limit.rlim_cur = 7;   // Don't know why, but it is the lowest number that works
00237           //            if( setrlimit( RLIMIT_NOFILE, &res_limit ) == -1 )
00238           //              Error(true, "Couldn't limit file access for robot " + robot_filename, 
00239           //                    "Robot::start_process, child");
00240           
00241 
00242           // Forbid creation of child processes
00243           
00244 //  #ifdef HAVE_RLIMIT_NPROC
00245 //            if( getrlimit( RLIMIT_NPROC, &res_limit ) == -1 )
00246 //              Error(true, "Couldn't get proc limits for robot " + robot_filename, 
00247 //                    "Robot::start_process, child");
00248           
00249 //            res_limit.rlim_cur = 0;
00250 //            if( setrlimit( RLIMIT_NPROC, &res_limit ) == -1 )
00251 //              Error(true, "Couldn't limit child processes for robot " + robot_filename, 
00252 //                    "Robot::start_process, child");
00253 //  #endif
00254       //        }
00255 
00256       // Execute process. Should not return!
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]);     // Close input side of pipe_out
00266       close(pipe_in[1]);      // Close output side of pipe_in  
00267                 
00268       pipes[0] = pipe_out[1];
00269       pipes[1] = pipe_in[0];
00270 
00271       // Make the pipes non-blocking
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         // Der Schrott geht nimmer in libstdc++ v3
00289 
00290      // outstreamp = new ofstream(pipe_out[1]);
00291      // instreamp = new ifstream(pipe_in[0]);
00292       
00293      outstreamp = new boost::fdostream(pipe_out[1]);  
00294      instreamp = new boost::fdistream(pipe_in[0]);
00295               
00296     }
00297 
00298   // wait some time to let process start up
00299  
00300   struct timeval timeout; 
00301   timeout.tv_sec = 0;
00302   timeout.tv_usec = 40000;  //  1/25 s 
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   // step to the correct value
00327   for(int i=0; i<15; i++) 
00328     procfile >> buf; 
00329 
00330   // The next four values should be added to get the correct cpu usage
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 //    if( getrusage( pid, &ru ) != 0 ) return;
00340 
00341 //    current_cpu = ((double)( ru->ru_utime.tv_usec + ru->ru_stime.tv_usec )) / 1e6 +
00342 //      (double)( ru->ru_utime.tv_sec + ru->ru_stime.tv_sec );
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   //  String procfilename = "/proc/" + String(pid) + "/stat";
00362 
00363   if( !is_process_running() || !alive || network_robot ) return;
00364 
00365     //    ifstream procfile(procfilename.chars());
00366 //        if( !procfile ) 
00367 //          {
00368 //            process_running = false;
00369 //            return;
00370 //          }
00371 
00372 //        char buf[16];
00373 
00374 //        for(int i=0; i<13; i++)
00375 //          procfile >> buf;
00376       
00377 //        int jiffies;
00378       
00379 //        procfile >> jiffies;
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 ) // ok, within time limit
00387             { 
00388               // add extra time
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 // cpu limit exceeded, robot disqualified
00395             {              
00396               die();
00397 
00398               // restart with full cpu_time next game
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; // No more warnings
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 // Version of set_stats used by ArenaReplay
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     // Replaying
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 // if robot dead
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 ) // Relative starting pos
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 ) // Absolute coordinates
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   //  points_this_game = 0.0;
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() )       // first sequence !
00888     {
00889       send_message(INITIALIZE, 1);
00890       colour_given = false;
00891       name_given = false;
00892     }
00893   else        // not first sequence !
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       // TODO: probably free color!
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       //      Vector2D new_center = center - min(eps, time_to_collision)*velocity;
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       //      center = new_center;
01003       //if( iterstep % 10 == 0 ) 
01004       //  cout << "Iterstep: " << iterstep << "   time_remaining: " << time_remaining
01005       //       << "  Collided on: " << closest_shape << "   time_to_col: " << time_to_collision << endl;
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 // This is the function which gets messages from the robot,
01047 // parses them and take appropriate action. It is certainly 
01048 // too long, but who cares :-)
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       //*instreamp >> msg_name;
01068       msg_t = name2msg_from_robot_type(msg_name);
01069       //      cerr << "Got message: " << msg_name << endl;
01070 
01071 
01072 
01073       *instreamp >> ws;
01074 
01075       switch(msg_t)
01076         {
01077         case UNKNOWN_MESSAGE_FROM_ROBOT:
01078           //cout << "Server: Warning sent for message: " << msg_name << endl;
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               // TODO: check if colour is already allocated! 
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  // No space for shot, direct hit!!
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:  // Included only for compatibility reasons
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           //          case LOAD_DATA:
01477           //            if( check_state_for_message(msg_t, STARTING_ROBOTS) )
01478           //              {
01479           //                bool bin;
01480           //                *instreamp >> bin;
01481           //                load_data(bin);
01482           //              }
01483           //            break;
01484           //          case SAVE_DATA_FINISHED:
01485           //            if( check_state_for_message(msg_t, SHUTTING_DOWN_ROBOTS) )
01486           //              {
01487           //                send_message(EXIT_ROBOT);
01488           //                send_signal();
01489           //              }
01490           //            break;
01491           //          case BIN_DATA_FROM:
01492           //            if( check_state_for_message(msg_t, SHUTTING_DOWN_ROBOTS) )
01493           //              {
01494           //                save_data(true, has_saved);
01495           //                has_saved = true;
01496           //              }
01497           //            break;
01498           //          case ASCII_DATA_FROM:
01499           //            if( check_state_for_message(msg_t, SHUTTING_DOWN_ROBOTS) )
01500           //              {
01501           //                save_data(false, has_saved);
01502           //                has_saved = true;
01503           //              }
01504           //            break;
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       //cout << "Server: Warning sent for message: " << msg_name << "     State: " << the_arena.get_state() << endl;
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 // If non_blocking is _not_ used, a file, OPTION_TMP_RTB_DIR/"robotname"
01563 // , is created.
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   //  restart_process
01586 
01587   kill_process_forcefully();
01588   start_process();
01589 }
01590 
01591 
01592 
01593 //  void
01594 //  Robot::save_data(const bool binary, const bool append)
01595 //  {
01596 //    cerr << "Sorry, save_data is broken at the moment!" << endl;
01597 //    return;
01598 
01599 //    String filename;
01600 
01601 //  //    if( robot_name_uniqueness_number == 0 )
01602 //  //      filename = the_gui.get_robotdir() + plain_robot_name + ".robotdata";
01603 //  //    else
01604 //  //      filename = the_gui.get_robotdir() + robot_name + ".robotdata";
01605 
01606 //    int mode = _IO_OUTPUT;  
01607 //    if( append ) mode = _IO_APPEND;
01608 
01609 //    ofstream file(filename.chars(), mode);
01610 
01611 //    if( !file ) Error(true, "Couldn't open file " + filename, "Robot::save_bin_data");
01612 
01613 //    if( binary )
01614 //      {
01615 //        int bytes;
01616 //        char c;
01617 //        *instreamp >> bytes;
01618 
01619 //        // TODO: check if data is avalable (peek), wait otherwise (select)
01620       
01621 //        for(int i=0; i < bytes; i++)
01622 //          {
01623 //            instreamp->get(c);
01624 //            file.put(c);
01625 //          }
01626 //      }
01627 //    else
01628 //      {
01629 //        char buf[256];
01630       
01631 //        instreamp->get(buf, 256 ,'\n');
01632 //        file << buf << endl;
01633 
01634 //        // TODO: continue saving if next message is SAVE_DATA
01635 //      }
01636 //  }
01637 
01638 //  void
01639 //  Robot::load_data(const bool binary)
01640 //  {
01641 //    cerr << "Sorry, load_data is broken at the moment!" << endl;
01642 //    return;
01643 
01644 //    String filename;
01645 
01646 //    ifstream file;
01647 
01648 
01649 //  //    if( robot_name_uniqueness_number == 0 )
01650 //  //      {
01651 //  //        filename = the_gui.get_robotdir() + "RobotSave/" + plain_robot_name + ".robotdata";
01652 //  //        file.open(filename.chars());
01653 //  //      }
01654 //  //    if( !file )
01655 //  //      {
01656 //  //        filename = the_gui.get_robotdir() + "RobotSave/" + robot_name + ".robotdata";
01657 //  //        file.open(filename.chars());
01658 //  //      }
01659 
01660 //    if (!file) 
01661 //      {
01662 //        send_message(LOAD_DATA_FINISHED);
01663 //        return;
01664 //      }
01665 
01666 //    char buf[256];
01667 //    if( binary )
01668 //      {
01669 //        char c;
01670 //        int i;
01671 //        while( !file.eof() )
01672 //          {
01673 //            for(i=0; i < 255 && file.get(c) ; i++)
01674 //              buf[i] = c;
01675 
01676 //            buf[i] = '\0';
01677 //            send_message(BIN_DATA_TO, i, buf);
01678 //          }
01679 //      }
01680 //    else
01681 //      {
01682 //        while( !file.eof() )
01683 //          {
01684           
01685 //            file.get(buf, 256 ,'\n');
01686 //            send_message(ASCII_DATA_TO, buf);
01687 //          }
01688 //      }
01689 
01690 //    send_message(LOAD_DATA_FINISHED);
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   // Draw Cannon
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   // Draw radar lines
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   // Draw robot angle line
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

Generated on Fri Oct 15 15:47:38 2004 for Real Time Battle by  doxygen 1.3.9.1