|
ORTS
|
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