00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <iostream>
00028 #include "physical_obj.h"
00029 #include "physics.h"
00030 #include "objects_list.h"
00031 #include "../game/config.h"
00032 #include "../game/time.h"
00033 #include "../map/map.h"
00034 #include "../network/randomsync.h"
00035 #include "../team/macro.h"
00036 #include "../team/teams_list.h"
00037 #include "../tool/debug.h"
00038 #include "../tool/math_tools.h"
00039 #include "../tool/point.h"
00040 #include "../tool/rectangle.h"
00041 #include "../weapon/ninja_rope.h"
00042 #include "../weapon/launcher.h"
00043
00044 const int Y_OBJET_MIN = -10000;
00045 const int WATER_RESIST_FACTOR = 40;
00046
00047 const double PIXEL_PER_METER = 40;
00048
00049 double MeterDistance (const Point2i &p1, const Point2i &p2)
00050 {
00051 return p1.Distance(p2) / PIXEL_PER_METER;
00052 }
00053
00054 PhysicalObj::PhysicalObj (const std::string &name, const std::string &xml_config) :
00055 m_name(name),
00056 m_width(0),
00057 m_height(0)
00058 {
00059 life_points = -1;
00060 m_goes_through_wall = false;
00061 m_collides_with_characters = false;
00062 m_collides_with_objects = false;
00063
00064
00065 m_overlapping_object = NULL;
00066
00067 m_allow_negative_y = false;
00068 m_alive = ALIVE;
00069
00070 m_rebound_sound = "";
00071
00072 m_test_left = 0;
00073 m_test_right = 0;
00074 m_test_top = 0;
00075 m_test_bottom = 0;
00076
00077 m_rebound_position = Point2i(-1, -1);
00078
00079 m_cfg.LoadXml(m_name,xml_config);
00080 ResetConstants();
00081 }
00082
00083 PhysicalObj::~PhysicalObj ()
00084 {}
00085
00086
00087
00088
00089
00090 void PhysicalObj::SetX (int x){
00091 SetXY( Point2i(x, GetY()) );
00092 }
00093
00094 void PhysicalObj::SetY (int y){
00095 SetXY( Point2i(GetX(), y) );
00096 }
00097
00098 void PhysicalObj::SetXY(const Point2i &position)
00099 {
00100 CheckOverlapping();
00101
00102 if( IsOutsideWorldXY( position ) )
00103 {
00104 Point2d physPos(position.x, position.y);
00105 SetPhysXY( physPos / PIXEL_PER_METER );
00106 Ghost();
00107 SignalOutOfMap();
00108 }
00109 else
00110 {
00111 Point2d physPos(position.x, position.y);
00112 SetPhysXY( physPos / PIXEL_PER_METER );
00113 if( FootsInVacuum() ) StartMoving();
00114 }
00115 }
00116
00117 const Point2i PhysicalObj::GetPosition() const
00118 {
00119 return Point2i(GetX(), GetY());
00120 }
00121
00122 int PhysicalObj::GetX() const
00123 {
00124 return (int)round(GetPhysX() * PIXEL_PER_METER);
00125 }
00126
00127 int PhysicalObj::GetY() const
00128 {
00129 return (int)round(GetPhysY() * PIXEL_PER_METER);
00130 }
00131
00132 int PhysicalObj::GetCenterX() const
00133 {
00134 return GetX() +m_test_left +GetTestWidth()/2;
00135 }
00136
00137 int PhysicalObj::GetCenterY() const
00138 {
00139 return GetY() +m_test_top +GetTestHeight()/2;
00140 }
00141
00142 const Point2i PhysicalObj::GetCenter() const
00143 {
00144 return Point2i(GetCenterX(), GetCenterY());
00145 }
00146
00147 void PhysicalObj::SetSize(const Point2i &newSize){
00148 if( newSize == Point2i(0, 0) )
00149 Error( "New size of (0, 0) !");
00150 m_width = newSize.x;
00151 m_height = newSize.y;
00152 SetPhysSize( (double)newSize.x / PIXEL_PER_METER, (double)newSize.y/PIXEL_PER_METER );
00153 }
00154
00155
00156 int PhysicalObj::GetWidth() const{
00157 assert (m_width != 0);
00158 return m_width;
00159 }
00160
00161 int PhysicalObj::GetHeight() const{
00162 assert (m_height != 0);
00163 return m_height;
00164 }
00165
00166 Point2i PhysicalObj::GetSize() const{
00167 return Point2i(m_width, m_height);
00168 }
00169
00170 void PhysicalObj::SetOverlappingObject(PhysicalObj* obj)
00171 {
00172 m_overlapping_object = obj;
00173 MSG_DEBUG( "physic.overlapping", "\"%s\" doesn't check any collision with \"%s\" anymore", GetName().c_str(), obj->GetName().c_str());
00174 CheckOverlapping();
00175 }
00176
00177 void PhysicalObj::CheckOverlapping()
00178 {
00179 if(m_overlapping_object == NULL)
00180 return;
00181
00182
00183 if (!m_overlapping_object->GetTestRect().Intersect( GetTestRect() ))
00184 {
00185 MSG_DEBUG( "physic.overlapping", "\"%s\" just stopped overlapping with \"%s\"", GetName().c_str(), m_overlapping_object->GetName().c_str());
00186 m_overlapping_object = NULL;
00187 }
00188 else
00189 {
00190 MSG_DEBUG( "physic.overlapping", "\"%s\" is overlapping with \"%s\"", GetName().c_str(), m_overlapping_object->GetName().c_str());
00191 }
00192 }
00193
00194 void PhysicalObj::SetTestRect (uint left, uint right, uint top, uint bottom)
00195 {
00196 m_test_left = left;
00197 m_test_right = right;
00198 m_test_top = top;
00199 m_test_bottom = bottom;
00200 }
00201
00202 int PhysicalObj::GetTestWidth() const
00203 {
00204 return m_width -m_test_left -m_test_right;
00205 }
00206
00207 int PhysicalObj::GetTestHeight() const
00208 {
00209 return m_height -m_test_top -m_test_bottom;
00210 }
00211
00212 const Rectanglei PhysicalObj::GetRect() const
00213 {
00214 return Rectanglei( GetX(), GetY(), m_width, m_height);
00215 }
00216
00217 const Rectanglei PhysicalObj::GetTestRect() const
00218 {
00219 return Rectanglei(GetX()+m_test_left,
00220 GetY()+m_test_top,
00221 m_width-m_test_right-m_test_left,
00222 m_height-m_test_bottom-m_test_top);
00223 }
00224
00225 void PhysicalObj::AddDamage(uint damage_points)
00226 {
00227 if(life_points == -1)
00228 return;
00229 life_points -= damage_points;
00230 if(life_points <= 0 && !IsGhost())
00231 {
00232 Ghost();
00233 life_points = -1;
00234 }
00235 }
00236
00237
00238 void PhysicalObj::NotifyMove(Point2d oldPos, Point2d newPos)
00239 {
00240 if (IsGhost()) return;
00241 Point2d pos, offset;
00242 PhysicalObj* collided_obj = NULL;
00243
00244 typedef enum {
00245 NO_COLLISION = 0,
00246 COLLISION_ON_GROUND,
00247 COLLISION_ON_OBJECT
00248 } collision_t;
00249 collision_t collision = NO_COLLISION;
00250
00251 if(IsGhost())
00252 return;
00253
00254
00255 oldPos *= PIXEL_PER_METER;
00256 newPos *= PIXEL_PER_METER;
00257
00258
00259 double lg = oldPos.Distance( newPos);
00260
00261 if (lg == 0)
00262 return;
00263
00264
00265
00266 offset = (newPos - oldPos) / lg;
00267
00268
00269 pos = oldPos + offset;
00270
00271 if (m_goes_through_wall || IsInWater())
00272 {
00273 Point2i tmpPos( lround(newPos.x), lround(newPos.y) );
00274 SetXY(tmpPos);
00275 return;
00276 }
00277
00278 do
00279 {
00280 Point2i tmpPos( lround(pos.x), lround(pos.y) );
00281
00282
00283 if( IsOutsideWorldXY(tmpPos) ){
00284
00285 if( !Config::GetInstance()->GetExterieurMondeVide() ){
00286 tmpPos.x = BorneLong(tmpPos.x, 0, world.GetWidth() - GetWidth() - 1);
00287 tmpPos.y = BorneLong(tmpPos.y, 0, world.GetHeight() - GetHeight() - 1);
00288 MSG_DEBUG( "physic.state", "%s - DeplaceTestCollision touche un bord : %d, %d", m_name.c_str(), tmpPos.x, tmpPos.y );
00289 collision = COLLISION_ON_GROUND;
00290 break;
00291 }
00292
00293 SetXY( tmpPos );
00294 return;
00295 }
00296
00297
00298 collided_obj = CollidedObjectXY(tmpPos);
00299 if( collided_obj != NULL)
00300 MSG_DEBUG( "physic.state", "%s collide on %s", m_name.c_str(), collided_obj->GetName().c_str() );
00301
00302 if( collided_obj != NULL)
00303 collision = COLLISION_ON_OBJECT;
00304 else
00305 if( ! IsInVacuumXY(tmpPos, false) )
00306 collision = COLLISION_ON_GROUND;
00307
00308 if( collision != NO_COLLISION )
00309 {
00310 MSG_DEBUG( "physic.state", "%s - Collision at %d,%d : %s", m_name.c_str(), tmpPos.x, tmpPos.y,
00311 collision == COLLISION_ON_GROUND ? "on ground" : "on an object");
00312
00313
00314 SetXY( Point2i( lround(pos.x - offset.x), lround(pos.y - offset.y)) );
00315 break;
00316 }
00317
00318
00319 pos += offset;
00320 lg -= 1.0 ;
00321 } while (0 < lg);
00322
00323
00324
00325 if (ActiveTeam().GetWeaponType() == Weapon::WEAPON_NINJA_ROPE &&
00326 ActiveTeam().GetWeapon().IsActive()) {
00327 Weapon& tmp = ActiveTeam().AccessWeapon();
00328 NinjaRope * ninjarope = (NinjaRope *)(&tmp);
00329 ninjarope->NotifyMove(collision) ;
00330 }
00331
00332 if ( collision == NO_COLLISION )
00333 return;
00334 if ( collision == COLLISION_ON_GROUND ) {
00335
00336
00337
00338
00339
00340 int cx, cy;
00341 Point2d contactPos;
00342 double ground_angle;
00343
00344 if (ContactPoint(cx, cy)) {
00345 ground_angle = world.ground.Tangeante(cx, cy);
00346 contactPos.x = (double)cx / PIXEL_PER_METER;
00347 contactPos.y = (double)cy / PIXEL_PER_METER;
00348 } else {
00349 ground_angle = - GetSpeedAngle();
00350 contactPos = pos;
00351 }
00352
00353 SignalGroundCollision();
00354 SignalCollision();
00355
00356 Rebound(contactPos, ground_angle);
00357 CheckRebound();
00358 } else if ( collision == COLLISION_ON_OBJECT ) {
00359 SignalObjectCollision(collided_obj);
00360 collided_obj->SignalObjectCollision(this);
00361
00362
00363 double v1, v2, mass1, angle1, angle2, mass2;
00364 collided_obj->GetSpeed(v1, angle1);
00365 GetSpeed(v2, angle2);
00366 mass1 = GetMass();
00367 mass2 = collided_obj->GetMass();
00368
00369
00370
00371
00372
00373
00374 SignalCollision();
00375
00376 collided_obj->SetSpeed(((mass1 - mass2) * v1 + 2 * mass1 *v2 * m_cfg.m_rebound_factor) / (mass1 + mass2),
00377 angle1);
00378 SetSpeed(((mass2 - mass1) * v2 + 2 * mass1 *v1 * m_cfg.m_rebound_factor) / (mass1 + mass2), angle2);
00379
00380
00381 double contact_angle = - GetSpeedAngle();
00382 Point2d contactPos = pos;
00383 Rebound(contactPos, contact_angle);
00384 CheckRebound();
00385 }
00386 return;
00387 }
00388
00389 void PhysicalObj::UpdatePosition ()
00390 {
00391
00392 if (IsGhost()) return;
00393
00394 if ( !m_goes_through_wall )
00395 {
00396
00397 if ( !IsMoving() && !FootsInVacuum() && !IsInWater() ) return;
00398
00399
00400 if ( !IsMoving() && FootsInVacuum() ) StartMoving();
00401 }
00402
00403
00404 RunPhysicalEngine();
00405
00406
00407 if( IsOutsideWorldXY(GetPosition()) )
00408 Ghost();
00409
00410 if (IsGhost()) return;
00411
00412
00413 if ( !m_goes_through_wall )
00414 {
00415 if ( IsInWater() && m_alive != DROWNED ) Drown();
00416 else if ( !IsInWater() && m_alive == DROWNED ) GoOutOfWater();
00417 }
00418
00419 }
00420
00421 bool PhysicalObj::PutOutOfGround(double direction)
00422 {
00423 if(IsOutsideWorld(Point2i(0, 0)))
00424 return false;
00425
00426 const int max_step = 30;
00427
00428 if( IsInVacuum(Point2i(0, 0), false) )
00429 return true;
00430
00431 double dx = cos(direction);
00432 double dy = sin(direction);
00433
00434 int step=1;
00435 while(step<max_step && !IsInVacuum(
00436 Point2i((int)(dx * (double)step),(int)(dy * (double)step)), false ))
00437 step++;
00438
00439 if(step<max_step)
00440 SetXY( Point2i((int)(dx * (double)step)+GetX(),(int)(dy * (double)step)+GetY()) );
00441 else
00442 return false;
00443
00444 return true;
00445 }
00446
00447 bool PhysicalObj::PutOutOfGround()
00448 {
00449 if(IsOutsideWorld(Point2i(0, 0)))
00450 return false;
00451
00452 if( IsInVacuum(Point2i(0, 0)) )
00453 return true;
00454
00455 bool left,right,top,bottom;
00456 left = world.IsInVacuum_left(*this, 0, 0);
00457 right = world.IsInVacuum_right(*this, 0, 0);
00458 top = world.EstDansVide_haut(*this, 0, 0);
00459 bottom = world.EstDansVide_bas(*this, 0, 0);
00460
00461 int dx = (int)GetTestRect().GetSizeX() * (right-left);
00462 int dy = (int)GetTestRect().GetSizeY() * (top-bottom);
00463
00464 if( dx == 0 && dy == 0 )
00465 return false;
00466
00467 Point2i b(dx, dy);
00468
00469 double dir = b.ComputeAngle();
00470 return PutOutOfGround(dir);
00471 }
00472
00473 void PhysicalObj::Init()
00474 {
00475 if (m_alive != ALIVE)
00476 MSG_DEBUG( "physic.state", "%s - Init.", m_name.c_str());
00477 m_alive = ALIVE;
00478 m_overlapping_object = NULL;
00479 StopMoving();
00480 }
00481
00482 void PhysicalObj::Ghost ()
00483 {
00484 if (m_alive == GHOST)
00485 return;
00486
00487 bool was_dead = IsDead();
00488 m_alive = GHOST;
00489 MSG_DEBUG("physic.state", "%s - Ghost, was_dead = %d", m_name.c_str(), was_dead);
00490
00491
00492 StopMoving();
00493
00494 SignalGhostState(was_dead);
00495 }
00496
00497 void PhysicalObj::Drown()
00498 {
00499 assert (m_alive != DROWNED);
00500 MSG_DEBUG("physic.state", "%s - Drowned...", m_name.c_str());
00501 m_alive = DROWNED;
00502
00503
00504 SetAirResistFactor(WATER_RESIST_FACTOR * GetAirResistFactor());
00505 StopMoving();
00506 StartMoving();
00507 SignalDrowning();
00508 }
00509
00510 void PhysicalObj::GoOutOfWater()
00511 {
00512 assert (m_alive == DROWNED);
00513 MSG_DEBUG("physic.state", "%s - Go out of water!...", m_name.c_str());
00514 m_alive = ALIVE;
00515
00516
00517 SetAirResistFactor(m_cfg.m_air_resist_factor);
00518
00519 StartMoving();
00520 }
00521
00522 bool PhysicalObj::IsImmobile() const
00523 {
00524 return (!IsMoving() && !FootsInVacuum())||(m_alive == GHOST);
00525 }
00526
00527 bool PhysicalObj::IsDead () const
00528 { return ((m_alive == GHOST) || (m_alive == DROWNED) || (m_alive == DEAD)); }
00529
00530 bool PhysicalObj::IsGhost() const
00531 { return (m_alive == GHOST); }
00532
00533 bool PhysicalObj::IsDrowned() const
00534 { return (m_alive == DROWNED); }
00535
00536 void PhysicalObj::SignalRebound()
00537 {
00538
00539 if (!m_rebound_sound.empty())
00540 jukebox.Play("share", m_rebound_sound) ;
00541 }
00542
00543 void PhysicalObj::SignalObjectCollision(PhysicalObj * obj) {}
00544
00545 void PhysicalObj::SignalGroundCollision() {}
00546
00547 void PhysicalObj::SignalCollision() {}
00548
00549 void PhysicalObj::SignalOutOfMap() {}
00550
00551 void PhysicalObj::SetCollisionModel(bool goes_through_wall,
00552 bool collides_with_characters,
00553 bool collides_with_objects)
00554 {
00555 m_goes_through_wall = goes_through_wall;
00556 m_collides_with_characters = collides_with_characters;
00557 m_collides_with_objects = collides_with_objects;
00558
00559
00560 {
00561 if (m_collides_with_characters || m_collides_with_objects)
00562 assert(m_goes_through_wall == false);
00563
00564 if (m_goes_through_wall) {
00565 assert(m_collides_with_characters == false);
00566 assert(m_collides_with_objects == false);
00567 }
00568 }
00569 }
00570
00571 void PhysicalObj::CheckRebound()
00572 {
00573
00574
00575 if( m_rebound_position != Point2i( -1, -1) )
00576 {
00577 if ( m_rebound_position == GetPosition() )
00578 {
00579 MSG_DEBUG("physic.state", "%s seems to be stuck in ground. Stop moving!", m_name.c_str());
00580 StopMoving();
00581 }
00582 }
00583 m_rebound_position = GetPosition();
00584 }
00585
00586 bool PhysicalObj::IsOutsideWorldXY(Point2i position) const{
00587 int x = position.x + m_test_left;
00588 int y = position.y + m_test_top;
00589
00590 if( world.EstHorsMondeXlarg(x, GetTestWidth()) )
00591 return true;
00592 if( world.EstHorsMondeYhaut(y, GetTestHeight()) ){
00593 if( m_allow_negative_y )
00594 if( (Y_OBJET_MIN <= y) && (y + GetTestHeight() - 1 < 0) )
00595 return false;
00596 return true;
00597 }
00598 return false;
00599 }
00600
00601 bool PhysicalObj::IsOutsideWorld(const Point2i &offset) const
00602 {
00603 return IsOutsideWorldXY( GetPosition() + offset );
00604 }
00605
00606 bool PhysicalObj::FootsOnFloor(int y) const
00607 {
00608
00609 if ( Config::GetInstance()->GetExterieurMondeVide() ) return false;
00610
00611 const int y_max = world.GetHeight()-m_height +m_test_bottom;
00612 return (y_max <= y);
00613 }
00614
00615 bool PhysicalObj::IsOverlapping(const PhysicalObj* obj) const
00616 {
00617 return m_overlapping_object == obj;
00618 }
00619
00620 bool PhysicalObj::IsInVacuum(const Point2i &offset, bool check_object) const
00621 {
00622 return IsInVacuumXY(GetPosition() + offset, check_object);
00623 }
00624
00625 bool PhysicalObj::IsInVacuumXY(const Point2i &position, bool check_object) const
00626 {
00627 if( IsOutsideWorldXY(position) )
00628 return Config::GetInstance()->GetExterieurMondeVide();
00629
00630 if( FootsOnFloor(position.y - 1) )
00631 return false;
00632
00633 if( check_object && CollidedObjectXY(position) )
00634 return false;
00635
00636 Rectanglei rect(position.x + m_test_left, position.y + m_test_top,
00637 m_width - m_test_right - m_test_left, m_height -m_test_bottom - m_test_top);
00638
00639 return world.RectEstDansVide (rect);
00640 }
00641
00642 PhysicalObj* PhysicalObj::CollidedObject(const Point2i &offset) const
00643 {
00644 return CollidedObjectXY(GetPosition() + offset);
00645 }
00646
00647 PhysicalObj* PhysicalObj::CollidedObjectXY(const Point2i & position) const
00648 {
00649 if( IsOutsideWorldXY(position) )
00650 return NULL;
00651
00652 Rectanglei rect(position.x + m_test_left, position.y + m_test_top,
00653 m_width - m_test_right - m_test_left, m_height - m_test_bottom - m_test_top);
00654
00655 if (m_collides_with_characters)
00656 {
00657 FOR_ALL_LIVING_CHARACTERS(team,character)
00658 {
00659
00660 if (&(*character) != this && !IsOverlapping(&(*character)) && !character->IsOverlapping(this)
00661 && character->GetTestRect().Intersect( rect ))
00662 return (PhysicalObj*) &(*character);
00663 }
00664 }
00665
00666 if (m_collides_with_objects)
00667 {
00668 FOR_EACH_OBJECT(it)
00669 {
00670 PhysicalObj * object=*it;
00671
00672 if (object != this && !IsOverlapping(object) && !object->IsOverlapping(this)
00673 && object->m_collides_with_objects
00674 && object->GetTestRect().Intersect(rect) )
00675 return object;
00676 }
00677 }
00678 return NULL;
00679 }
00680
00681 bool PhysicalObj::FootsInVacuum() const
00682 {
00683 return FootsInVacuumXY(GetPosition());
00684 }
00685
00686 bool PhysicalObj::FootsInVacuumXY(const Point2i &position) const
00687 {
00688 if( IsOutsideWorldXY(position) ){
00689 MSG_DEBUG("physical", "%s - physobj is outside the world", m_name.c_str());
00690 return Config::GetInstance()->GetExterieurMondeVide();
00691 }
00692
00693 if( FootsOnFloor(position.y) ){
00694 MSG_DEBUG("physical", "%s - physobj is on floor", m_name.c_str());
00695 return false;
00696 }
00697
00698 int y_test = position.y + m_height - m_test_bottom;
00699
00700 Rectanglei rect( position.x + m_test_left, y_test,
00701 m_width - m_test_right - m_test_left, 1);
00702
00703 if( m_allow_negative_y && rect.GetPositionY() < 0){
00704 int b = rect.GetPositionY() + rect.GetSizeY();
00705
00706 rect.SetPositionY( 0 );
00707 rect.SetSizeY( ( b > 0 ) ? b - rect.GetPositionY() : 0 );
00708 }
00709
00710 if(CollidedObjectXY( position + Point2i(0, 1)) != NULL )
00711 return false;
00712
00713 return world.RectEstDansVide (rect);
00714 }
00715
00716 bool PhysicalObj::IsInWater () const
00717 {
00718 assert (!IsGhost());
00719 if (!world.water.IsActive()) return false;
00720 int x = BorneLong(GetCenterX(), 0, world.GetWidth()-1);
00721 return (int)world.water.GetHeight(x) < GetCenterY();
00722 }
00723
00724 void PhysicalObj::DirectFall()
00725 {
00726 while (!IsGhost() && !IsInWater() && FootsInVacuum())
00727 SetY(GetY()+1);
00728 }
00729
00730 bool PhysicalObj::ContactPoint (int & contact_x, int & contact_y)
00731 {
00732 int x1, x2, y1, y2;
00733
00734
00735 y1 = (GetY()+m_height-m_test_bottom);
00736 y2 = y1-1;
00737 for (uint x=GetX()+ m_test_left; x<=(GetX()+m_width)-m_test_right; x++)
00738 {
00739 if(!world.EstHorsMonde(Point2i(x,y1)) && !world.EstHorsMonde(Point2i(x,y2))
00740 && world.ground.IsEmpty(Point2i(x,y2)) && !world.ground.IsEmpty(Point2i(x,y1)))
00741 {
00742 contact_x = x;
00743 contact_y = GetY() +m_height-m_test_bottom;
00744 return true;
00745 }
00746 }
00747
00748
00749 x1 = GetX()+m_test_left;
00750 x2 = x1+1;
00751 for(uint y=GetY()+m_test_top;y<=GetY()+m_height-m_test_bottom;y++)
00752 {
00753 if(!world.EstHorsMonde(Point2i(x1,y)) && !world.EstHorsMonde(Point2i(x2,y))
00754 && !world.ground.IsEmpty(Point2i(x1,y)) && world.ground.IsEmpty(Point2i(x2,y)))
00755 {
00756 contact_x = GetX() +m_test_left;
00757 contact_y = y;
00758 return true;
00759 }
00760 }
00761
00762
00763 x1 = (GetX()+m_width-m_test_right);
00764 x2 = x1-1;
00765 for(uint y=GetY()+m_test_top;y<=GetY()+m_height-m_test_bottom;y++)
00766 {
00767 if(!world.EstHorsMonde(Point2i(x1, y)) && !world.EstHorsMonde(Point2i(x2, y))
00768 && !world.ground.IsEmpty(Point2i(x1, y)) && world.ground.IsEmpty(Point2i(x2, y)))
00769 {
00770 contact_x = GetX() + m_width - m_test_right;
00771 contact_y = y;
00772 return true;
00773 }
00774 }
00775
00776
00777 y1 = GetY()+m_test_top;
00778 y2 = y1 - 1;
00779 for(uint x=GetX()+m_test_left;x<=GetX()+m_width-m_test_right;x++)
00780 {
00781 if(!world.EstHorsMonde(Point2i(x,y1)) && !world.EstHorsMonde(Point2i(x,y2))
00782 && !world.ground.IsEmpty(Point2i(x, y1)) && world.ground.IsEmpty(Point2i(x, y2)))
00783 {
00784 contact_x =x;
00785 contact_y = GetY() +m_test_top;
00786 return true;
00787 }
00788 }
00789 return false;
00790 }
00791
00792
00793 bool PhysicalObj::ObjTouche(const PhysicalObj &b) const
00794 {
00795 return GetTestRect().Intersect( b.GetTestRect() );
00796 }
00797
00798
00799 bool PhysicalObj::ObjTouche(const Point2i &p) const
00800 {
00801 return GetTestRect().Contains( p );
00802 }
00803
00804 bool PhysicalObj::PutRandomly(bool on_top_of_world, double min_dst_with_characters)
00805 {
00806 uint bcl=0;
00807 uint NB_MAX_TRY = 60;
00808 bool ok;
00809 Point2i position;
00810
00811 MSG_DEBUG("physic.position", "%s - Search a position...", m_name.c_str());
00812
00813 do
00814 {
00815 bcl++;
00816 ok = true;
00817 Init();
00818
00819 if (bcl >= NB_MAX_TRY) {
00820 MSG_DEBUG("physic.position", "%s - Impossible to find an initial position !!", m_name.c_str());
00821 return false;
00822 }
00823
00824 if (on_top_of_world) {
00825
00826 position.x = randomSync.GetLong(0, world.GetWidth() - GetWidth());
00827 position.y = -GetHeight()+1;
00828 } else {
00829 position = randomSync.GetPoint(world.GetSize() - GetSize() + 1);
00830 }
00831 SetXY(position);
00832 MSG_DEBUG("physic.position", "%s - Test in %d, %d", m_name.c_str(), position.x, position.y);
00833
00834
00835 ok &= !IsGhost() && world.ParanoiacRectIsInVacuum(GetTestRect()) && IsInVacuum( Point2i(0, 1) );
00836 if (!ok) {
00837 MSG_DEBUG("physic.position", "%s - Put it in the ground -> try again !", m_name.c_str());
00838 continue;
00839 }
00840
00841
00842 DirectFall();
00843 ok &= !IsGhost() && !IsInWater() && (GetY() < static_cast<int>(world.GetHeight() - (WATER_INITIAL_HEIGHT + 30)));
00844
00845 if (!ok) {
00846 MSG_DEBUG("physic.position", "%s - Put in outside the map or in water -> try again", m_name.c_str());
00847 continue;
00848 }
00849
00850
00851 FOR_ALL_LIVING_CHARACTERS(equipe, ver) if (&(*ver) != this)
00852 {
00853 if (min_dst_with_characters == 0) {
00854
00855 if( ObjTouche(*ver) ) {
00856 MSG_DEBUG("physic.position", "%s - Object is too close from character %s", m_name.c_str(), (*ver).m_name.c_str());
00857 ok = false;
00858 }
00859 } else {
00860 Point2i p1 = ver->GetCenter();
00861 Point2i p2 = GetCenter();
00862 double dst = p1.Distance( p2 );
00863
00864
00865
00866 if (dst < min_dst_with_characters) ok = false;
00867 }
00868 }
00869
00870 if (ok && on_top_of_world) SetXY(position);
00871 } while (!ok);
00872
00873 MSG_DEBUG("physic.position", "Putted after %d try", m_name.c_str(), bcl);
00874
00875 return true;
00876 }