void CCSBot::MoveTowardsPosition(const Vector *pos) { // Jump up on ledges // Because we may not be able to get to our goal position and enter the next // area because our extent collides with a nearby vertical ledge, make sure // we look far enough ahead to avoid this situation. // Can't look too far ahead, or bots will try to jump up slopes. // NOTE: We need to do this frequently to catch edges at the right time // TODO: Look ahead *along path* instead of straight line if ((m_lastKnownArea == NULL || !(m_lastKnownArea->GetAttributes() & NAV_NO_JUMP)) && !IsOnLadder() && !m_isJumpCrouching) { float ground; Vector aheadRay(pos->x - pev->origin.x, pos->y - pev->origin.y, 0); aheadRay.NormalizeInPlace(); // look far ahead to allow us to smoothly jump over gaps, ledges, etc // only jump if ground is flat at lookahead spot to avoid jumping up slopes bool jumped = false; if (IsRunning()) { const float farLookAheadRange = 80.0f; Vector normal; Vector stepAhead = pev->origin + farLookAheadRange * aheadRay; stepAhead.z += HalfHumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground, &normal)) { if (normal.z > 0.9f) jumped = DiscontinuityJump(ground, ONLY_JUMP_DOWN); } } if (!jumped) { // close up jumping // cant be less or will miss jumps over low walls const float lookAheadRange = 30.0f; Vector stepAhead = pev->origin + lookAheadRange * aheadRay; stepAhead.z += HalfHumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) { jumped = DiscontinuityJump(ground); } } if (!jumped) { // about to fall gap-jumping const float lookAheadRange = 10.0f; Vector stepAhead = pev->origin + lookAheadRange * aheadRay; stepAhead.z += HalfHumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) { jumped = DiscontinuityJump(ground, ONLY_JUMP_DOWN, MUST_JUMP); } } } // compute our current forward and lateral vectors float angle = pev->v_angle.y; Vector2D dir(BotCOS(angle), BotSIN(angle)); Vector2D lat(-dir.y, dir.x); // compute unit vector to goal position Vector2D to(pos->x - pev->origin.x, pos->y - pev->origin.y); to.NormalizeInPlace(); // move towards the position independant of our view direction float toProj = to.x * dir.x + to.y * dir.y; float latProj = to.x * lat.x + to.y * lat.y; const float c = 0.25f; if (toProj > c) MoveForward(); else if (toProj < -c) MoveBackward(); // if we are avoiding someone via strafing, don't override if (m_avoid != NULL) return; if (latProj >= c) StrafeLeft(); else if (latProj <= -c) StrafeRight(); }
void CHostageImprov::__MAKE_VHOOK(OnTouch)(CBaseEntity *other) { const char *classname; Vector2D to; const float pushForce = 20.0f; classname = STRING(other->pev->classname); if (cv_hostage_debug.value != 0.0) { CONSOLE_ECHO("%5.1f: Hostage hit '%s'\n", gpGlobals->time, classname); } m_collisionTimer.Start(); if (FStrEq(classname, "worldspawn")) { const float lookAheadRange = 30.0f; float ground; Vector normal = Vector(0, 0, 1); Vector alongFloor; TraceResult result; bool isStep = false; UTIL_MakeVectors(m_hostage->pev->angles); if (!GetSimpleGroundHeightWithFloor(&GetEyes(), &ground, &normal)) return; if (cv_hostage_debug.value < 0.0) { UTIL_DrawBeamPoints(GetFeet() + normal * 50, GetFeet(), 2, 255, 255, 0); } alongFloor = CrossProduct(normal, gpGlobals->v_right); Vector pos = alongFloor * lookAheadRange; for (float_precision offset = 1.0f; offset <= 18.0f; offset += 3.0f) { Vector vecStart = GetFeet(); vecStart.z += offset; UTIL_TraceLine(vecStart, vecStart + pos, ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && result.vecPlaneNormal.z < MaxUnitZSlope) { isStep = true; break; } } if (isStep) { float stepAheadGround = pos.z; Vector stepAheadNormal = Vector(0, 0, stepAheadGround); m_inhibitObstacleAvoidance.Start(0.5); for (float range = 1.0f; range <= 30.5f; range += 5.0f) { Vector stepAhead = GetFeet() + alongFloor * range; stepAhead.z = GetEyes().z; if (GetSimpleGroundHeightWithFloor(&stepAhead, &stepAheadGround, &stepAheadNormal)) { float dz = stepAheadGround - GetFeet().z; if (dz > 0.0f && dz < 18.0f) { m_hostage->pev->origin.z = stepAheadGround + 3.0f; break; } } } } else if (!IsMoving() && !IsUsingLadder()) { bool isSeam = false; const float checkSeamRange = 50.0f; Vector posBehind; posBehind = GetEyes() - alongFloor * checkSeamRange; UTIL_TraceLine(posBehind, posBehind - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) { isSeam = true; } else { Vector posAhead = GetEyes() + alongFloor * checkSeamRange; UTIL_TraceLine(posAhead, posAhead - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) isSeam = true; } if (isSeam) { if (cv_hostage_debug.value != 0.0) { CONSOLE_ECHO("Hostage stuck on seam.\n"); } const float nudge = 3.0f; m_hostage->pev->origin.z += nudge; } } } else if (FStrEq(classname, "func_breakable")) { other->TakeDamage(m_hostage->pev, m_hostage->pev, 9999.9, DMG_BULLET); } else if (other->IsPlayer() || FClassnameIs(other->pev, "hostage_entity")) { to = (m_hostage->pev->origin - other->pev->origin).Make2D(); to.NormalizeInPlace(); m_vel.x += to.x * pushForce; m_vel.y += to.y * pushForce; } }
void CHostageImprov::MoveTowards(const Vector &pos, float deltaT) { Vector move; float_precision accelRate; const float crouchWalkRate = 250.0f; // Jump up on ledges // Because we may not be able to get to our goal position and enter the next // area because our extent collides with a nearby vertical ledge, make sure // we look far enough ahead to avoid this situation. // Can't look too far ahead, or bots will try to jump up slopes. // // NOTE: We need to do this frequently to catch edges at the right time // TODO: Look ahead *along path* instead of straight line ClearPath(); if ((m_lastKnownArea == NULL || !(m_lastKnownArea->GetAttributes() & NAV_NO_JUMP)) && !IsUsingLadder() && !IsJumping() && IsOnGround() && !IsCrouching()) { float ground; Vector aheadRay(pos.x - GetFeet().x, pos.y - GetFeet().y, 0); aheadRay.NormalizeInPlace(); bool jumped = false; if (IsRunning()) { const float farLookAheadRange = 80.0f; Vector normal; Vector stepAhead = GetFeet() + farLookAheadRange * aheadRay; stepAhead.z += HumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground, &normal )) { if (normal.z > 0.9f) jumped = DiscontinuityJump(ground, HOSTAGE_ONLY_JUMP_DOWN); } } if (!jumped) { // close up jumping // cant be less or will miss jumps over low walls const float lookAheadRange = 30.0f; Vector stepAhead = GetFeet() + lookAheadRange * aheadRay; stepAhead.z += HumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) { jumped = DiscontinuityJump(ground); } } if (!jumped) { // about to fall gap-jumping const float lookAheadRange = 10.0f; Vector stepAhead = GetFeet() + lookAheadRange * aheadRay; stepAhead.z += HumanHeight; if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) { jumped = DiscontinuityJump(ground, HOSTAGE_ONLY_JUMP_DOWN, HOSTAGE_MUST_JUMP); } } } move = (pos - GetFeet()); move.z = 0; if (!move.IsZero()) { move.NormalizeInPlace(); } switch (m_moveType) { case Stopped: accelRate = 0; break; case Walking: if (IsCrouching()) accelRate = crouchWalkRate; else accelRate = 400; break; case Running: if (IsCrouching()) accelRate = crouchWalkRate; else accelRate = 1000; break; } m_vel.x = move.x * accelRate * deltaT + m_vel.x; m_vel.y = move.y * accelRate * deltaT + m_vel.y; }
// Do reflex avoidance movements if our "feelers" are touched void CCSBot::FeelerReflexAdjustment(Vector *goalPosition) { // if we are in a "precise" area, do not do feeler adjustments if (m_lastKnownArea && (m_lastKnownArea->GetAttributes() & NAV_PRECISE)) return; Vector dir(BotCOS(m_forwardAngle), BotSIN(m_forwardAngle), 0.0f); Vector lat(-dir.y, dir.x, 0.0f); const float feelerOffset = (IsCrouching()) ? 15.0f : 20.0f; const float feelerLengthRun = 50.0f; // 100 - too long for tight hallways (cs_747) const float feelerLengthWalk = 30.0f; const float feelerHeight = StepHeight + 0.1f; // if obstacle is lower than StepHeight, we'll walk right over it float feelerLength = (IsRunning()) ? feelerLengthRun : feelerLengthWalk; feelerLength = (IsCrouching()) ? 20.0f : feelerLength; // Feelers must follow floor slope float ground; Vector normal; //m_eyePos = EyePosition(); m_eyePos.x = pev->origin.x + pev->view_ofs.x; m_eyePos.y = pev->origin.y + pev->view_ofs.y; m_eyePos.z = pev->origin.z + pev->view_ofs.z; if (GetSimpleGroundHeightWithFloor(&m_eyePos, &ground, &normal) == false) return; // get forward vector along floor dir = CrossProduct(lat, normal); // correct the sideways vector lat = CrossProduct(dir, normal); Vector feet(pev->origin.x, pev->origin.y, GetFeetZ()); feet.z += feelerHeight; Vector from = feet + feelerOffset * lat; Vector to = from + feelerLength * dir; bool leftClear = IsWalkableTraceLineClear(from, to, WALK_THRU_EVERYTHING); // avoid ledges, too // use 'from' so it doesn't interfere with legitimate gap jumping (its at our feet) // TODO: Rethink this - it causes lots of wiggling when bots jump down from vents, etc /* float ground; if (GetSimpleGroundHeightWithFloor(&from, &ground)) { if (GetFeetZ() - ground > JumpHeight) leftClear = false; } */ if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f) { if (leftClear) UTIL_DrawBeamPoints(from, to, 1, 0, 255, 0); else UTIL_DrawBeamPoints(from, to, 1, 255, 0, 0); } from = feet - feelerOffset * lat; to = from + feelerLength * dir; bool rightClear = IsWalkableTraceLineClear(from, to, WALK_THRU_EVERYTHING); /* // avoid ledges, too if (GetSimpleGroundHeightWithFloor(&from, &ground)) { if (GetFeetZ() - ground > JumpHeight) rightClear = false; } */ if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f) { if (rightClear) UTIL_DrawBeamPoints(from, to, 1, 0, 255, 0); else UTIL_DrawBeamPoints(from, to, 1, 255, 0, 0); } const float avoidRange = (IsCrouching()) ? 150.0f : 300.0f; // 50.0f : 300.0f if (!rightClear) { if (leftClear) { // right hit, left clear - veer left *goalPosition = *goalPosition + avoidRange * lat; } } else if (!leftClear) { // right clear, left hit - veer right *goalPosition = *goalPosition - avoidRange * lat; } }