void cMonster::MoveToWayPoint(cChunk & a_Chunk) { if ((m_NextWayPointPosition - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS) { return; } if (m_JumpCoolDown == 0) { if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) { if (((IsOnGround()) && (GetSpeed().SqrLength() == 0.0f)) || (IsSwimming())) { m_bOnGround = false; m_JumpCoolDown = 20; // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport AddPosY(1.6); // Jump!! SetSpeedX(3.2 * (m_NextWayPointPosition.x - GetPosition().x)); // Move forward in a preset speed. SetSpeedZ(3.2 * (m_NextWayPointPosition.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect. } } } else { --m_JumpCoolDown; } Vector3d Distance = m_NextWayPointPosition - GetPosition(); if ((Distance.x != 0.0f) || (Distance.z != 0.0f)) { Distance.y = 0; Distance.Normalize(); if (m_bOnGround) { Distance *= 2.5f; } else if (IsSwimming()) { Distance *= 1.3f; } else { // Don't let the mob move too much if he's falling. Distance *= 0.25f; } // Apply walk speed: Distance *= m_RelativeWalkSpeed; /* Reduced default speed. Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence better pathfinding. */ Distance *= 0.5; AddSpeedX(Distance.x); AddSpeedZ(Distance.z); } }
void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) { StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5); if (m_AttachedTo == NULL) { if (IsClimbing()) { if (a_DeltaPos.y > 0.0) // Going up { m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5)); } } else if (IsSubmerged()) { m_Stats.AddValue(statDistDove, Value); AddFoodExhaustion(0.00015 * (double)Value); } else if (IsSwimming()) { m_Stats.AddValue(statDistSwum, Value); AddFoodExhaustion(0.00015 * (double)Value); } else if (IsOnGround()) { m_Stats.AddValue(statDistWalked, Value); AddFoodExhaustion((m_IsSprinting ? 0.001 : 0.0001) * (double)Value); } else { if (Value >= 25) // Ignore small/slow movement { m_Stats.AddValue(statDistFlown, Value); } } } else { switch (m_AttachedTo->GetEntityType()) { case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break; case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break; case cEntity::etMonster: { cMonster * Monster = (cMonster *)m_AttachedTo; switch (Monster->GetMobType()) { case cMonster::mtPig: m_Stats.AddValue(statDistPig, Value); break; case cMonster::mtHorse: m_Stats.AddValue(statDistHorse, Value); break; default: break; } break; } default: break; } } }
void cPlayer::ApplyFoodExhaustionFromMovement() { if (IsGameModeCreative()) { return; } // If we have just teleported, apply no exhaustion if (m_bIsTeleporting) { m_bIsTeleporting = false; return; } // If riding anything, apply no food exhaustion if (m_AttachedTo != NULL) { return; } // Process exhaustion every two ticks as that is how frequently m_LastPos is updated // Otherwise, we apply exhaustion for a 'movement' every tick, one of which is an already processed value if (GetWorld()->GetWorldAge() % 2 != 0) { return; } // Calculate the distance travelled, update the last pos: Vector3d Movement(GetPosition() - m_LastPos); Movement.y = 0; // Only take XZ movement into account // Apply the exhaustion based on distance travelled: double BaseExhaustion = Movement.Length(); if (IsSprinting()) { // 0.1 pt per meter sprinted BaseExhaustion = BaseExhaustion * 0.1; } else if (IsSwimming()) { // 0.015 pt per meter swum BaseExhaustion = BaseExhaustion * 0.015; } else { // 0.01 pt per meter walked / sneaked BaseExhaustion = BaseExhaustion * 0.01; } m_FoodExhaustionLevel += BaseExhaustion; }
void cEnderman::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); // TODO take damage in rain // Take damage when touching water, drowning damage seems to be most appropriate if (IsSwimming()) { EventLosePlayer(); TakeDamage(dtDrowning, nullptr, 1, 0); // TODO teleport to a safe location } }
void cPlayer::ApplyFoodExhaustionFromMovement() { if (IsGameModeCreative()) { return; } // Calculate the distance travelled, update the last pos: Vector3d Movement(GetPosition() - m_LastFoodPos); Movement.y = 0; // Only take XZ movement into account m_LastFoodPos = GetPosition(); // If riding anything, apply no food exhaustion if (m_AttachedTo != NULL) { return; } // Apply the exhaustion based on distance travelled: double BaseExhaustion = Movement.Length(); if (IsSprinting()) { // 0.1 pt per meter sprinted BaseExhaustion = BaseExhaustion * 0.1; } else if (IsSwimming()) { // 0.015 pt per meter swum BaseExhaustion = BaseExhaustion * 0.015; } else { // 0.01 pt per meter walked / sneaked BaseExhaustion = BaseExhaustion * 0.01; } m_FoodExhaustionLevel += BaseExhaustion; }
void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); if (m_Health <= 0) { // The mob is dead, but we're still animating the "puff" they leave when they die m_DestroyTimer += a_Dt / 1000; if (m_DestroyTimer > 1) { Destroy(true); } return; } if ((m_Target != NULL) && m_Target->IsDestroyed()) m_Target = NULL; // Burning in daylight HandleDaylightBurning(a_Chunk); a_Dt /= 1000; if (m_bMovingToDestination) { if (m_bOnGround) { if (DoesPosYRequireJump((int)floor(m_Destination.y))) { m_bOnGround = false; // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport AddPosY(1.2); // Jump!! } } Vector3d Distance = m_Destination - GetPosition(); if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move { Distance.y = 0; Distance.Normalize(); if (m_bOnGround) { Distance *= 2.5f; } else if (IsSwimming()) { Distance *= 1.3f; } else { // Don't let the mob move too much if he's falling. Distance *= 0.25f; } // Apply walk speed: Distance *= m_RelativeWalkSpeed; AddSpeedX(Distance.x); AddSpeedZ(Distance.z); // It's too buggy! /* if (m_EMState == ESCAPING) { // Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); } */ } else { if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate { FinishPathFinding(); } else { TickPathFinding(); // We have reached the next point in our path, calculate another point } } } SetPitchAndYawFromDestination(); HandleFalling(); switch (m_EMState) { case IDLE: { // If enemy passive we ignore checks for player visibility InStateIdle(a_Dt); break; } case CHASING: { // If we do not see a player anymore skip chasing action InStateChasing(a_Dt); break; } case ESCAPING: { InStateEscaping(a_Dt); break; } case ATTACKING: break; } // switch (m_EMState) BroadcastMovementUpdate(); }