| 1433 | | namespace MaNGOS |
| 1434 | | { |
| 1435 | | class NearUsedPosDo |
| 1436 | | { |
| 1437 | | public: |
| 1438 | | NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector) |
| 1439 | | : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {} |
| 1440 | | |
| 1441 | | void operator()(Corpse*) const {} |
| 1442 | | void operator()(DynamicObject*) const {} |
| 1443 | | |
| 1444 | | void operator()(Creature* c) const |
| 1445 | | { |
| 1446 | | // skip self or target |
| 1447 | | if(c==i_searcher || c==&i_object) |
| 1448 | | return; |
| 1449 | | |
| 1450 | | float x,y,z; |
| 1451 | | |
| 1452 | | if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED) || |
| 1453 | | !c->GetMotionMaster()->GetDestination(x,y,z) ) |
| 1454 | | { |
| 1455 | | x = c->GetPositionX(); |
| 1456 | | y = c->GetPositionY(); |
| 1457 | | } |
| 1458 | | |
| 1459 | | add(c,x,y); |
| 1460 | | } |
| 1461 | | |
| 1462 | | template<class T> |
| 1463 | | void operator()(T* u) const |
| 1464 | | { |
| 1465 | | // skip self or target |
| 1466 | | if(u==i_searcher || u==&i_object) |
| 1467 | | return; |
| 1468 | | |
| 1469 | | float x,y; |
| 1470 | | |
| 1471 | | x = u->GetPositionX(); |
| 1472 | | y = u->GetPositionY(); |
| 1473 | | |
| 1474 | | add(u,x,y); |
| 1475 | | } |
| 1476 | | |
| 1477 | | // we must add used pos that can fill places around center |
| 1478 | | void add(WorldObject* u, float x, float y) const |
| 1479 | | { |
| 1480 | | // dist include size of u |
| 1481 | | float dist2d = i_object.GetDistance2d(x,y); |
| 1482 | | |
| 1483 | | // u is too nearest to i_object |
| 1484 | | if(dist2d + i_object.GetObjectSize() + u->GetObjectSize() < i_selector.m_dist - i_selector.m_size) |
| 1485 | | return; |
| 1486 | | |
| 1487 | | // u is too far away from i_object |
| 1488 | | if(dist2d + i_object.GetObjectSize() - u->GetObjectSize() > i_selector.m_dist + i_selector.m_size) |
| 1489 | | return; |
| 1490 | | |
| 1491 | | float angle = i_object.GetAngle(u)-i_angle; |
| 1492 | | |
| 1493 | | // move angle to range -pi ... +pi |
| 1494 | | while( angle > M_PI) |
| 1495 | | angle -= 2.0f * M_PI; |
| 1496 | | while(angle < -M_PI) |
| 1497 | | angle += 2.0f * M_PI; |
| 1498 | | |
| 1499 | | i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize()); |
| 1500 | | } |
| 1501 | | private: |
| 1502 | | WorldObject const& i_object; |
| 1503 | | WorldObject const* i_searcher; |
| 1504 | | float i_angle; |
| 1505 | | ObjectPosSelector& i_selector; |
| 1506 | | }; |
| 1507 | | } // namespace MaNGOS |
| 1508 | | |
| 1509 | | //=================================================================================================== |
| 1510 | | |
| 1524 | | |
| 1525 | | // if detection disabled, return first point |
| 1526 | | if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION)) |
| 1527 | | { |
| 1528 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1529 | | return; |
| 1530 | | } |
| 1531 | | |
| 1532 | | // or remember first point |
| 1533 | | float first_x = x; |
| 1534 | | float first_y = y; |
| 1535 | | bool first_los_conflict = false; // first point LOS problems |
| 1536 | | |
| 1537 | | // prepare selector for work |
| 1538 | | ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size); |
| 1539 | | |
| 1540 | | // adding used positions around object |
| 1541 | | { |
| 1542 | | CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); |
| 1543 | | Cell cell(p); |
| 1544 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1545 | | cell.SetNoCreate(); |
| 1546 | | |
| 1547 | | MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector); |
| 1548 | | MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(u_do); |
| 1549 | | |
| 1550 | | TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker); |
| 1551 | | TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker); |
| 1552 | | |
| 1553 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1554 | | cell_lock->Visit(cell_lock, grid_obj_worker, *MapManager::Instance().GetMap(GetMapId(), this)); |
| 1555 | | cell_lock->Visit(cell_lock, world_obj_worker, *MapManager::Instance().GetMap(GetMapId(), this)); |
| 1556 | | } |
| 1557 | | |
| 1558 | | // maybe can just place in primary position |
| 1559 | | if( selector.CheckOriginal() ) |
| 1560 | | { |
| 1561 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1562 | | |
| 1563 | | if(IsWithinLOS(x,y,z)) |
| 1564 | | return; |
| 1565 | | |
| 1566 | | first_los_conflict = true; // first point have LOS problems |
| 1567 | | } |
| 1568 | | |
| 1569 | | float angle; // candidate of angle for free pos |
| 1570 | | |
| 1571 | | // special case when one from list empty and then empty side preferred |
| 1572 | | if(selector.FirstAngle(angle)) |
| 1573 | | { |
| 1574 | | GetNearPoint2D(x,y,distance2d,absAngle+angle); |
| 1575 | | z = GetPositionZ(); |
| 1576 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1577 | | |
| 1578 | | if(IsWithinLOS(x,y,z)) |
| 1579 | | return; |
| 1580 | | } |
| 1581 | | |
| 1582 | | // set first used pos in lists |
| 1583 | | selector.InitializeAngle(); |
| 1584 | | |
| 1585 | | // select in positions after current nodes (selection one by one) |
| 1586 | | while(selector.NextAngle(angle)) // angle for free pos |
| 1587 | | { |
| 1588 | | GetNearPoint2D(x,y,distance2d,absAngle+angle); |
| 1589 | | z = GetPositionZ(); |
| 1590 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1591 | | |
| 1592 | | if(IsWithinLOS(x,y,z)) |
| 1593 | | return; |
| 1594 | | } |
| 1595 | | |
| 1596 | | // BAD NEWS: not free pos (or used or have LOS problems) |
| 1597 | | // Attempt find _used_ pos without LOS problem |
| 1598 | | |
| 1599 | | if(!first_los_conflict) |
| 1600 | | { |
| 1601 | | x = first_x; |
| 1602 | | y = first_y; |
| 1603 | | |
| 1604 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1605 | | return; |
| 1606 | | } |
| 1607 | | |
| 1608 | | // special case when one from list empty and then empty side preferred |
| 1609 | | if( selector.IsNonBalanced() ) |
| 1610 | | { |
| 1611 | | if(!selector.FirstAngle(angle)) // _used_ pos |
| 1612 | | { |
| 1613 | | GetNearPoint2D(x,y,distance2d,absAngle+angle); |
| 1614 | | z = GetPositionZ(); |
| 1615 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1616 | | |
| 1617 | | if(IsWithinLOS(x,y,z)) |
| 1618 | | return; |
| 1619 | | } |
| 1620 | | } |
| 1621 | | |
| 1622 | | // set first used pos in lists |
| 1623 | | selector.InitializeAngle(); |
| 1624 | | |
| 1625 | | // select in positions after current nodes (selection one by one) |
| 1626 | | while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem |
| 1627 | | { |
| 1628 | | GetNearPoint2D(x,y,distance2d,absAngle+angle); |
| 1629 | | z = GetPositionZ(); |
| 1630 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1631 | | |
| 1632 | | if(IsWithinLOS(x,y,z)) |
| 1633 | | return; |
| 1634 | | } |
| 1635 | | |
| 1636 | | // BAD BAD NEWS: all found pos (free and used) have LOS problem :( |
| 1637 | | x = first_x; |
| 1638 | | y = first_y; |
| 1639 | | |
| 1640 | | UpdateGroundPositionZ(x,y,z); // update to LOS height if available |
| 1641 | | } |
| | 1445 | |
| | 1446 | UpdateGroundPositionZ(x,y,z); |
| | 1447 | } |