Esempio n. 1
0
void PhysicalObj::UpdatePosition()
{
  // No ghost allowed here !
  if (IsGhost()) {
    return;
  }

  if (m_collides_with_ground) {
    // object is not moving
    if (!IsMoving()) {
      // and has no reason to move
      if (!FootsInVacuum()) {
        if (!IsInWater()) {
          return;
        }
      } else {
        // it should fall !
        StartMoving();
      }
    }
  }

  // Compute new position.
  RunPhysicalEngine();

  if (IsGhost()) {
    return;
  }

  // Classical object sometimes sinks in water and sometimes goes out of water!
  if (m_collides_with_ground) {
    if (IsInWater() && m_alive!=DROWNED && m_alive!=DEAD) Drown();
    else if (!IsInWater() && m_alive==DROWNED) GoOutOfWater();
  }
}
Esempio n. 2
0
bool CEntity::FVisible(CEntity *pEntity)
{
    // don't look through water
    if (IsInWater() != pEntity->IsInWater())
        return false;

    return (TestLine(EyePosition(), pEntity->EyePosition(), true, pEntity).fraction >= 1.0);
}
Esempio n. 3
0
bool CEntity::FBoxVisible(CEntity *pEntity, Vector *pvHit, unsigned char *ucBodyPart)
{
    if (ucBodyPart)
        *ucBodyPart = 0;

    // don't look through water
    if (IsInWater() != pEntity->IsInWater())
        return false;

    bool            fVisible = false;
    traceresult_t   tr;

    // Check direct Line to waist
    Vector vecLookerOrigin = GetGunPosition();
    Vector vecTarget = pEntity->GetOrigin();
    tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);
    if (tr.fraction >= 1.0) {
        if (pvHit)
            *pvHit = tr.endpos;
        if (ucBodyPart)
            *ucBodyPart |= WAIST_VISIBLE;
        fVisible = true;
    }

    // Check direct Line to head
    vecTarget = pEntity->GetGunPosition();
    tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);
    if (tr.fraction >= 1.0) {
        if (pvHit)
            *pvHit = tr.endpos;
        if (ucBodyPart)
            *ucBodyPart |= HEAD_VISIBLE;
        fVisible = true;
    }

    if (fVisible)
        return true;

    // Nothing visible - check randomly other parts of body
    for (int i = 0; i < 5; i++) {
        vecTarget.x = RandomFloat(pEntity->GetAbsMin().x, pEntity->GetAbsMax().x);
        vecTarget.y = RandomFloat(pEntity->GetAbsMin().y, pEntity->GetAbsMax().y);
        vecTarget.z = RandomFloat(pEntity->GetAbsMin().z, pEntity->GetAbsMax().z);

        tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);

        if (tr.fraction == 1.0) {
            // Return seen position
            if (pvHit)
                *pvHit = tr.endpos;
            if (ucBodyPart)
                *ucBodyPart |= CUSTOM_VISIBLE;
            return true;
        }
    }

    return false; // it's invisible
}
Esempio n. 4
0
    void JustSummoned(Creature* pCreature)
    {
        if (pCreature->GetEntry() != NPC_SCORCH)
            return;
        if (IsInWater())
            pCreature->ForcedDespawn();

        DoScriptText(urand(0, 1) ? SAY_SCORCH1 : SAY_SCORCH2, m_creature);
        m_creature->SetFacingToObject(pCreature);
        pCreature->SetDisplayId(11686);
        pCreature->ForcedDespawn(SCORCH_DESPAWN_TIME);
        pCreature->CastSpell(pCreature, m_bIsRegularMode ? SPELL_SCORCH_AURA : SPELL_SCORCH_AURA_H, true, 0, 0, m_creature->GetObjectGuid());
    }
Esempio n. 5
0
/**
 * Function find higher form water or ground height for current floor
 *
 * @param x, y, z    Coordinates original point at floor level
 *
 * @param pGround    optional arg for retrun calculated by function work ground height, it let avoid in caller code recalculate height for point if it need
 *
 * @param swim       z coordinate can be calculated for select above/at or under z coordinate (for fly or swim/walking by bottom)
 *                   in last cases for in water returned under water height for avoid client set swimming unit as saty at water.
 *
 * @return           calculated z coordinate
 */
float TerrainInfo::GetWaterOrGroundLevel(float x, float y, float z, float* pGround /*= NULL*/, bool swim /*= false*/) const
{
    if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
    {
        // we need ground level (including grid height version) for proper return water level in point
        float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH) + 0.05f;
        if (pGround)
            *pGround = ground_z;

        GridMapLiquidData liquid_status;

        if (!IsInWater(x, y, z, &liquid_status))
            return ground_z;
        else
            return swim ? liquid_status.level - 2.0f : liquid_status.level;
    }

    return VMAP_INVALID_HEIGHT_VALUE;
}
Esempio n. 6
0
bool CFeature::UpdateVelocity(
	const float3& dragAccel,
	const float3& gravAccel,
	const float3& movMask,
	const float3& velMask
) {
	// apply drag and gravity to speed; leave more advanced physics (water
	// buoyancy, etc) to Lua
	// NOTE:
	//   all these calls use the base-class because FeatureHandler::Update
	//   iterates over updateFeatures and our ::SetVelocity will insert us
	//   into that
	//
	// drag is only valid for current speed, needs to be applied first
	CWorldObject::SetVelocity((speed + dragAccel) * velMask);

	if (!IsInWater()) {
		// quadratic downward acceleration if not in water
		CWorldObject::SetVelocity(((speed * OnesVector) + gravAccel) * velMask);
	} else {
		// constant downward speed otherwise, unless floating
		CWorldObject::SetVelocity(((speed *   XZVector) + gravAccel * (1 - def->floating)) * velMask);
	}

	const float oldGroundHeight = CGround::GetHeightReal(pos        );
	const float newGroundHeight = CGround::GetHeightReal(pos + speed);

	// adjust vertical speed so we do not sink into the ground
	if ((pos.y + speed.y) <= newGroundHeight) {
		speed.y  = std::min(newGroundHeight - pos.y, math::fabs(newGroundHeight - oldGroundHeight));
		speed.y *= moveCtrl.velocityMask.y;
	}

	// indicates whether to update quadfield position
	return ((speed.x * movMask.x) != 0.0f || (speed.z * movMask.z) != 0.0f);
}
Esempio n. 7
0
// Move to a point with collision test
collision_t PhysicalObj::NotifyMove(Point2d oldPos, Point2d newPos)
{
  if (IsGhost())
    return NO_COLLISION;

  Point2d contactPos;
  Double contactAngle;
  Point2d pos, offset;
  PhysicalObj* collided_obj = NULL;

  collision_t collision = NO_COLLISION;

  // Convert meters to pixels.
  oldPos *= PIXEL_PER_METER;
  newPos *= PIXEL_PER_METER;

  // Compute distance between old and new position.
  Double lg = oldPos.SquareDistance(newPos);

  MSG_DEBUG("physic.move", "%s moves (%s, %s) -> (%s, %s), square distance: %s",
            GetName().c_str(),
            Double2str(oldPos.x).c_str(), Double2str(oldPos.y).c_str(),
            Double2str(newPos.x).c_str(), Double2str(newPos.y).c_str(),
            Double2str(lg).c_str());

  if (!lg.IsNotZero())
    return NO_COLLISION;

  // Compute increments to move the object step by step from the old
  // to the new position.
  lg = sqrt(lg);
  offset = (newPos - oldPos) / lg;

  // First iteration position.
  pos = oldPos + offset;

  if (!m_collides_with_ground || IsInWater()) {
    MSG_DEBUG("physic.move", "%s moves (%s, %s) -> (%s, %s), collides ground:%d, water:%d",
              GetName().c_str(),
              Double2str(oldPos.x).c_str(), Double2str(oldPos.y).c_str(),
              Double2str(newPos.x).c_str(), Double2str(newPos.y).c_str(),
              m_collides_with_ground, IsInWater());

    SetXY(newPos);
    return NO_COLLISION;
  }

  do {
    Point2i tmpPos(uround(pos.x), uround(pos.y));

    // Check if we exit the GetWorld(). If so, we stop moving and return.
    if (IsOutsideWorldXY(tmpPos)) {

      if (!GetWorld().IsOpen()) {
        tmpPos.x = InRange_Long(tmpPos.x, 0, GetWorld().GetWidth() - GetWidth() - 1);
        tmpPos.y = InRange_Long(tmpPos.y, 0, GetWorld().GetHeight() - GetHeight() - 1);
        MSG_DEBUG("physic.state", "%s - DeplaceTestCollision touche un bord : %d, %d",
                  GetName().c_str(), tmpPos.x, tmpPos.y);
        collision = COLLISION_ON_GROUND;
        break;
      }

      SetXY(pos);

      MSG_DEBUG("physic.move", "%s moves (%f, %f) -> (%f, %f) : OUTSIDE WORLD",
                GetName().c_str(), oldPos.x.tofloat(), oldPos.y.tofloat(),
                newPos.x.tofloat(), newPos.y.tofloat());
      return NO_COLLISION;
    }

    // Test if we collide...
    collided_obj = CollidedObjectXY(tmpPos);
    if (collided_obj) {
      if (!m_go_through_objects || m_last_collided_object != collided_obj) {
        MSG_DEBUG("physic.state", "%s collide on %s", GetName().c_str(), collided_obj->GetName().c_str());

        if (m_go_through_objects) {
          SignalObjectCollision(GetSpeed(), collided_obj, collided_obj->GetSpeed());
          collision = NO_COLLISION;
        } else {
          collision = COLLISION_ON_OBJECT;
        }
        m_last_collided_object = collided_obj;
      } else {
        collided_obj = NULL;
        collision = NO_COLLISION;
      }
    } else if (!IsInVacuumXY(tmpPos, false)) {
      collision = COLLISION_ON_GROUND;
      m_last_collided_object = NULL;
    }

    if (collision != NO_COLLISION) {
      // Nothing more to do!
      MSG_DEBUG("physic.state", "%s - Collision at %d,%d : on %s",
                GetName().c_str(), tmpPos.x, tmpPos.y,
                collision == COLLISION_ON_GROUND ? "ground" : "an object");

      // Set the object position to the current position.
      SetXY(Point2d(pos.x - offset.x, pos.y - offset.y));
      break;
    }

    // Next motion step
    pos += offset;
    lg -= ONE;
  } while (ZERO < lg);

  Point2d speed_before_collision = GetSpeed();
  Point2d speed_collided_obj;
  if (collided_obj) {
    speed_collided_obj = collided_obj->GetSpeed();
  }

  ContactPointAngleOnGround(pos, contactPos, contactAngle);

  Collide(collision, collided_obj, pos);

  // ===================================
  // it's time to signal object(s) about collision!
  // WARNING: the following calls can send Action(s) over the network (cf bug #11232)
  // Be sure to keep it isolated here
  // ===================================
  ActiveTeam().AccessWeapon().NotifyMove(!!collision);
  switch (collision) {
  case NO_COLLISION:
    // Nothing more to do!
    break;
  case COLLISION_ON_GROUND:
    SignalGroundCollision(speed_before_collision, contactAngle);
    break;
  case COLLISION_ON_OBJECT:
    SignalObjectCollision(speed_before_collision, collided_obj, speed_collided_obj);
    collided_obj->SignalObjectCollision(speed_collided_obj, this, speed_before_collision);
    break;
  }
  // ===================================

  return collision;
}
Esempio n. 8
0
void Bot::CombatFight (void)
{
   // no enemy? no need to do strafing
   if (FNullEnt (m_enemy))
      return;

   Vector enemyOrigin = m_lookAt;

   if (m_currentWeapon == WEAPON_KNIFE)
      m_destOrigin = m_enemy->v.origin;

   enemyOrigin = (enemyOrigin - EyePosition ()).SkipZ (); // ignore z component (up & down)

   float distance = enemyOrigin.GetLength ();  // how far away is the enemy scum?

   if (m_timeWaypointMove + m_frameInterval < engine->GetTime ())
   {
      if (m_currentWeapon == WEAPON_KNIFE)
         return;

      int approach;

      if ((m_states & STATE_SUSPECTENEMY) && !(m_states & STATE_SEEINGENEMY)) // if suspecting enemy stand still
         approach = 49;
      else if (m_isReloading || m_isVIP) // if reloading or vip back off
         approach = 29;
      else if (m_currentWeapon == WEAPON_KNIFE) // knife?
         approach = 100;
      else
      {
         approach = static_cast <int> (pev->health * m_agressionLevel);

         if (UsesSniper () && (approach > 49))
            approach = 49;
      }

      // only take cover when bomb is not planted and enemy can see the bot or the bot is VIP
      if (approach < 30 && !g_bombPlanted && (::IsInViewCone (pev->origin, m_enemy) || m_isVIP))
      {
         m_moveSpeed = -pev->maxspeed;

         GetCurrentTask ()->taskID = TASK_SEEKCOVER;
         GetCurrentTask ()->canContinue = true;
         GetCurrentTask ()->desire = TASKPRI_FIGHTENEMY + 1.0f;
      }
      else if (approach < 50)
         m_moveSpeed = 0.0f;
      else
         m_moveSpeed = pev->maxspeed;

      if (distance < 96 && m_currentWeapon != WEAPON_KNIFE)
         m_moveSpeed = -pev->maxspeed;

      if (UsesSniper ())
      {
         m_fightStyle = 1;
         m_lastFightStyleCheck = engine->GetTime ();
      }
      else if (UsesRifle () || UsesSubmachineGun ())
      {
         if (m_lastFightStyleCheck + 3.0f < engine->GetTime ())
         {
            int rand = engine->RandomInt (1, 100);

            if (distance < 450)
               m_fightStyle = 0;
            else if (distance < 1024)
            {
               if (rand < (UsesSubmachineGun () ? 50 : 30))
                  m_fightStyle = 0;
               else
                  m_fightStyle = 1;
            }
            else
            {
               if (rand < (UsesSubmachineGun () ? 80 : 93))
                  m_fightStyle = 1;
               else
                  m_fightStyle = 0;
            }
            m_lastFightStyleCheck = engine->GetTime ();
         }
      }
      else
      {
         if (m_lastFightStyleCheck + 3.0f < engine->GetTime ())
         {
            if (engine->RandomInt (0, 100) < 65)
               m_fightStyle = 1;
            else
               m_fightStyle = 0;

            m_lastFightStyleCheck = engine->GetTime ();
         }
      }

      if ((m_skill > 50 && m_fightStyle == 0) || ((pev->button & IN_RELOAD) || m_isReloading) || (UsesPistol () && distance < 500.0f))
      {
         if (m_strafeSetTime < engine->GetTime ())
         {
            // to start strafing, we have to first figure out if the target is on the left side or right side
            MakeVectors (m_enemy->v.v_angle);

            Vector dirToPoint = (pev->origin - m_enemy->v.origin).Normalize2D ();
            Vector rightSide = g_pGlobals->v_right.Normalize2D ();

            if ((dirToPoint | rightSide) < 0)
               m_combatStrafeDir = 1;
            else
               m_combatStrafeDir = 0;

            if (engine->RandomInt (1, 100) < 30)
               m_combatStrafeDir ^= 1;

            m_strafeSetTime = engine->GetTime () + engine->RandomFloat (0.5, 2.5);
         }

         if (m_combatStrafeDir == 0)
         {
            if (!CheckWallOnLeft ())
               m_strafeSpeed = -160.0f;
            else
            {
               m_combatStrafeDir ^= 1;
               m_strafeSetTime = engine->GetTime () + 0.7f;
            }
         }
         else
         {
            if (!CheckWallOnRight ())
               m_strafeSpeed = 160.0f;
            else
            {
               m_combatStrafeDir ^= 1;
               m_strafeSetTime = engine->GetTime () + 1.0f;
            }
         }

         if (m_skill > 80 && (m_jumpTime + 5.0f < engine->GetTime () && IsOnFloor () && engine->RandomInt (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D () > 150.0f))
            pev->button |= IN_JUMP;

         if (m_moveSpeed != 0.0f && distance > 150.0f)
            m_moveSpeed = 0.0f;
      }
      else if (m_fightStyle == 1)
      {
         bool shouldDuck = true; // should duck

         // check the enemy height
         float enemyHalfHeight = ((m_enemy->v.flags & FL_DUCKING) == FL_DUCKING ? 36.0f : 72.0f) / 2;

         // check center/feet
         if (!IsVisible (m_enemy->v.origin, GetEntity ()) && !IsVisible (m_enemy->v.origin + Vector (0, 0, -enemyHalfHeight), GetEntity ()))
            shouldDuck = false;

         int nearestToEnemyPoint = g_waypoint->FindNearest (m_enemy->v.origin);

         if (shouldDuck && GetCurrentTask ()->taskID != TASK_SEEKCOVER && GetCurrentTask ()->taskID != TASK_HUNTENEMY && (m_visibility & VISIBILITY_BODY) && !(m_visibility & VISIBILITY_OTHER) && g_waypoint->IsDuckVisible (m_currentWaypointIndex, nearestToEnemyPoint))
            m_duckTime = engine->GetTime () + m_frameInterval * 3.5f;

         m_moveSpeed = 0.0f;
         m_strafeSpeed = 0.0f;
         m_navTimeset = engine->GetTime ();
      }
   }

   if (m_duckTime > engine->GetTime ())
   {
      m_moveSpeed = 0.0f;
      m_strafeSpeed = 0.0f;
   }

   if (m_moveSpeed != 0.0f)
      m_moveSpeed = GetWalkSpeed ();

   if (m_isReloading)
   {
      m_moveSpeed = -pev->maxspeed;
      m_duckTime = engine->GetTime () - (m_frameInterval * 4.0f);
   }

   if (!IsInWater () && !IsOnLadder () && (m_moveSpeed != 0 || m_strafeSpeed != 0))
   {
      MakeVectors (pev->v_angle);

      if (IsDeadlyDrop (pev->origin + (g_pGlobals->v_forward * m_moveSpeed * 0.2f) + (g_pGlobals->v_right * m_strafeSpeed * 0.2f) + (pev->velocity * m_frameInterval)))
      {
         m_strafeSpeed = -m_strafeSpeed;
         m_moveSpeed = -m_moveSpeed;

         pev->button &= ~IN_JUMP;
      }
   }
}
Esempio n. 9
0
// SyPB Pro P.30 - Attack Ai
void Bot::CombatFight(void)
{
	if (FNullEnt(m_enemy))
		return;

	//if (m_currentWeapon == WEAPON_KNIFE)

	// SyPB Pro P.34 - Base Ai
	m_destOrigin = GetEntityOrigin(m_enemy);

	// SyPB Pro P.30 - Zombie Mod
	if (GetGameMod() == 2 || GetGameMod () == 4) // SyPB Pro P.37 - small change
	{
		m_currentWaypointIndex = -1;
		m_prevGoalIndex = -1;
		m_moveToGoal = false;
		m_navTimeset = engine->GetTime();
		
		if (IsZombieBot(GetEntity()))
		{
			m_moveSpeed = pev->maxspeed; 
			return;
		}
	}

	Vector enemyOrigin = GetEntityOrigin(m_enemy);
	float distance = (pev->origin - enemyOrigin).GetLength();

	if (m_timeWaypointMove + m_frameInterval < engine->GetTime())
	{
		if (GetGameMod() == 2)
		{
			float baseDistance = 600.0f;

			if (::IsInViewCone(pev->origin, m_enemy) && 
				GetNearbyEnemiesNearPosition (GetEntityOrigin (m_enemy), 300) < 3) // SyPB Pro P.37 - Zombie Mode Attack Ai
			{
				if (m_currentWeapon == WEAPON_KNIFE)
					baseDistance = 450.0f;
				else
					baseDistance = 400.0f;
			}
			else
			{
				if (m_currentWeapon == WEAPON_KNIFE)
					baseDistance = -1.0f;
				else
					baseDistance = 300.0f;
			}

			if (baseDistance != -1.0f)
			{
				int fdPlayer = GetNearbyFriendsNearPosition(pev->origin, (baseDistance > 0.0f) ? int(baseDistance) / 2 : 300);
				int enPlayer = GetNearbyEnemiesNearPosition(enemyOrigin, (baseDistance > 0.0f) ? int(baseDistance) : 400);

				baseDistance -= (fdPlayer * 10.0f);
				baseDistance += (enPlayer * 20.0f);

				if (baseDistance <= 0.0f)
					baseDistance = 50.0f;
			}

			if (baseDistance < 0.0f)
				m_moveSpeed = pev->maxspeed;
			else
			{
				if (distance <= baseDistance)
					m_moveSpeed = -pev->maxspeed;
				else if (distance >= (baseDistance + 100.0f))
					m_moveSpeed = 0.0f;
			}

			if (m_moveSpeed > 0.0f)
			{
				if (baseDistance != -1.0f)
				{
					if (distance <= 100)
						m_moveSpeed = -pev->maxspeed;
					else
						m_moveSpeed = 0.0f;
				}
			}
		}
		else if (GetGameMod() == 1)
		{
			if (m_currentWeapon == WEAPON_KNIFE)
				m_moveSpeed = pev->maxspeed;
			else
				m_moveSpeed = 0.0f;
		}
		else
		{
			int approach;

			if ((m_states & STATE_SUSPECTENEMY) && !(m_states & STATE_SEEINGENEMY)) // if suspecting enemy stand still
				approach = 49;
			else if (m_isReloading || m_isVIP) // if reloading or vip back off
				approach = 29;
			else if (m_currentWeapon == WEAPON_KNIFE) // knife?
				approach = 100;
			else
			{
				approach = static_cast <int> (pev->health * m_agressionLevel);

				if (UsesSniper() && (approach > 49))
					approach = 49;

				// SyPB Pro P.35 - Base mode Weapon Ai Improve
				if (UsesSubmachineGun())
					approach += 20;
			}
			
			// only take cover when bomb is not planted and enemy can see the bot or the bot is VIP
			if (approach < 30 && !g_bombPlanted && (::IsInViewCone(pev->origin, m_enemy) && !UsesSniper () || m_isVIP))
			{
				m_moveSpeed = -pev->maxspeed;

				GetCurrentTask()->taskID = TASK_SEEKCOVER;
				GetCurrentTask()->canContinue = true;
				GetCurrentTask()->desire = TASKPRI_FIGHTENEMY + 1.0f;
			}
			else if (approach < 50)
				m_moveSpeed = 0.0f;
			else
				m_moveSpeed = pev->maxspeed;

			// SyPB Pro P.35 - Base mode Weapon Ai Improve
			if (distance < 96 && m_currentWeapon != WEAPON_KNIFE)
			{
				pev->button |= IN_DUCK;
				m_moveSpeed = -pev->maxspeed;
			}
		}

		if (UsesSniper())
		{
			m_fightStyle = 1;
			m_lastFightStyleCheck = engine->GetTime();
		}
		else if (UsesRifle() || UsesSubmachineGun())
		{
			if (m_lastFightStyleCheck + 3.0f < engine->GetTime())
			{
				int rand = engine->RandomInt(1, 100);

				if (distance < 450)
					m_fightStyle = 0;
				else if (distance < 1024)
				{
					if (rand < (UsesSubmachineGun() ? 50 : 30))
						m_fightStyle = 0;
					else
						m_fightStyle = 1;
				}
				else
				{
					if (rand < (UsesSubmachineGun() ? 80 : 93))
						m_fightStyle = 1;
					else
						m_fightStyle = 0;
				}
				m_lastFightStyleCheck = engine->GetTime();
			}
		}
		else
		{
			if (m_lastFightStyleCheck + 3.0f < engine->GetTime())
			{
				if (engine->RandomInt(0, 100) < 65)
					m_fightStyle = 1;
				else
					m_fightStyle = 0;

				m_lastFightStyleCheck = engine->GetTime();
			}
		}

		if (((pev->button & IN_RELOAD) || (m_isReloading) || (m_skill >= 70 && m_fightStyle && distance < 800.0f)) &&
			GetGameMod () != 2 && GetGameMod () != 4)
		{
			if (m_strafeSetTime < engine->GetTime())
			{
				// to start strafing, we have to first figure out if the target is on the left side or right side
				MakeVectors(m_enemy->v.v_angle);

				Vector dirToPoint = (pev->origin - GetEntityOrigin(m_enemy)).Normalize2D();
				Vector rightSide = g_pGlobals->v_right.Normalize2D();

				if ((dirToPoint | rightSide) < 0)
					m_combatStrafeDir = 1;
				else
					m_combatStrafeDir = 0;

				if (engine->RandomInt(1, 100) < 30)
					m_combatStrafeDir ^= 1;

				m_strafeSetTime = engine->GetTime() + engine->RandomFloat(0.5, 2.5);
			}

			if (m_combatStrafeDir == 0)
			{
				if (!CheckWallOnLeft())
					m_strafeSpeed = -160.0f;
				else
				{
					m_combatStrafeDir ^= 1;
					m_strafeSetTime = engine->GetTime() + 0.7f;
				}
			}
			else
			{
				if (!CheckWallOnRight())
					m_strafeSpeed = 160.0f;
				else
				{
					m_combatStrafeDir ^= 1;
					m_strafeSetTime = engine->GetTime() + 1.0f;
				}
			}

			if (m_skill > 80 && (m_jumpTime + 5.0f < engine->GetTime() && IsOnFloor() && engine->RandomInt(0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.GetLength2D() > 150.0f))
				pev->button |= IN_JUMP;
		}
		else if ((GetGameMod() != 2 && m_fightStyle) || (m_fightStyle && m_moveSpeed == 0.0f))
		{
			bool shouldDuck = true; // should duck

			// check the enemy height
			float enemyHalfHeight = ((m_enemy->v.flags & FL_DUCKING) == FL_DUCKING ? 36.0f : 72.0f) / 2;

			// check center/feet
			if (!IsVisible(GetEntityOrigin(m_enemy), GetEntity()) && !IsVisible(GetEntityOrigin(m_enemy) + Vector(0, 0, -enemyHalfHeight), GetEntity()))
				shouldDuck = false;

			int nearestToEnemyPoint = g_waypoint->FindNearest(GetEntityOrigin(m_enemy));

			if (shouldDuck && GetCurrentTask()->taskID != TASK_SEEKCOVER && GetCurrentTask()->taskID != TASK_HUNTENEMY && (m_visibility & VISIBILITY_BODY) && !(m_visibility & VISIBILITY_OTHER) && g_waypoint->IsDuckVisible(m_currentWaypointIndex, nearestToEnemyPoint))
				m_duckTime = engine->GetTime() + m_frameInterval * 3.5f;

			m_moveSpeed = 0.0f;
			m_strafeSpeed = 0.0f;
			m_navTimeset = engine->GetTime();
		}
		else
			m_strafeSpeed = 0.0f;
	}

	if (m_duckTime > engine->GetTime())
	{
		m_moveSpeed = 0.0f;
		m_strafeSpeed = 0.0f;
	}

	if (GetGameMod() == 2)
		return;

	if (m_moveSpeed != 0.0f)
		m_moveSpeed = GetWalkSpeed();

	if (m_isReloading)
	{
		m_moveSpeed = -pev->maxspeed;
		m_duckTime = engine->GetTime() - (m_frameInterval * 4.0f);
	}

	if (!IsInWater() && !IsOnLadder())
	{
		if (m_moveSpeed != 0 || m_strafeSpeed != 0)
		{
			if (IsDeadlyDrop(pev->origin + (g_pGlobals->v_forward * m_moveSpeed * 0.2f) + (g_pGlobals->v_right * m_strafeSpeed * 0.2f) + (pev->velocity * m_frameInterval)))
			{
				m_strafeSpeed = -m_strafeSpeed;
				m_moveSpeed = -m_moveSpeed;

				pev->button &= ~IN_JUMP;
			}
		}
	}
}