Files
ThordekkCore/MOVEMENT_FIX_VISUAL_EXPLANATION.md
T
2026-01-20 21:33:16 -03:00

10 KiB

Visual Explanation: Creature Trigger Movement Fix

The Problem (Before Fix)

Broken Calculation

Bot Position A: (-8869.6, -237.9, 81.9)
Target Position B: (unknown, 139.9 yards away)
Safe Distance: 11 yards

BROKEN CODE:
angleFromBot = bot->GetRelativeAngle(targetObject)      ← Angle FROM A toward B
closePos = bot->GetNearPoint(bot, ..., 11yd, angleFromBot)  ← Point near A

RESULT:
        A (Bot)                                       B (Target)
        o------> closePos                             o
        |________|__________________________________|
        11 yards           128+ yards

Bot moves to closePos (11 yards from A), but still ~128 yards from target!
Next update: Same problem repeats. Bot stuck forever.

Observable Symptom

[Update 1] Distance: 139.9yd → Issued movement command
[Update 2] Distance: 139.9yd → Issued movement command (STUCK!)
[Update 3] Distance: 139.9yd → Issued movement command (STUCK!)
... infinite loop ...

The Solution (After Fix)

Correct Calculation

Bot Position A: (-8869.6, -237.9, 81.9)
Target Position B: (unknown, 139.9 yards away)
Safe Distance: 11 yards

FIXED CODE:
angleFromTarget = targetObject->GetRelativeAngle(bot)           ← Angle FROM B toward A
closePos = targetObject->GetNearPoint(bot, ..., 11yd, angleFromTarget)  ← Point near B

RESULT:
        A (Bot)                            closePos   B (Target)
        o___________________________________|------->o
                  128+ yards                 11 yards

Bot moves to closePos (11 yards from TARGET!), arrives at correct position.
Next update: Distance check passes, bot uses item. SUCCESS!

Observable Behavior

[Update 1] Distance: 139.9yd → Issued movement command to position near target
[Update 2] Distance: 100.0yd → Bot traveling (distance decreasing!)
[Update 3] Distance: 60.0yd  → Bot traveling
[Update 4] Distance: 15.0yd  → Bot arrived at closePos
[Update 5] Distance: 15.0yd  → Within safe range [11-30yd], using item!

Side-by-Side Code Comparison

BEFORE (Broken)

else if (currentDistance > maxUseDistance)
{
    TC_LOG_ERROR("...", "MOVING CLOSER");  // Misleading log

    // Get angle from BOT toward target
    float angleFromBot = bot->GetRelativeAngle(targetObject);

    Position closePos;
    // Calculate point near BOT at safe distance
    bot->GetNearPoint(bot, closePos.m_positionX, closePos.m_positionY, closePos.m_positionZ,
                      safeDistance, angleFromBot);

    TC_LOG_ERROR("...", "Moving CLOSER to safe position ({}, {}, {}) at distance {}yd",
                 closePos.GetPositionX(), closePos.GetPositionY(), closePos.GetPositionZ(), safeDistance);

    BotMovementUtil::MoveToPosition(bot, closePos);
    return;
}

Problem: Creates position near bot, not near target!

AFTER (Fixed)

else if (currentDistance > maxUseDistance)
{
    TC_LOG_ERROR("...", "MOVING TOWARD TARGET");  // Accurate log

    // CRITICAL FIX: Calculate position FROM TARGET toward bot at safe distance
    // This ensures bot moves TOWARD target, not toward own position
    float angleFromTarget = targetObject->GetRelativeAngle(bot);

    Position closePos;
    // Calculate point near TARGET at safe distance
    targetObject->GetNearPoint(bot, closePos.m_positionX, closePos.m_positionY, closePos.m_positionZ,
                               safeDistance, angleFromTarget);

    TC_LOG_ERROR("...", "Moving TOWARD target to safe position ({}, {}, {}) at distance {}yd from target",
                 closePos.GetPositionX(), closePos.GetPositionY(), closePos.GetPositionZ(), safeDistance);

    BotMovementUtil::MoveToPosition(bot, closePos);
    return;
}

Solution: Creates position near target, exactly where bot needs to be!

API Reference

GetRelativeAngle() Function

float WorldObject::GetRelativeAngle(WorldObject const* obj) const

Returns: Angle FROM this object TO obj (in radians)

Examples:

float angle1 = bot->GetRelativeAngle(target);
// Returns: Angle FROM bot TO target
// Use case: Finding direction to face target from bot's perspective

float angle2 = target->GetRelativeAngle(bot);
// Returns: Angle FROM target TO bot
// Use case: Finding direction from target toward bot

GetNearPoint() Function

void WorldObject::GetNearPoint(WorldObject* searcher,
                               float& x, float& y, float& z,
                               float distance, float angle)

Creates: A position at distance yards from this object at the given angle

Examples:

Position pos1;
bot->GetNearPoint(bot, pos1.m_positionX, pos1.m_positionY, pos1.m_positionZ, 10.0f, angle);
// Creates: Position 10 yards from BOT at angle

Position pos2;
target->GetNearPoint(bot, pos2.m_positionX, pos2.m_positionY, pos2.m_positionZ, 10.0f, angle);
// Creates: Position 10 yards from TARGET at angle

Geometric Explanation

Scenario

Bot at coordinates: (100, 100)
Target at coordinates: (200, 100)
Distance between them: 100 yards
Safe distance needed: 11 yards

Broken Calculation (Old Code)

Step 1: angleFromBot = bot->GetRelativeAngle(target)
        = angle from (100,100) toward (200,100)
        = 0 degrees (pointing east)

Step 2: closePos = bot->GetNearPoint(bot, ..., 11yd, 0°)
        = point 11 yards east of (100,100)
        = (111, 100)

Step 3: Bot moves from (100,100) to (111,100)
        New distance to target: 89 yards (still too far!)

Next update: Repeat same calculation, bot moves to (122,100)
Result: Bot slowly crawls toward target but takes many updates

Fixed Calculation (New Code)

Step 1: angleFromTarget = target->GetRelativeAngle(bot)
        = angle from (200,100) toward (100,100)
        = 180 degrees (pointing west)

Step 2: closePos = target->GetNearPoint(bot, ..., 11yd, 180°)
        = point 11 yards west of (200,100)
        = (189, 100)

Step 3: Bot moves from (100,100) to (189,100)
        New distance to target: 11 yards (PERFECT!)

Next update: Distance check passes, bot uses item immediately
Result: Bot travels directly to correct position in one command

Edge Cases Handled

Case 1: Bot Too Close (Already Working)

Bot at 5 yards from target (minSafeDistance = 11yd)

Code correctly uses:
angleToBot = targetObject->GetRelativeAngle(bot);
safePos = targetObject->GetNearPoint(bot, ..., safeDistance, angleToBot);

Result: Bot moves AWAY from target to 11 yards
Status: ✅ Already correct (unchanged by this fix)

Case 2: Bot Too Far (NOW FIXED)

Bot at 139.9 yards from target (maxUseDistance = 30yd)

Code NOW correctly uses:
angleFromTarget = targetObject->GetRelativeAngle(bot);
closePos = targetObject->GetNearPoint(bot, ..., safeDistance, angleFromTarget);

Result: Bot moves TOWARD target to 11 yards
Status: ✅ Fixed by this change

Case 3: Bot In Range (Already Working)

Bot at 15 yards from target (within [11-30yd] range)

Code skips movement, proceeds to item usage:
- Stop movement
- Face target
- Cast spell from quest item
- Quest progress updates

Status: ✅ Already correct (unchanged by this fix)

Testing Verification

Log Pattern Before Fix (BROKEN)

📏 UseQuestItemOnTarget: Bot distance to target=139.9yd (safe range: 11.0-30.0yd)
⚠️ UseQuestItemOnTarget: Bot TOO FAR from target (139.9yd > 30.0yd) - MOVING CLOSER
🏃 UseQuestItemOnTarget: Moving CLOSER to safe position (...) at distance 11.0yd

[... wait one update ...]

📏 UseQuestItemOnTarget: Bot distance to target=139.9yd (safe range: 11.0-30.0yd)  ← SAME DISTANCE!
⚠️ UseQuestItemOnTarget: Bot TOO FAR from target (139.9yd > 30.0yd) - MOVING CLOSER
🏃 UseQuestItemOnTarget: Moving CLOSER to safe position (...) at distance 11.0yd

[... infinite loop, quest never completes ...]

Log Pattern After Fix (WORKING)

📏 UseQuestItemOnTarget: Bot distance to target=139.9yd (safe range: 11.0-30.0yd)
⚠️ UseQuestItemOnTarget: Bot TOO FAR from target (139.9yd > 30.0yd) - MOVING TOWARD TARGET
🏃 UseQuestItemOnTarget: Moving TOWARD target to safe position (...) at distance 11.0yd from target

[... bot travels toward target ...]

📏 UseQuestItemOnTarget: Bot distance to target=15.0yd (safe range: 11.0-30.0yd)
✅ UseQuestItemOnTarget: Bot in safe range (15.0yd), health 100.0%, preparing to use item
🛑 UseQuestItemOnTarget: Bot stopped moving
👁️ UseQuestItemOnTarget: Bot now facing target 33737 (type: Creature)
🎯 UseQuestItemOnTarget: Casting spell 62678 on Creature
✅ Quest objective completed: 1/8

Why This Bug Existed

Root Cause Analysis

  1. Similar Variable Names: angleFromBot vs angleToBot - easy to confuse
  2. Dual Context: Code handles both "too close" and "too far" scenarios
  3. "Too Close" Was Correct: The working code was implemented first
  4. Copy-Paste Error: "Too far" code likely copied but not fully adapted
  5. Testing Gap: Tests may have focused on short-distance scenarios

Why It Wasn't Caught Earlier

  • Logs showed movement commands being issued (✓)
  • Logs showed calculated positions (✓)
  • BUT: No log showed distance change over time (✗)
  • Manual testing at close range worked fine (✓)
  • Long-distance testing revealed the issue (✓✓✓)

Prevention Strategies

Code Review Checklist

  • When using GetNearPoint(), verify reference object is correct
  • When using GetRelativeAngle(), verify FROM/TO direction is correct
  • Add distance delta logs: "Distance changed from X to Y"
  • Test both "too close" and "too far" scenarios
  • Test with extreme distances (100+ yards)

Variable Naming Convention

// RECOMMENDED PATTERN:
float angleFromTarget = target->GetRelativeAngle(bot);   // FROM target TO bot
Position posNearTarget = target->GetNearPoint(...);      // Position NEAR target

float angleFromBot = bot->GetRelativeAngle(target);      // FROM bot TO target
Position posNearBot = bot->GetNearPoint(...);            // Position NEAR bot

Date: 2025-10-27 Status: ✅ DEPLOYED Impact: ALL creature trigger quests now work correctly