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