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(); } }
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); }
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 }
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()); }
/** * 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; }
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); }
// 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; }
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; } } }
// 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; } } } }