bool CHostageImprov::FaceTowards(const Vector &target, float deltaT) { bool bError = false; Vector2D to = (target - GetFeet()).Make2D(); #ifndef PLAY_GAMEDLL to.NormalizeInPlace(); #else // TODO: fix test demo float_precision float_x = target.x - GetFeet().x; float_precision float_y = target.y - GetFeet().y; float_precision flLen = to.Length(); if (flLen <= 0) { to.x = 1; to.y = 0; } else { to.x = float_x / flLen; to.y = float_y / flLen; } #endif float moveAngle = GetMoveAngle(); Vector2D lat(BotCOS(moveAngle), BotSIN(moveAngle)); Vector2D dir(-lat.y, lat.x); float_precision dot = DotProduct(to, dir); if (DotProduct(to, lat) < 0.0f) { if (dot >= 0.0f) dot = 1.0f; else dot = -1.0f; bError = true; } const float maxTurnRate = 0.05f; if (bError || Q_fabs(dot) >= maxTurnRate) { const float tolerance = 300.0f; float moveRatio = dot * deltaT * tolerance + moveAngle; BotCOS(moveRatio); BotSIN(moveRatio); m_moveAngle = moveRatio; m_hostage->pev->angles.y = moveRatio; return false; } return true; }
NOXREF void CCSBot::MoveAwayFromPosition(const Vector *pos) { // compute our current forward and lateral vectors float angle = pev->v_angle[ YAW ]; 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 away from 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.5f; if (toProj > c) MoveBackward(); else if (toProj < -c) MoveForward(); if (latProj >= c) StrafeRight(); else if (latProj <= -c) StrafeLeft(); }
void CCSBot::Panic(CBasePlayer *pEnemy) { if (IsSurprised()) return; Vector2D dir(BotCOS(pev->v_angle.y), BotSIN(pev->v_angle.y)); Vector2D perp(-dir.y, dir.x); Vector spot; if (GetProfile()->GetSkill() >= 0.5f) { Vector2D toEnemy = (pEnemy->pev->origin - pev->origin).Make2D(); toEnemy.NormalizeInPlace(); float along = DotProduct(toEnemy, dir); float c45 = 0.7071f; float size = 100.0f; real_t shift = RANDOM_FLOAT(-75.0, 75.0); if (along > c45) { spot.x = pev->origin.x + dir.x * size + perp.x * shift; spot.y = pev->origin.y + dir.y * size + perp.y * shift; } else if (along < -c45) { spot.x = pev->origin.x - dir.x * size + perp.x * shift; spot.y = pev->origin.y - dir.y * size + perp.y * shift; } else if (DotProduct(toEnemy, perp) > 0.0) { spot.x = pev->origin.x + perp.x * size + dir.x * shift; spot.y = pev->origin.y + perp.y * size + dir.y * shift; } else { spot.x = pev->origin.x - perp.x * size + dir.x * shift; spot.y = pev->origin.y - perp.y * size + dir.y * shift; } } else { const float offset = 200.0f; real_t side = RANDOM_FLOAT(-offset, offset) * 2.0f; spot.x = pev->origin.x - dir.x * offset + perp.x * side; spot.y = pev->origin.y - dir.y * offset + perp.y * side; } spot.z = pev->origin.z + RANDOM_FLOAT(-50.0, 50.0); // we are stunned for a moment m_surpriseDelay = RANDOM_FLOAT(0.1, 0.2); m_surpriseTimestamp = gpGlobals->time; SetLookAt("Panic", &spot, PRIORITY_HIGH, 0, 0, 5.0); PrintIfWatched("Aaaah!\n"); }
/* <5d4160> ../cstrike/dlls/bot/states/cs_bot_plant_bomb.cpp:17 */ void PlantBombState::__MAKE_VHOOK(OnEnter)(CCSBot *me) { me->Crouch(); me->SetDisposition(CCSBot::SELF_DEFENSE); float yaw = me->pev->v_angle.y; Vector2D dir(BotCOS(yaw), BotSIN(yaw)); Vector down(me->pev->origin.x + 10.0f * dir.x, me->pev->origin.y + 10.0f * dir.y, me->GetFeetZ()); me->SetLookAt("Plant bomb on floor", &down, PRIORITY_HIGH); }
/** * Plant the bomb. */ void PlantBombState::OnEnter( CCFBot *me ) { me->Crouch(); me->SetDisposition( CCFBot::SELF_DEFENSE ); // look at the floor // Vector down( myOrigin.x, myOrigin.y, -1000.0f ); float yaw = me->EyeAngles().y; Vector2D dir( BotCOS(yaw), BotSIN(yaw) ); Vector myOrigin = GetCentroid( me ); Vector down( myOrigin.x + 10.0f * dir.x, myOrigin.y + 10.0f * dir.y, me->GetFeetZ() ); me->SetLookAt( "Plant bomb on floor", down, PRIORITY_HIGH ); }
void CCSBot::StrafeAwayFromPosition(const Vector *pos) { // compute our current forward and lateral vectors float angle = pev->v_angle[ YAW ]; 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(); float latProj = to.x * lat.x + to.y * lat.y; if (latProj >= 0.0f) StrafeRight(); else StrafeLeft(); }
void CHostageImprov::Wiggle() { // for wiggling if (m_wiggleTimer.IsElapsed()) { m_wiggleDirection = static_cast<NavRelativeDirType>(RANDOM_LONG(FORWARD, LEFT)); m_wiggleTimer.Start(RANDOM_FLOAT(0.3f, 0.5f)); } const float force = 15.0f; Vector dir(BotCOS(m_moveAngle), BotSIN(m_moveAngle), 0.0f); Vector lat(-dir.y, dir.x, 0.0f); switch (m_wiggleDirection) { case FORWARD: ApplyForce(dir * force); break; case BACKWARD: ApplyForce(dir * -force); break; case LEFT: ApplyForce(lat * force); break; case RIGHT: ApplyForce(lat * -force); break; default: break; } const float minStuckJumpTime = 0.5f; if (m_follower.GetStuckDuration() > minStuckJumpTime && m_wiggleJumpTimer.IsElapsed()) { if (Jump()) { m_wiggleJumpTimer.Start(RANDOM_FLOAT(0.75f, 1.2f)); } } }
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(); }
// "Bend" our line of sight around corners until we can "see" the point. bool CCSBot::BendLineOfSight(const Vector *eye, const Vector *point, Vector *bend) const { // if we can directly see the point, use it TraceResult result; UTIL_TraceLine(*eye, *point + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result); if (result.flFraction == 1.0f && !result.fStartSolid) { // can directly see point, no bending needed *bend = *point; return true; } // "bend" our line of sight until we can see the approach point Vector v = *point - *eye; float startAngle = UTIL_VecToYaw(v); float length = v.Length2D(); v.NormalizeInPlace(); float angleInc = 10.0f; for (float angle = angleInc; angle <= 135.0f; angle += angleInc) { // check both sides at this angle offset for (int side = 0; side < 2; ++side) { float actualAngle = (side) ? (startAngle + angle) : (startAngle - angle); float dx = BotCOS(actualAngle); float dy = BotSIN(actualAngle); // compute rotated point ray endpoint Vector rotPoint(eye->x + length * dx, eye->y + length * dy, point->z); TraceResult result; UTIL_TraceLine(*eye, rotPoint + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result); // if this ray started in an obstacle, skip it if (result.fStartSolid) { continue; } Vector ray = rotPoint - *eye; float rayLength = ray.NormalizeInPlace(); float visibleLength = rayLength * result.flFraction; // step along ray, checking if point is visible from ray point const float bendStepSize = 50.0f; for (float bendLength = bendStepSize; bendLength <= visibleLength; bendLength += bendStepSize) { // compute point along ray Vector rayPoint = *eye + bendLength * ray; // check if we can see approach point from this bend point UTIL_TraceLine(rayPoint, *point + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result); if (result.flFraction == 1.0f && !result.fStartSolid) { // target is visible from this bend point on the ray - use this point on the ray as our point // keep "bent" point at correct height along line of sight if (!GetGroundHeight(&rayPoint, &rayPoint.z)) { rayPoint.z = point->z; } *bend = rayPoint; return true; } } } } *bend = *point; // bending rays didn't help - still can't see the point return false; }
/** * Do reflex avoidance movements if our "feelers" are touched * @todo Parameterize feeler spacing */ void CNavPathFollower::FeelerReflexAdjustment( Vector *goalPosition, float height ) { // if we are in a "precise" area, do not do feeler adjustments if (m_improv->GetLastKnownArea() && m_improv->GetLastKnownArea()->GetAttributes() & NAV_PRECISE) return; Vector dir( BotCOS( m_improv->GetMoveAngle() ), BotSIN( m_improv->GetMoveAngle() ), 0.0f ); dir.z = 0.0f; dir.NormalizeInPlace(); Vector lat( -dir.y, dir.x, 0.0f ); const float feelerOffset = (m_improv->IsCrouching()) ? 20.0f : 25.0f; // 15, 20 const float feelerLengthRun = 50.0f; // 100 - too long for tight hallways (cs_747) const float feelerLengthWalk = 30.0f; const float feelerHeight = (height > 0.0f) ? height : StepHeight + 0.1f; // if obstacle is lower than StepHeight, we'll walk right over it float feelerLength = (m_improv->IsRunning()) ? feelerLengthRun : feelerLengthWalk; feelerLength = (m_improv->IsCrouching()) ? 20.0f : feelerLength; // // Feelers must follow floor slope // float ground; Vector normal; if (m_improv->GetSimpleGroundHeightWithFloor( &m_improv->GetEyes(), &ground, &normal ) == false) return; // get forward vector along floor dir = CrossProduct( lat, normal ); // correct the sideways vector lat = CrossProduct( dir, normal ); Vector feet = m_improv->GetFeet(); feet.z += feelerHeight; Vector from = feet + feelerOffset * lat; Vector to = from + feelerLength * dir; bool leftClear = IsWalkableTraceLineClear( from, to, WALK_THRU_DOORS | WALK_THRU_BREAKABLES ); // draw debug beams if (m_isDebug) { 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_DOORS | WALK_THRU_BREAKABLES ); // draw debug beams if (m_isDebug) { if (rightClear) UTIL_DrawBeamPoints( from, to, 1, 0, 255, 0 ); else UTIL_DrawBeamPoints( from, to, 1, 255, 0, 0 ); } const float avoidRange = (m_improv->IsCrouching()) ? 150.0f : 300.0f; if (!rightClear) { if (leftClear) { // right hit, left clear - veer left *goalPosition = *goalPosition + avoidRange * lat; //*goalPosition = m_improv->GetFeet() + avoidRange * lat; //m_improv->StrafeLeft(); } } else if (!leftClear) { // right clear, left hit - veer right *goalPosition = *goalPosition - avoidRange * lat; //*goalPosition = m_improv->GetFeet() - avoidRange * lat; //m_improv->StrafeRight(); } }
// 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; } }