ORTS

FFLocPath.C

Go to the documentation of this file.
00001 
00002 #include "Global.H"
00003 #include "FFLocPath.H"
00004 #include "Options.H"
00005 #include "GameObj.H"
00006 #include <utility>
00007 #include <iterator>
00008 #include <math.h>
00009 #include "TR_PFEngine.H"
00010 
00011 
00012 using namespace std;
00013 
00014 #define TEST(x)
00015 //#define TEST(x) x
00016 
00017 
00018 
00019   void FFLocPath::add_options()
00020   {
00021     ::Options o("SimpleTerrain - ForceField");
00022     o.put("-costonly", "represent boundaries only by higher edge cost");
00023     //o.put("-makesquares" ,"compute the motion squares of objects");
00024     o.put("-highres", "use a high resolution world map (slower but more accurate)");
00025     o.put("-nopush", "turns off pushing");
00026   }
00027 
00028   //----------------------------------------------------------------------------- 
00029   static Loc get_center_loc(const Object *obj)
00030   {
00031     Loc l;
00032     obj->get_center(l.x, l.y);
00033     return l;
00034   }
00035 
00036 //   static ScalarPoint get_center_sp(const Object *obj)
00037 //   {
00038 //     ScalarPoint l;
00039 //     obj->get_center(l.x, l.y);
00040 //     return l;
00041 //   }
00042 
00043     static real8 path_length(Path &path)
00044   {
00045     if( path.locs.size() < 2 )
00046       return 0;
00047     real8 total = 0;
00048     for( Vector<Loc>::iterator i = ++path.locs.begin() ; i != path.locs.end() ; i++ )
00049       total += i->distance(*(i-1));
00050     return total;
00051   }
00052     
00053   // Assuming path is in the usual reversed order, with goal at locs[0]
00054   static real8 path_length_from(Path &path, const Loc& start_loc)
00055   {
00056     if( path.locs.size() < 1 ) 
00057       return 0;
00058     return start_loc.distance(path.locs[path.locs.size()-1]) + path_length(path);
00059   }
00060 
00061 FFLocPath::FFLocPath() {
00062     sint4 seed = 0;
00063     ::Options::get("-seed", seed);
00064     rand.srand(seed);
00065     bool nopush;
00066     ::Options::get("-nopush", nopush);
00067     if (nopush){
00068       pushing_on = false;
00069     }
00070     else{
00071       pushing_on = true;
00072     }
00073     //Options::get("-makesquares", makesquares);
00074   }
00075 
00076   //-----------------------------------------------------------------------------
00077   void FFLocPath::init(sint4 tiles_x_, sint4 tiles_y_, sint4 tile_points_, sint4 client_pID_, sint4 neutral_pID_)
00078   {
00079     TerrainBasicImp<FF_Task>::init(tiles_x_, tiles_y_, tile_points_,
00080                    client_pID_, neutral_pID_);
00081     std::cout << "tiles_x_ = " << tiles_x_ << endl; 
00082     
00083     // initialize the internal PFEngine
00084     Vector<sint4> levels_of_detail;
00085     bool high_resolution_only;
00086     Options::get("-highres", high_resolution_only);
00087 
00088     if( !high_resolution_only ) {
00089     levels_of_detail.push_back(4);  // default - use a resolution reduced by a factor of 4.
00090       }
00091       levels_of_detail.push_back(1); // also (or exclusively) maintain a full resolution view.
00092       pfEngine = boost::shared_ptr<GlobalPathfinder>(new TR_PFEngine(tiles_x_, tiles_y_, tile_points_, client_pID_, neutral_pID_));
00093     
00094     // initialize motion squares
00095 /*    if(makesquares){ // temporarily commented to prevent unused var warning -- dd
00096       sint4 area = tiles_x_ * tiles_y_;
00097       // sectors = new vector<Sector>(area); 
00098     }*/
00099 
00100       
00101   }
00102 
00103   //-----------------------------------------------------------------------------
00104   void FFLocPath::add_obj(const Object *obj)
00105   {
00106     TerrainBasicImp<FF_Task>::add_obj(obj);
00107     assert(pfEngine!=NULL);
00108     pfEngine->insert_object(obj);
00109     
00110     objects[obj] = Loc(-1,-1);
00111   }
00112 
00113   //-----------------------------------------------------------------------------
00114   void FFLocPath::update_obj(const Object *obj)
00115   {
00116     TerrainBasicImp<FF_Task>::update_obj(obj);
00117     assert(pfEngine!=NULL);
00118     pfEngine->update_object(obj);
00119   }
00120 
00121   //-----------------------------------------------------------------------------
00122   void FFLocPath::remove_obj(const Object *obj)
00123   {
00124     // shorthand
00125     typedef ObjIsGoalInTaskId::iterator OGIT;
00126 
00127     // remove from world representation
00128     assert(pfEngine!=NULL);
00129     pfEngine->remove_object(obj);
00130 
00131     // If we intended to stop it, we don't need to anymore
00132     objsToStop.erase(obj);
00133 
00134     // If this is the target of any existing task...
00135     pair<OGIT,OGIT> range = objIsGoalInTaskId.equal_range(obj);
00136     for( OGIT i = range.first ; i != range.second ; i++ ) {
00137       // Change the target of the task to the last known location of the object
00138       FIND(taskId2task, ti2tIt, i->second);
00139       assert(ti2tIt != taskId2task.end());
00140       
00141       ti2tIt->second->task.goal.target = Goal::LOCATION;
00142       Loc obj_center;
00143       ti2tIt->second->task.goal.obj->get_center(obj_center.x, obj_center.y);
00144       ti2tIt->second->task.goal.loc = obj_center;
00145 
00146     }
00147     
00148     TerrainBasicImp<FF_Task>::remove_obj(obj);
00149 
00150     objects.erase(obj);
00151   }
00152 
00153   //-----------------------------------------------------------------------------
00154   void FFLocPath::add_segments(const Vector<Segment> &segs)
00155   {
00156     TerrainBasicImp<FF_Task>::add_segments(segs);
00157     assert(pfEngine!=NULL);
00158     pfEngine->insert_boundaries(segs);
00159     FORALL(segs,i){
00160       segments.push_back(*i);
00161       segment_ends[i->l1] = true;
00162       segment_ends[i->l2] = true;
00163     }
00164     invalidate_paths(segs);
00165     
00166   }
00167 
00168   //----------------------------------------------------------------------------------
00169   void FFLocPath::cancel_task(const Object *obj)
00170   {
00171     objsToStop.insert(obj);
00172     TerrainBasicImp<FF_Task>::cancel_task(obj);
00173   }
00174 
00175   //----------------------------------------------------------------------------------
00176   void FFLocPath::remove_task(TaskId tid)
00177   {
00178     FIND (taskId2task, it, tid);
00179     if (it != taskId2task.end() ) {
00180       Task& task = it->second->task;
00181       objsToStop.insert(task.objs.begin(), task.objs.end());
00182     }
00183     TerrainBasicImp<FF_Task>::remove_task(tid);
00184   }
00185 
00186 
00187   //----------------------------------------------------------------------------------
00188  real8 FFLocPath::find_path(const Loc &/*l1*/, const Loc &/*l2*/, sint4 /*radius*/, Path * /*path*/, ConsiderObjects /*consider*/)
00189   {
00190     assert(0); // unimplemented yet    
00191     return -1;
00192   }
00193 
00194   //----------------------------------------------------------------------------------
00195   real8 FFLocPath::find_path(const Object *obj, const Goal &goal, Path *path, ConsiderObjects consider)
00196   {
00197     assert( goal.mode == Goal::TOUCH && "ATTACK, VICINITY modes are currently unimplemented");
00198     assert( (goal.target == Goal::LOCATION || goal.target == Goal::OBJ) && 
00199             "Unknown Goal::target type");
00200 
00201     Path result;
00202     bool found;
00203     if (goal.target == Goal::LOCATION) {
00204       found = pfEngine->find_path(obj, goal.loc, result,  consider);
00205     } else {
00206       found = pfEngine->find_path(obj, goal.obj, result,  consider);
00207     }
00208 
00209     if( !found )
00210       return -1;
00211 
00212     // need to return waypoints in a 'forward' order
00213     if( path != NULL ) {
00214       path->locs.clear();
00215       reverse_copy(result.locs.begin(), result.locs.end(), back_inserter(path->locs));
00216     }
00217 
00218     // compute and return the length of the path
00219     return path_length_from(result, get_center_loc(obj));
00220   }
00221 
00222   //----------------------------------------------------------------------------------
00223 
00224   // fixme: we only check the path of the *center* of the unit vs the new boundaries,
00225   // and we should account for its size (radius).
00226   void FFLocPath::invalidate_paths(const Vector<Segment> &segments)
00227   {
00228     FORALL(tasks, ti) {
00229       if (!ti->isValid() ) continue;
00230       // fixme: better handling of zcat != ON_LAND ?
00231       if (ti->path->obj->get_zcat() != Object::ON_LAND ) continue;
00232 
00233       FORALL(segments, si) {
00234         if (ti->path->is_intersect(*si) ) {
00235           // this path is invalid, mark as pending for (re)planning
00236           pendingTasks.push_back(ti);
00237           ti->isPending = true;
00238           cout << "Marked an invalid path" << endl;
00239           break;
00240         }
00241       }
00242     }
00243   }
00244 
00245   void FFLocPath::execute_tasks(Vector<MoveCmd> &cmds, Vector<StatusMsg> &msgs){
00246   
00247     //clear the reserved locations in the object map
00248     FORALL(objects, it){
00249       it->second = Loc(-1, -1);
00250     }
00251     // Execute all active tasks
00252     /*for (Tasks::iterator j = tasks.begin(); j != tasks.end();) {
00253       Tasks::iterator i = j++;*/
00254     FORALL(tasks, i) {
00255 
00256       // Report failure of planning (no path at all)
00257       if (i->noPathFound ) {
00258     TerrainBase::StatusMsg s;
00259     // fixme: this is not robust to future changes in the meaning of TaskId.
00260     s.task_id = (TerrainBase::TaskId)&(*i);
00261     s.obj = *(i->task.objs.begin());
00262     s.type = TerrainBase::StatusMsg::NO_PATH_FAILURE;
00263     msgs.push_back(s);
00264     continue;
00265       }
00266 
00267       // Skip invalid tasks.
00268       if (!i->isValid() ) { 
00269     TEST(cout << *i->task.objs.begin() << " task not valid" << endl;);
00270     continue;
00271       }
00272 
00273       UnitPath_FF &cur_path = *(i->path);
00274       const Object *obj = cur_path.obj;
00275 
00276       // Skip tasks that are waiting for a retry
00277       if (cur_path.sleeping()) {
00278     TEST(cout << obj << " path sleeping" << endl;);
00279     continue;
00280       }
00281 
00282       // Skip objects for which we gave a (move) action that is still pending
00283       /*
00284     if (obj->is_pending_action()) {
00285     TEST(cout << obj << " pending action" << endl;)
00286     continue;
00287     }
00288       */
00289 
00290       bool atGoal = is_at_goal(obj, i->task);
00291 
00292       // Look ahead: if the object will get to a waypoint in the next tick,
00293       // give the next action now the prevent it from wasting a tick on stopping.
00294       // This will cut a single tick at each waypoint, though it will really prevent 
00295       // the object from stopping only if there's no (network or processing) lag
00296       // between this client and the server.
00297       // atWaypoint can be true only if the current waypoint is an intermediate and
00298       // not the *final* waypoint/goal.
00299       //   bool atWaypoint = cur_path.current_target > 0 &&  // reverse order, goal==0
00300       //    is_at_location(obj, cur_path.path.at(cur_path.current_target));
00301 
00302       // Skip a moving object which is currently not at a waypoint/goal
00303       if (/*(obj->get_speed() > 0 || obj->get_moving() != 0) && !atWaypoint && */ !atGoal ) {
00304     TEST(cout << obj << " atWaypoint=" << atWaypoint << " speed=" << obj->get_speed() << " is_moving=" << obj->get_moving() << endl;);
00305     Loc target;
00306     //  bool deflected = get_forcefield_target(cur_path, target);
00307     //  bool nearWaypoint = is_near_waypoint(obj, cur_path.path.at(cur_path.current_target));
00308     //  if (nearWaypoint && deflected && cur_path.current_target > 0){
00309     //    bool valid = slide_wp(cur_path);
00310     //    if (!valid){
00311     //      i->isFailed = true;
00312     //      continue;
00313     //    }
00314     get_forcefield_target(cur_path, target);
00315     //  }
00316     add_move_command(obj, target, cmds);
00317 
00318     ///////////////////////////////
00319     
00320     Loc obj_center;
00321     obj->get_center(obj_center.x, obj_center.y);
00322 
00323 //  FORALL(i->followers, fol_it){
00324 //    get_forcefield_target(*fol_it, obj_center, target);
00325 //    add_move_command(*fol_it, target, cmds);
00326 //  }
00327     
00328     real8 distance = obj_center.distance(cur_path.path.at(cur_path.current_target));
00329     if (cur_path.spot != Loc(-1,-1)){
00330       real8 spot_distance = cur_path.spot.distance(cur_path.path.at(cur_path.current_target));
00331       if (distance >= spot_distance - ((real8)obj->get_max_speed())/2){
00332         if (cur_path.collision_step > 5){
00333           if (i->replanned < 1){ //fixed cap on number of replannings
00334            i->isFailed = true;
00335             failedTasks.push_back(i);
00336           }
00337         }
00338         if (cur_path.collision_step > 10){
00339           TerrainBase::StatusMsg s;
00340           //    fixme: this is not robust to future changes in the meaning of TaskId.
00341           s.task_id = (TerrainBase::TaskId)&(*i);
00342           s.obj = obj;
00343           s.type = TerrainBase::StatusMsg::MOVEMENT_FAILURE;
00344           msgs.push_back(s);
00345           cout << "Movement failure!" << endl;
00346         }
00347        
00348         cur_path.collision_step++;
00349       }
00350       else{
00351         cur_path.collision_step = 0;
00352         cur_path.spot = obj_center;
00353       }
00354     }
00355     else{
00356       cur_path.spot = obj_center;
00357       cur_path.collision_step = 0;
00358     }
00359     
00360     
00361     ///////////////////////////////
00362 
00363     continue;
00364       }
00365 
00366 
00367 
00368       // ok, so it needs attention:
00369       // 1. maybe it had reached the goal
00370       // 2. maybe it's at a waypoint (with the lookahead)
00371       // 3. maybe it needs the first orders
00372       // 4. maybe it unexpectedly collided with something
00373 
00374       if (atGoal ) {
00375 
00376     TEST(cout << obj << " arrived" << endl;)
00377 
00378       TerrainBase::StatusMsg s;
00379     // fixme: this is not robust to future changes in the meaning of TaskId.
00380     s.task_id = (TerrainBase::TaskId)&(*i);
00381     s.obj = obj; 
00382     s.type = TerrainBase::StatusMsg::ARRIVED;
00383     msgs.push_back(s);  
00384 
00385       }
00386   //     else if( atWaypoint || 
00387 //       cur_path.no_orders_yet || 
00388 //       cur_path.stopped_to_avoid_collision ) {
00389 
00390 //  // in all these cases we should just issue a move command
00391 
00392 //  TEST(cout << obj << " atWaypoint=" << atWaypoint
00393 //       << " no_orders_yet=" << cur_path.no_orders_yet
00394 //       << " stopped_to_avoid_collision=" << cur_path.stopped_to_avoid_collision
00395 //       << endl; );
00396 
00397 //  // if we are at a waypoint, move to next waypoint
00398 //      if( atWaypoint )
00399 //        cur_path.current_target--;
00400 //  cur_path.no_orders_yet = false;
00401 //  cur_path.stopped_to_avoid_collision = false;
00402 //  Loc target;
00403 //  get_forcefield_target(cur_path, target);
00404 //  add_move_command(obj, target, cmds);
00405 
00406 //       } 
00407       else {
00408 
00409     // Unexpected stop. The current policy is:
00410     // 1-2. First time => wait a little and send the move command again.
00411     // 3-4. Second stop at the same place => mark as failed and replan.
00412     // 5. Third stop at the same place => report failure.
00413 
00414 //  TEST(cout << obj << " unexpectedly stopped, collision_step=" << cur_path.collision_step << endl);
00415 
00416 //  Loc cur_position; obj->get_center(cur_position.x, cur_position.y);
00417 
00418 //  // First collision in this position:
00419 //  if (cur_path.spot != cur_position ) {
00420 //    cur_path.collision_step = 1;
00421 //    cur_path.mark_spot(cur_position);
00422 //    // sleep for a short random time, 500-999 millisecs
00423 //    cur_path.sleep(500 + (rand.rand_uint4() % 500));
00424 //  } else {
00425 //    cur_path.collision_step++;
00426 
00427 //    // Just finished the sleeping:
00428 //    if (cur_path.collision_step == 2 ) {
00429 //      Loc target;
00430 //      get_forcefield_target(cur_path, target);
00431 //      add_move_command(obj, target, cmds);
00432 //    }
00433 //    // Second collision
00434 //    else if (cur_path.collision_step == 3 ) {
00435 //      i->isFailed = true;
00436 //    }
00437 //    // Back from replanning
00438 //    else if (cur_path.collision_step == 4 ) {
00439 //      Loc target;
00440 //      get_forcefield_target(cur_path, target);
00441 //      add_move_command(obj, target, cmds);
00442 //    }
00443 //    // Third collision
00444 //    else if (cur_path.collision_step == 5 ) {
00445 //      TerrainBase::StatusMsg s;
00446 //      // fixme: this is not robust to future changes in the meaning of TaskId.
00447 //      s.task_id = (TerrainBase::TaskId)&(*i);
00448 //      s.obj = obj;
00449 //      s.type = TerrainBase::StatusMsg::MOVEMENT_FAILURE;
00450 //      msgs.push_back(s);
00451 //    }
00452 //  }
00453       }
00454     }
00455 
00456     //Pushing!
00457     if (pushing_on){
00458       FORALL(objects, objIt){
00459     const GameObj *gob = dynamic_cast<const GameObj*>(objIt->first);
00460     if (gob){
00461       if (objIt->second == Loc(-1,-1) && *(gob->sod.owner) == client_pID && objIt->first->get_max_speed() > 0){
00462         Loc target;
00463         get_push_target(objIt->first, target);
00464         add_move_command(objIt->first, target, cmds);
00465       }
00466     }
00467       }
00468     }
00469    
00470  // Priority of commands:
00471     // 1. stops to avoid a collision.
00472     // 2. moves.
00473     // 3. other stops (resulting from a cancelled task, etc.).
00474     
00475     // 2 above 3:
00476     FORALL(cmds, c) {
00477       objsToStop.erase(c->obj);
00478     }
00479 
00480     // With all movement commands were given while assuming an ideal-no-collisions
00481     // world, now check if any of our controlled objects are going to collide
00482     // (because of an existing movement vector, and also consider commands
00483     // we just intended to give).
00484     //resolve_friendly_collisions();
00485 
00486     // 1 above 2:
00487     for(typeof(cmds.begin()) c = cmds.begin() ; c != cmds.end() ; ) {
00488       FIND(objsToStop, s, c->obj);
00489       if( s != objsToStop.end() )
00490     c = cmds.erase(c);
00491       else
00492     c++;
00493     }
00494 
00495     // Return also the stop commands
00496     FORALL(objsToStop, oi) {
00497       const Object *obj = *oi;
00498 
00499       TerrainBase::MoveCmd m;
00500       m.obj = obj;
00501       obj->get_center(m.next_loc.x, m.next_loc.y); // doesn't really matter
00502       m.speed = 0; // 0 -> stop
00503       cmds.push_back(m);
00504     }
00505     objsToStop.clear();
00506 
00507     // remove finished tasks
00508     FORALL (msgs, t) {
00509       remove_task(t->task_id);
00510     }
00511     //motionSquares.clear();
00512   }
00513 
00514   void FFLocPath::add_move_command(const Object *obj, Loc target, Vector<TerrainBase::MoveCmd> &cmds){
00515     //hack: 
00516     if (abs(target.x) >= 500000){
00517        target.x = 499999;
00518      }
00519      if( abs(target.y) >= 500000){
00520          target.y = 499999;
00521      }
00522 
00523     TerrainBase::MoveCmd m;
00524     m.obj = obj;
00525     m.next_loc = target;
00526     m.speed = obj->get_max_speed();
00527     cmds.push_back(m);
00528   
00529     FIND (objects, it, obj);
00530     // assert(it != objects.end() && "hrmm... all objects should be in objects map");
00531     if (it != objects.end()){
00532       Loc curr_loc;
00533       obj->get_center(curr_loc.x, curr_loc.y);
00534       Vec_2D vec(target.x - curr_loc.x, target.y - curr_loc.y);
00535       
00536       real8 k = ((real8)obj->get_max_speed()) / vec.length();
00537       
00538       vec = vec.multiply(k);
00539  
00540       it->second.x = curr_loc.x + vec.x;
00541       it->second.y = curr_loc.y + vec.y;
00542     }
00543   
00544   }
00545 
00546   sint4 FFLocPath::what_team(const Object *obj){
00547     const GameObj *p = dynamic_cast<const GameObj*>(obj);
00548     if (p){
00549       return *(p->sod.owner);
00550     }
00551     else
00552       return -1;
00553   }
00554 
00555   void FFLocPath::get_push_target(const Object *obj, Loc &output){
00556         //const Object *obj = path.obj;
00557     if (obj->get_shape() != Object::CIRCLE){
00558       return; //only circle movement implemented -- this also functions as a crude check for buildings
00559     }
00560   
00561 
00562     Vec_2D force_vec(0,0);
00563 
00564     FORALL(objects, i){
00565       const GameObj *gob = dynamic_cast<const GameObj*>(i->first);
00566       if (!gob){continue;}
00567       
00568       //don't consider any object that's not your own as a force that can push you
00569       if (*(gob->sod.owner) != client_pID){continue;}
00570       
00571       if (obj == i->first){
00572     continue;
00573       }
00574       Vec_2D vec;
00575       if (i->first->get_shape() == Object::CIRCLE){
00576     Loc obstacle_center;
00577     if (i->second == Loc(-1, -1)){
00578       i->first->get_center(obstacle_center.x, obstacle_center.y);
00579     }
00580     else{
00581       obstacle_center = i->second;
00582     }
00583     vec = get_point_repulsion(obj, obstacle_center, i->first->get_radius());
00584     force_vec = force_vec + vec;
00585       }
00586       else if (i->first->get_shape() == Object::RECTANGLE){
00587     Loc u_l, u_r, l_r, l_l; //upper-left, upper-right, lower-right, lower-left
00588     i->first->get_p1(u_l.x, u_l.y);
00589     i->first->get_p2(l_r.x, l_r.y);
00590     u_r.x = l_r.x;
00591     u_r.y = u_l.y;
00592       
00593     l_l.x = u_l.x;
00594     l_l.y = l_r.y;
00595       
00596     Segment seg;
00597     seg.l1 = u_l;
00598     seg.l2 = u_r;      
00599     vec = get_line_repulsion(obj, seg);
00600     //force_vec = force_vec + vec;
00601 
00602     seg.l1 = u_r;
00603     seg.l2 = l_r;
00604     vec = vec + get_line_repulsion(obj, seg);
00605     //force_vec = force_vec + vec;
00606 
00607     seg.l1 = l_r;
00608     seg.l2 = l_l;
00609     vec = vec + get_line_repulsion(obj, seg);
00610     //force_vec = force_vec + vec;
00611 
00612     seg.l1 = l_l;
00613     seg.l2 = u_l;
00614     vec = vec + get_line_repulsion(obj, seg);
00615     //force_vec = force_vec + vec;
00616     if (vec == Vec_2D(0,0)){
00617       vec = vec + get_point_repulsion(obj, u_l);
00618       vec = vec + get_point_repulsion(obj, u_r);
00619       vec = vec + get_point_repulsion(obj, l_l);
00620       vec = vec + get_point_repulsion(obj, l_r);
00621     }
00622     force_vec = force_vec + vec;
00623     
00624       }
00625     }
00626     Vec_2D wall_repulsion;
00627     FORALL(segment_ends, ends_it){
00628       ends_it->second = true;
00629     }
00630     FORALL(segments, seg_it){
00631       Vec_2D vec;
00632       vec = get_line_repulsion(obj, *seg_it);
00633       if (vec != Vec_2D(0,0)){
00634     FIND(segment_ends, ends_it, seg_it->l1);
00635     if (ends_it != segment_ends.end())
00636       ends_it->second = false;
00637     FIND(segment_ends, ends_it2, seg_it->l2);
00638     if (ends_it != segment_ends.end())
00639       ends_it->second = false;
00640       }
00641       wall_repulsion = wall_repulsion + get_line_repulsion(obj, *seg_it);
00642       // force_vec = force_vec + vec;
00643     }
00644     FORALL(segment_ends, endit){
00645       if (endit->second){
00646     wall_repulsion = wall_repulsion + get_point_repulsion(obj, endit->first);
00647       }
00648     }
00649     force_vec = force_vec + wall_repulsion;
00650 
00651     if (force_vec != Vec_2D(0,0)){
00652       Vec_2D rand_vec;
00653       Vec_2D half_force = Vec_2D(force_vec.x/2, force_vec.y/2);
00654       
00655       uint4 rand_angle_int = rand.rand_uint4() % 62;
00656       real8 rand_angle = ((real8)rand_angle_int)/ 10;
00657       rand_vec.x = Vec_2D::round(half_force.length() * cos(rand_angle));
00658       rand_vec.y = Vec_2D::round(half_force.length() * sin(rand_angle));
00659       
00660       force_vec = force_vec + rand_vec;
00661     }
00662 
00663    //  if (force_vec == Vec_2D(0,0)){
00664 //       output = path.path.at(path.current_target);
00665 //       return false;
00666 //     }
00667     
00668     Loc object_center;
00669     obj->get_center(object_center.x, object_center.y);
00670     
00671     output.x = object_center.x + force_vec.x;
00672     output.y = object_center.y + force_vec.y;
00673   }
00674 
00675   void FFLocPath::get_forcefield_target(const Object *obj, const Loc &attractor, Loc &output){
00676     //const Object *obj = path.obj;
00677     assert(obj->get_shape() == Object::CIRCLE && "Only Circle Movement implemented");
00678   
00679 
00680     Vec_2D force_vec(0,0);
00681 
00682     FORALL(objects, i){
00683       if (obj == i->first){
00684     continue;
00685       }
00686       Vec_2D vec;
00687       if (i->first->get_shape() == Object::CIRCLE){
00688     Loc obstacle_center;
00689     if (i->second == Loc(-1, -1)){
00690       i->first->get_center(obstacle_center.x, obstacle_center.y);
00691     }
00692     else{
00693       obstacle_center = i->second;
00694     }
00695     vec = get_point_repulsion(obj, obstacle_center, i->first->get_radius());
00696     force_vec = force_vec + vec;
00697       }
00698       else if (i->first->get_shape() == Object::RECTANGLE){
00699     Loc u_l, u_r, l_r, l_l; //upper-left, upper-right, lower-right, lower-left
00700     i->first->get_p1(u_l.x, u_l.y);
00701     i->first->get_p2(l_r.x, l_r.y);
00702     u_r.x = l_r.x;
00703     u_r.y = u_l.y;
00704       
00705     l_l.x = u_l.x;
00706     l_l.y = l_r.y;
00707       
00708     Segment seg;
00709     seg.l1 = u_l;
00710     seg.l2 = u_r;      
00711     vec = get_line_repulsion(obj, seg);
00712     //force_vec = force_vec + vec;
00713 
00714     seg.l1 = u_r;
00715     seg.l2 = l_r;
00716     vec = vec + get_line_repulsion(obj, seg);
00717     //force_vec = force_vec + vec;
00718 
00719     seg.l1 = l_r;
00720     seg.l2 = l_l;
00721     vec = vec + get_line_repulsion(obj, seg);
00722     //force_vec = force_vec + vec;
00723 
00724     seg.l1 = l_l;
00725     seg.l2 = u_l;
00726     vec = vec + get_line_repulsion(obj, seg);
00727     //force_vec = force_vec + vec;
00728     if (vec == Vec_2D(0,0)){
00729       vec = vec + get_point_repulsion(obj, u_l);
00730       vec = vec + get_point_repulsion(obj, u_r);
00731       vec = vec + get_point_repulsion(obj, l_l);
00732       vec = vec + get_point_repulsion(obj, l_r);
00733     }
00734     force_vec = force_vec + vec;
00735     
00736       }
00737     }
00738     Vec_2D wall_repulsion;
00739     FORALL(segment_ends, ends_it){
00740       ends_it->second = true;
00741     }
00742     FORALL(segments, seg_it){
00743       Vec_2D vec;
00744       vec = get_line_repulsion(obj, *seg_it);
00745       if (vec != Vec_2D(0,0)){
00746     FIND(segment_ends, ends_it, seg_it->l1);
00747     if (ends_it != segment_ends.end())
00748       ends_it->second = false;
00749     FIND(segment_ends, ends_it2, seg_it->l2);
00750     if (ends_it != segment_ends.end())
00751       ends_it->second = false;
00752       }
00753       wall_repulsion = wall_repulsion + get_line_repulsion(obj, *seg_it);
00754       // force_vec = force_vec + vec;
00755     }
00756     FORALL(segment_ends, endit){
00757       if (endit->second){
00758     wall_repulsion = wall_repulsion + get_point_repulsion(obj, endit->first);
00759       }
00760     }
00761     force_vec = force_vec + wall_repulsion;
00762   
00763    //  if (force_vec == Vec_2D(0,0)){
00764 //       output = path.path.at(path.current_target);
00765 //       return false;
00766 //     }
00767     
00768     Vec_2D attract_vec, scaled_attract_vec;
00769     Loc obj_center;
00770     obj->get_center(obj_center.x, obj_center.y);
00771     attract_vec = Vec_2D(obj_center, attractor);
00772          
00773     real8 k;
00774     if (attract_vec.length() < 1){
00775       k = ATTRACTOR_FORCE;
00776     }
00777     else{
00778       k = ATTRACTOR_FORCE / attract_vec.length();
00779     }
00780     scaled_attract_vec = attract_vec.multiply(k); 
00781   
00782     force_vec = force_vec + scaled_attract_vec;
00783   
00784     restrict_vector(attract_vec, force_vec);
00785 
00786     if (force_vec == Vec_2D(0,0)){
00787       force_vec = Vec_2D(attract_vec.y, -attract_vec.x);
00788     }
00789     
00790     Loc object_center;
00791     obj->get_center(object_center.x, object_center.y);
00792     
00793     output.x = object_center.x + force_vec.x;
00794     output.y = object_center.y + force_vec.y;
00795  
00796   }
00797 
00798   void FFLocPath::get_forcefield_target(UnitPath_FF &path, Loc &output){
00799     Loc attractor = get_attractor(path);
00800     get_forcefield_target(path.obj, attractor, output);
00801   }
00802   
00803 
00804   Loc FFLocPath::get_attractor(UnitPath_FF &path){
00805     Loc object_center, attractor;
00806     Vec_2D to_wp, scaled_to_wp;
00807     path.obj->get_center(object_center.x, object_center.y);
00808     if (path.current_target >= ((sint4)path.path.size()) - 1){
00809       attractor = object_center;
00810     }
00811     else{
00812       attractor = find_point_on_line(object_center, path.path.at(path.current_target), path.path.at(path.current_target+1));
00813     }
00814     to_wp = Vec_2D(path.path.at(path.current_target).x - attractor.x, path.path.at(path.current_target).y - attractor.y);
00815     real8 offset = path.obj->get_max_speed() * PATH_LOOK_AHEAD;
00816     //std::cout << "k = " << offset/to_wp.length() << "\n";
00817     if (to_wp.length() == 0)
00818       scaled_to_wp = Vec_2D(1,1);
00819     else
00820       scaled_to_wp = to_wp.multiply(offset / to_wp.length());
00821     while (scaled_to_wp.length() > to_wp.length()){
00822       offset = offset - to_wp.length();
00823       attractor = path.path.at(path.current_target);
00824       if (path.current_target == 0){
00825     scaled_to_wp = Vec_2D(0,0);
00826     break;
00827       }
00828       path.current_target--;
00829       //std::cout << "new wp: " << path.path.at(path.current_target).x 
00830       //        << ", " << path.path.at(path.current_target).y << "\n"; 
00831       to_wp = Vec_2D(path.path.at(path.current_target).x - attractor.x, path.path.at(path.current_target).y - attractor.y);
00832       scaled_to_wp = to_wp.multiply(offset / to_wp.length());
00833     }
00834     
00835     attractor.x = attractor.x + scaled_to_wp.x;
00836     attractor.y = attractor.y + scaled_to_wp.y;
00837     
00838     return attractor;
00839   }
00840   
00841   Loc FFLocPath::find_point_on_line(Loc loc, Loc line_start, Loc line_end){
00842     
00843     Vec_2D line_to_obj, n;
00844    
00845     line_to_obj = Vec_2D(loc.x - line_start.x, loc.y - line_start.y);
00846     n = Vec_2D(line_end.y - line_start.y, -(line_end.x - line_start.x)); //perpendicular to segment
00847   
00848     line_to_obj = line_to_obj.project_onto(n);
00849   
00850     Loc point_on_line(loc.x - line_to_obj.x, loc.y - line_to_obj.y);
00851     
00852     return point_on_line;
00853  
00854   }
00855 
00856 //   bool FFLocPath::slide_wp(UnitPath_FF &path){
00857   
00858 //     Loc next_wp, curr_wp, temp_wp;
00859 //     next_wp = path.path.at(path.current_target -1);
00860 //     curr_wp = path.path.at(path.current_target);
00861 //     real8 d = next_wp.distance(curr_wp);
00862   
00863 //     Vec_2D wp_vector(next_wp.x - curr_wp.x, next_wp.y - curr_wp.y);
00864   
00865 //     for(uint4 i = 1; ; i++){
00866 //       real8 k = ((real8)(i * path.obj->get_max_speed())) / d;
00867 //       if (k > 1){
00868 //  return false;
00869 //       }
00870 //       Vec_2D scaled_wp_vec = wp_vector.multiply(k);
00871    
00872 //       temp_wp.x = curr_wp.x + scaled_wp_vec.x;
00873 //       temp_wp.y = curr_wp.y + scaled_wp_vec.y;
00874 //       if (!is_near_waypoint(path.obj, temp_wp))
00875 //  break;
00876 //     }
00877 //     path.path.at(path.current_target) = temp_wp;
00878 //     return true;
00879 //   }
00880 
00881   void FFLocPath::restrict_vector(const Vec_2D &target_vec, Vec_2D &vec){
00882 
00883     real8 dot_prod = vec.dot_prod(target_vec);
00884     if (dot_prod < 0){
00885       Vec_2D perpendicular(target_vec.y, -target_vec.x);
00886       vec = vec.project_onto(perpendicular);
00887     }
00888   
00889   
00890   }
00891 
00892   Vec_2D FFLocPath::get_point_repulsion(const Object *moving_obj, const Loc &point, sint4 radius){
00893     Vec_2D vec;
00894     Loc center;
00895     moving_obj->get_center(center.x, center.y);
00896     real8 d = center.distance(point) - moving_obj->get_radius() - radius +1;
00897   
00898     if (d < moving_obj->get_max_speed() * FIELD_RANGE_MULTIPLIER){
00899       vec.x = center.x - point.x;
00900       vec.y = center.y - point.y;
00901       real8 k = REPULSOR_BASELINE / (d * d * vec.length());
00902       vec = vec.multiply(k);
00903     }
00904     return vec;
00905   }
00906 #if 0
00907   Vec_2D FFLocPath::get_line_repulsion(const Object *moving_obj, const Segment &seg){
00908     Loc q, p;
00909     Vec_2D line_to_obj, n;
00910     moving_obj->get_center(q.x, q.y);
00911     p = seg.l1;
00912     line_to_obj = Vec_2D(q.x - p.x, q.y - p.y);
00913     n = Vec_2D(seg.l1.y - seg.l2.y, -(seg.l1.x - seg.l2.x)); //perpendicular to segment
00914   
00915     line_to_obj = line_to_obj.project_onto(n);
00916   
00917     Loc point_on_line(q.x - line_to_obj.x, q.y - line_to_obj.y);
00918     Vec_2D to_l1, to_l2;
00919   
00920     to_l1 = Vec_2D(seg.l1.x - point_on_line.x, seg.l1.y - point_on_line.y);
00921     to_l2 = Vec_2D(seg.l2.x - point_on_line.x, seg.l2.y - point_on_line.y);
00922   
00923     if (to_l1.dot_prod(to_l2) > 0){ //if both vectors are pointing in the same direction
00924     //   if(to_l1.length() > to_l2.length()){
00925 //  return get_point_repulsion(moving_obj, seg.l2);
00926 //       }
00927 //       else{
00928 //  return get_point_repulsion(moving_obj, seg.l1);
00929 //       }
00930     }
00931     else{
00932       real8 d = q.distance(point_on_line) - moving_obj->get_radius() +1;
00933       if (d < moving_obj->get_max_speed() * FIELD_RANGE_MULTIPLIER){
00934     real8 k = REPULSOR_BASELINE / (d * d * line_to_obj.length());
00935     return line_to_obj.multiply(k);
00936       }
00937     }
00938     return Vec_2D(0,0);
00939   }
00940 #endif
00941 
00942 Vec_2D FFLocPath::get_line_repulsion(const Object *moving_obj, const Segment &seg)
00943   {
00944     Loc loc;
00945     moving_obj->get_center(loc.x, loc.y);
00946     const Loc &line_start = seg.l1;
00947     const Loc &line_end = seg.l2;
00948 
00949     sint4 line_x = line_end.x - line_start.x;
00950     sint4 line_y = line_end.y - line_start.y;
00951 
00952     sint4 v_x = loc.x - line_start.x;
00953     sint4 v_y = loc.y - line_start.y;
00954 
00955     sint4 a = line_x * v_x + line_y * v_y;
00956     sint4 b = line_x * line_x + line_y * line_y;
00957 
00958     Loc proj(line_start.x + line_x * a / b, line_start.y + line_y * a / b);
00959 
00960     Vec_2D line_to_obj(loc.x - proj.x, loc.y - proj.y);
00961     Vec_2D to_l1, to_l2;
00962 
00963     to_l1 = Vec_2D(seg.l1.x - proj.x, seg.l1.y - proj.y);
00964     to_l2 = Vec_2D(seg.l2.x - proj.x, seg.l2.y - proj.y);
00965 
00966     if (to_l1.dot_prod(to_l2) > 0){ //if both vectors are pointing in the same direction
00967     //   if(to_l1.length() > to_l2.length()){
00968 //  return get_point_repulsion(moving_obj, seg.l2);
00969 //       }
00970 //       else{
00971 //  return get_point_repulsion(moving_obj, seg.l1);
00972 //       }
00973     }
00974     else{
00975       real8 d = loc.distance(proj) - moving_obj->get_radius() +1;
00976       if (d < moving_obj->get_max_speed() * FIELD_RANGE_MULTIPLIER /2){
00977         real8 k = REPULSOR_BASELINE /  (d * d * line_to_obj.length());
00978     return line_to_obj.multiply(k);
00979       }
00980     }
00981     return Vec_2D(0,0);
00982 
00983     /*
00984     Loc c;
00985     moving_obj->get_center(c.x, c.y);
00986 
00987     sint4 ux = seg.l2.x - seg.l1.x;
00988     sint4 uy = seg.l2.y - seg.l1.y;
00989     sint4 vx = c.x - seg.l1.x;
00990     sint4 vy = c.y - seg.l1.y;
00991 
00992     sint4 u_v = ux * vx + uy * vy; // u dot v
00993     if (u_v <= 0) return Vec_2D(0,0);
00994 
00995     sint4 u_u = ux * ux + uy * uy; // u dot u
00996     if (u_u <= u_v) return Vec_2D(0,0);
00997 
00998     real8 b = real8(u_v) / real8(u_u);
00999 
01000     Loc proj((sint4)(seg.l1.x+b*ux), (sint4)(seg.l1.y+b*uy)); // projection to the segment
01001 
01002     real8 d1 = c.distance(proj);
01003     real8 d2 = d1 - moving_obj->get_radius() +1;
01004 
01005     if (d2 < moving_obj->get_max_speed() * FIELD_RANGE_MULTIPLIER) {
01006       real8 k = REPULSOR_BASELINE / (d2 * d2 * d1);
01007       Vec_2D vec(c.x - proj.x, c.y - proj.y);
01008       return vec.multiply(k);
01009     }
01010     return Vec_2D(0,0);
01011     */
01012   }
01013 
01014   //-------------------------------------------------------------------------
01015 
01016   bool FFLocPath::plan_tasks(uint4 max_time)
01017   {
01018     assert(pfEngine!=NULL);
01019     sint4 stop_time = 0;
01020     if(max_time > 0){
01021       stop_time = (sint4)SDL_GetTicks() + max_time;
01022     }
01023 
01024     // cout << "Chance To Plan Task\n" ;
01025 
01026     // try to plan one failed and one pending tasks
01027     bool did_something = plan_failed_task();
01028     bool did_some_more = plan_pending_task();
01029     sint4 counter = 0;
01030     //Continue planning until we have reached the max_time
01031     while( (sint4)SDL_GetTicks() < stop_time && (!pendingTasks.empty() || !failedTasks.empty() )) {
01032       if(counter++ % 2 == 0){
01033     //did_something = plan_failed_task(stop_time);
01034     did_something = plan_failed_task();
01035       }
01036       else{
01037     //did_some_more = plan_pending_task(stop_time);
01038     did_some_more = plan_pending_task();
01039       }
01040       did_some_more = did_something || did_some_more; // careful not to short-circuit!
01041     }
01042 
01043 
01044 
01045     did_something = did_some_more || did_something;
01046     return did_something;
01047 
01048 
01049   }
01050 
01051   //----------------------------------------------------------------------------------
01052 bool FFLocPath::plan_pending_task()
01053   {
01054     if (pendingTasks.empty()) return false;
01055 
01056     TIter tit = pendingTasks.front(); pendingTasks.pop_front();
01057     // mark the task as handled
01058     tit->isPending = false;
01059 
01060     // if the object is moving, stop it first and come back to it later
01061     assert(tit->task.objs.size() > 0);
01062 
01063 //     bool moving = false;
01064 //     FORALL(tit->task.objs, it){
01065 //       if ((*it)->get_speed()>0 || (*it)->get_moving()){
01066 //  moving = true;
01067 //  break;
01068 //       }
01069 //     }
01070 
01071 //     if (moving) {
01072 //       FORALL(tit->task.objs, it){
01073 //  objsToStop.insert(*it);
01074 //       }
01075 //       pendingTasks.push_back(tit);
01076 //       return false;
01077 //       // fixme: might be better to try another pending task already in this tick...
01078 //     }
01079 
01080     // plan
01081     TEST(cout << obj << " planning pending path" << endl);
01082     plan_task(tit);
01083     return true;
01084   }
01085 
01086   //-------------------------------------------------------------------
01087   struct FindFailed {
01088     bool operator()(FF_Task &task) { return task.isFailed && !task.noPathFound; };
01089   };
01090 
01091   //-------------------------------------------------------------------
01092   FFLocPath::TIter FFLocPath::get_random_failed_task(void)
01093   {
01094     // find a failed path for which we don't yet know that 'noPathFound'
01095     // (ie we still didn't try to replan and found that there is no path)
01096     if( tasks.empty() )
01097       return tasks.end();
01098 
01099     // start the search with in a random position to avoid planning the same
01100     // path repeatedly (in case it is immediately marked as failed again).
01101     int skip = rand(tasks.size());
01102     TIter start_at = tasks.begin();
01103     advance(start_at, skip);
01104 
01105     // search from the middle to the end
01106     TIter tit = find_if(start_at, tasks.end(), FindFailed());
01107     // if found
01108     if( tit != tasks.end() )
01109       return tit;
01110     // else, search from start to middle
01111     tit = find_if(tasks.begin(), start_at, FindFailed());
01112     return (tit != start_at)? tit : tasks.end();
01113   }
01114   //-------------------------------------------------------------------------------
01115 
01116   //----------------------------------------------------------------------------------
01117   bool FFLocPath::plan_failed_task()
01118   {
01119     if (failedTasks.empty()) return false;
01120 
01121     TIter tit = failedTasks.front(); failedTasks.pop_front();
01122 
01123     // if the object is moving, stop it first and come back to it later
01124     assert(tit->task.objs.size() > 0);
01125 
01126    //  bool moving = false;
01127 //     FORALL(tit->task.objs, it){
01128 
01129 //  if ((*it)->get_speed()>0 || (*it)->get_moving()){
01130 //  moving = true;
01131 //  break;
01132 //       }
01133 
01134 
01135 //     }
01136 
01137 //     if (moving) {
01138 //       FORALL(tit->task.objs, it){
01139 //  objsToStop.insert(*it);
01140 //       }
01141 //       failedTasks.push_back(tit);
01142 //       return true;
01143 //       // fixme: might be better to try another pending task already in this tick...
01144 //     }
01145 
01146     // plan
01147     TEST(cout << obj << " planning pending path" << endl);
01148     plan_task(tit);
01149     tit->replanned++;
01150 
01151     return true;
01152   }
01153 
01154   //-------------------------------------------------------------------
01155 //   bool ST_ForceField::plan_failed_task(void)
01156 //   {
01157 //     assert(pfEngine!=NULL);
01158 
01159 //     // get a failed task
01160 //     TIter tit = get_random_failed_task();
01161 //     if( tit == tasks.end() )
01162 //       return false;
01163 
01164 //     // if the object is moving, stop it first and come back to it later
01165 //     assert(tit->task.objs.size() > 0);
01166 //     const Object *obj = *(tit->task.objs.begin());
01167 
01168 //     if( obj->get_speed() > 0 || obj->get_moving() ) {
01169 //       objsToStop.insert(obj);
01170 //       return false;
01171 //       // fixme: might be better to try another failed task already in this tick...
01172 //     }
01173 //     tit->replanned++;
01174 //     // find-path
01175 //     TEST(cout << obj << " replanning path" << endl);
01176 //     plan_task(tit);
01177 //     return true;
01178 //   }
01179 
01180   //-------------------------------------------------------------------
01181   void FFLocPath::plan_task(TIter tit)
01182   {
01183     Path newpath;
01184     bool found;
01185 
01186     set<const Object*>::iterator obj_it = tit->task.objs.begin();
01187 
01188     // Object to move
01189     const Object *obj = *obj_it;
01190 
01191 
01192     // obj_it++;
01193     //remove the members of the group from the representation
01194   //   for (; obj_it != tit->task.objs.end(); obj_it++){
01195 //       tit->followers.push_back(*obj_it);
01196 //       pfEngine->remove_object(*obj_it);
01197 //     }
01198 //    cout << "CALLING GLOBAL PATHFINDER\n";
01199     if (tit->task.goal.target == Goal::LOCATION) {
01200       found = pfEngine->find_path(obj, tit->task.goal.loc, newpath, IGNORE_ALL_MOBILE_OBJS);
01201       if (found){
01202     newpath.locs[0] = tit->task.goal.loc;
01203       }
01204     } else {
01205       assert (tit->task.goal.target == Goal::OBJ);
01206       assert (!pushing_on ||
01207           what_team(tit->task.goal.obj) != client_pID ||
01208           tit->task.goal.mode != Goal::TOUCH ||
01209           tit->task.goal.obj->get_max_speed() <= 0); //because you'll push the object out of the way
01210       cout << "--------asking for path to obj-------\n";
01211       found = pfEngine->find_path(obj, tit->task.goal.obj, newpath, IGNORE_ALL_MOBILE_OBJS);
01212     }
01213 
01214     //add the members of the group back into the representation
01215  //    obj_it = tit->task.objs.begin();
01216 //     obj_it++;
01217 //     for (; obj_it != tit->task.objs.end(); obj_it++){
01218 //       pfEngine->insert_object(*obj_it);
01219 //     }
01220 
01221     // insert results into data structures
01222     if( found ) {
01223       assert(newpath.locs.size() > 0);
01224       tit->set_path(obj, newpath.locs);
01225       tit->isFailed = false;
01226     }
01227     else {
01228       cout << "WTF!!?! NO Path Found\n";
01229       // fixme: maybe add to "failed"/sleep etc. ?
01230       tit->noPathFound = true;
01231     }
01232   }
01233 
01234   //-------------------------------------------------------------------
01235 
01236   bool FFLocPath::is_at_location(const Object* obj, const Loc& target)
01237   {
01238     Loc position; obj->get_center(position.x, position.y);
01239     return position.distance(target) <= obj->get_speed();
01240   }
01241 
01242   //-------------------------------------------------------------------
01243   
01244   bool FFLocPath::is_near_location(const Object *obj, const Loc& target, sint4 range){
01245     Loc position; obj->get_center(position.x, position.y);
01246     return position.distance(target) <= range;
01247   }
01248 
01249   //-------------------------------------------------------------------
01250   bool FFLocPath::is_at_goal(const Object* obj, const Task& task)
01251   {
01252     // Getting to the goal depends on the definition of the task:
01253     if (task.goal.target == Goal::OBJ ) {
01254       switch(task.goal.mode) {
01255       case Goal::TOUCH :
01256     return( obj->distance_to(*task.goal.obj) <= 1 );
01257     // using 1-tick look-ahead:
01258     //return( obj->distance_to(*task.goal_obj) <= obj->get_speed() );
01259     break;
01260 
01261       case Goal::VICINITY :
01262     
01263     return (obj->distance_to(*task.goal.obj) <= task.goal.distance);
01264     //assert(0 && "Not implemented yet");
01265     break;
01266 
01267       case Goal::ATTACK :
01268 
01269     return(is_in_range(obj, task.goal.obj));
01270              
01271     break;
01272 
01273       default:
01274     ERR("Unknown mode");
01275       }
01276     } else if (task.goal.target == Goal::LOCATION ) {
01277       switch(task.goal.mode) {
01278       case Goal::TOUCH :
01279     return is_at_location(obj, task.goal.loc);
01280     break;
01281 
01282       case Goal::VICINITY :
01283     return is_near_location(obj, task.goal.loc, task.goal.distance);
01284     //assert(0 && "Not implemented yet");
01285     break;
01286 
01287       case Goal::ATTACK :
01288     return(is_in_range(obj, task.goal.loc));
01289     break;
01290 
01291       default:
01292     ERR("Unknown mode");
01293       }
01294     } else {
01295       ERR("Unknown target type");
01296     }
01297     return false;
01298   }
01299   
01300 
01301   //-------------------------------------------------------------------
01302 
01303   bool FFLocPath::is_in_range(const Object *moving_obj, const Loc goal_loc){
01304     //fixme: does not check if unit can see the target. 
01305     const GameObj *gob = dynamic_cast<const GameObj*>(moving_obj);
01306     sint4 range = 1;
01307     if (gob){
01308       ScriptObj *weapon = gob->component("weapon");
01309       const sintptr *r = weapon->get_const_int_ptr("max_ground_range");
01310       if (r){
01311     range = *r;
01312       }
01313     }
01314     sint4 x,y;
01315     moving_obj->get_center(x,y);
01316     Loc obj(x,y);
01317   
01318     return ( obj.distance(goal_loc) <= range );
01319     
01320     // this is the check in ShooterAI. Other way makes more intuitive sense though...
01321     //     real8 rdist = moving_obj->distance_to(*goal_obj);
01322     //     sint4 sdist = (sint4)floor(rdist);
01323     //     return (sdist <= range);
01324   }
01325 
01326   bool FFLocPath::is_in_range(const Object *moving_obj, const Object *goal_obj){
01327     //fixme: does not check if unit can see each other. 
01328     const GameObj *gob = dynamic_cast<const GameObj*>(moving_obj);
01329     sint4 range = 1;
01330     if (gob){
01331       ScriptObj *weapon = gob->component("weapon");
01332       const sintptr *r = weapon->get_const_int_ptr("max_ground_range");
01333       if (r){
01334     range = *r;
01335       }
01336     }
01337   
01338     //if not a GameObj or with no weapon range, should behave exactly
01339     //like the check for touch.
01340     return ( moving_obj->distance_to(*goal_obj) <= range );
01341     
01342     // this is the check in ShooterAI. Other way makes more intuitive sense though...
01343     //     real8 rdist = moving_obj->distance_to(*goal_obj);
01344     //     sint4 sdist = (sint4)floor(rdist);
01345     //     return (sdist <= range);
01346   }
01347 
01348 
01349   //-----------------------------------------------------------------------
01350   //------------------------Vec_2D-----------------------------------------
01351   //-----------------------------------------------------------------------
01352   Vec_2D Vec_2D::operator+(const Vec_2D &other) const{
01353     return Vec_2D(x + other.x, y + other.y);
01354   }
01355  
01356   Vec_2D Vec_2D::operator-(const Vec_2D &other) const{
01357     return Vec_2D(x - other.x, y - other.y);
01358   }
01359 
01360   sint4 Vec_2D::dot_prod(const Vec_2D &other) const{
01361     return x*other.x + y*other.y;
01362   }
01363 
01364   real8 Vec_2D::length() const{
01365     real8 length = sqrt(((real8)x)*x + y*y);
01366     return length;
01367   }
01368 
01369   Vec_2D Vec_2D::project_onto(const Vec_2D &other) const{
01370     real8 k = ((real8)this->dot_prod(other)) / other.dot_prod(other);
01371     return other.multiply(k);
01372   }
01373 
01374   Vec_2D Vec_2D::multiply(real8 k) const{
01375     return Vec_2D(round(k * x), round(k * y));
01376   }
01377 
01378   bool Vec_2D::operator==(const Vec_2D &other) const{
01379     return (x == other.x && y == other.y); 
01380   }
01381   
01382   bool Vec_2D::operator!=(const Vec_2D &other) const{
01383     return !(*this == other); 
01384   }
01385   sint4 Vec_2D::round(real8 real){
01386     real8 i;
01387     i = floor(real + 0.5);
01388     return (sint4)i;
01389   }
01390 
01391   bool Loc_less::operator() (Loc a, Loc b) const {
01392     if (a.x < b.x){
01393       return true;
01394     }
01395     else if (a.x == b.x && a.y < b.y){
01396       return true;
01397     }
01398     return false;
01399   }
01400 
01401 
01402 
01403 
01404   //----------------------------------------------------------------------------------
01405 
01406 #define EPS 1e-9f
01407 
01408 
01409 //   UnitPath_FF::UnitPath_FF(const Object *obj_, const Vector<Loc> &path_)
01410 //     : obj(obj_), path(path_), no_orders_yet(true), 
01411 //       stopped_to_avoid_collision(false), collision_step(0), wakeup(0)
01412 //   {
01413 //     current_target = path.size()-1;
01414 //     if (path.size() > 0) {
01415 //       goal = path[0];
01416 //     }
01417 //     spot = Loc(-1, -1);
01418 //   }
01419 
01420 
01421 //   bool UnitPath_FF::is_intersect(const Segment &segment) const
01422 //   {
01423 //     typeof(path.begin()) pj = path.begin();
01424 //     typeof(path.begin()) pi = pj++;
01425 //     for( ; pj != path.end() ; pi++, pj++ ) {
01426 //       if (Segment(*pi, *pj).touches(segment) )
01427 //         return true;
01428 //     }
01429 //     return false;
01430 //   }
01431 
01432   //----------------------------------------------------------------------------------
01433   //----------------------------------------------------------------------------------
01434 
01435   void FF_Task::set_path(const Object *obj_, const Vector<Loc> &path_)
01436   {
01437     // overwrite an existing path, retaining the collision-monitoring data.
01438     if( path ) {
01439       Loc   saved_spot = path->spot;
01440       int   saved_collision_step = path->collision_step;
01441       bool  saved_stopped_to_avoid_collision = path->stopped_to_avoid_collision;
01442       uint4 saved_wakeup = path->wakeup;
01443 
01444       path = boost::shared_ptr<UnitPath_FF>(new UnitPath_FF(obj_, path_));
01445 
01446       path->spot = saved_spot;
01447       path->collision_step = saved_collision_step;
01448       path->stopped_to_avoid_collision = saved_stopped_to_avoid_collision;
01449       path->wakeup = saved_wakeup;
01450     } 
01451     // No previous path was planned, so just create a new one.
01452     else {
01453        path = boost::shared_ptr<UnitPath_FF>(new UnitPath_FF(obj_, path_));
01454     }
01455   }
01456 
01457 
01458 
01459   //----------------------------------------------------------------------------------
01460  


Generated on Fri May 18 2012 03:02:38 for ORTS by Doxygen1.7.3