//===========================================================================// // File: Vehicle.cpp //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 09/09/98 JSE Inital base class based off of Shadowrun/Adept // // 09/23/98 BDB State engine update // //---------------------------------------------------------------------------// // Copyright (C) 1998, Fasa Interactive // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "MW4Headers.hpp" #include "Vehicle.hpp" #include "Subsystem.hpp" #include "Engine.hpp" #include "Torso.hpp" #include "VehicleInterface.hpp" #include "Weapon.hpp" #include "MWDamageObject.hpp" #include "bridge.hpp" #include "tank.hpp" #include "MWApplication.hpp" #include "SubsystemClassData.hpp" #include "aiutils.hpp" #include "MWMission.hpp" #include #include #include #include #include #include #include #include #include #include #include "gameinfo.hpp" #include "MWPlayer.hpp" #include #include #include #include "mwguimanager.hpp" #include "hudcomm.hpp" // MSL 5.02 Shadow #include const Stuff::Time sensor_map_update_frequency = 1.0f; #ifdef NEW_SENSOR_TIMING extern __int64 tVehicleTime; #endif void MechWarrior4::VehicleSecurityCheckStart() { _asm { nop } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Stuff::Scalar Vehicle::GetHeightAtPoint( const Stuff::Point3D& point, Adept::Entity* from_who ) { Verify(Adept::Map::GetInstance() != 0); Stuff::Line3D line; line.m_length = 100.0f; line.m_direction = Vector3D::Down; line.m_origin = point; line.m_origin.y += 50.0f; Stuff::Normal3D normal; Entity::CollisionQuery query(&line,&normal,Entity::CanBeWalkedOnFlag,from_who); Check_Object(CollisionGrid::Instance); if (CollisionGrid::Instance->ProjectLine(&query) == Adept::Map::GetInstance()) { Stuff::Point3D hit_spot; line.FindEnd(&hit_spot); return (hit_spot.y); } return -100000.0; } //############################################################################# //################## Vehicle::ExecutionStateEngine ###################### //############################################################################# const StateEngine::StateEntry Vehicle::ExecutionStateEngine::StateEntries[]= { STATE_ENTRY(Vehicle__ExecutionStateEngine, FallingMotion), STATE_ENTRY(Vehicle__ExecutionStateEngine, FlyingMotion), STATE_ENTRY(Vehicle__ExecutionStateEngine, AnimatedMotion), STATE_ENTRY(Vehicle__ExecutionStateEngine, DrivingMotion), STATE_ENTRY(Vehicle__ExecutionStateEngine, Destroyed), STATE_ENTRY(Vehicle__ExecutionStateEngine, AIMotion), STATE_ENTRY(Vehicle__ExecutionStateEngine, Dying), STATE_ENTRY(Vehicle__ExecutionStateEngine, Dropping) }; Vehicle::ExecutionStateEngine::ClassData* Vehicle::ExecutionStateEngine::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ExecutionStateEngine::InitializeClass() { Check_Object(BaseClass::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( Vehicle__ExecutionStateEngineClassID, "Vehicle::ExecutionStateEngine", BaseClass::DefaultData, ELEMENTS(StateEntries), StateEntries, (Entity::ExecutionStateEngine::Factory)Make, (Entity::ExecutionStateEngine::FactoryRequest::Factory) &FactoryRequest::ConstructFactoryRequest ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ExecutionStateEngine::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle::ExecutionStateEngine* Vehicle::ExecutionStateEngine::Make( Vehicle *vehicle, FactoryRequest *request ) { Check_Object(vehicle); Check_Object(request); gos_PushCurrentHeap(Heap); Vehicle::ExecutionStateEngine *engine = new Vehicle::ExecutionStateEngine(DefaultData, vehicle, request); gos_PopCurrentHeap(); return engine; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Vehicle::ExecutionStateEngine::RequestState( int new_state, void* data ) { Check_Object(this); Check_Object(owningEntity); // //------------------------------------------- // If there is no change of state just return //------------------------------------------- // if (new_state == currentState) return currentState; Vehicle *veh; veh = Cast_Object (Vehicle *,owningEntity); if ((currentState == AIMotionState) && veh->m_AI && (!veh->m_AI->TurningOn ())) { return currentState; } // //---------------------------------------------- // Now, switch the state and tickle the watchers //---------------------------------------------- // switch (BaseClass::RequestState(new_state, data)) { case DestroyedState: owningEntity->EnterNeverExecuteState(); break; } return currentState; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ExecutionStateEngine::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //############################################################################# //############################### Vehicle ############################## //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle::ClassData* Vehicle::DefaultData = NULL; DWORD MechWarrior4::Executed_Vehicle_Count = 0; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::InitializeClass() { Check_Object(BaseClass::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( VehicleClassID, "MechWarrior4::Vehicle", BaseClass::DefaultData, 0, NULL, (Entity::Factory)Make, (Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage, ExecutionStateEngine::DefaultData, (Entity::GameModel::Factory)GameModel::ConstructGameModel, (Entity::GameModel::Factory)GameModel::ConstructOBBStream, (Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify, (Entity::GameModel::ModelWrite)GameModel::WriteToText, (Entity::GameModel::ModelSave)GameModel::SaveGameModel, AnimationStateEngine::Make ); Register_Object(DefaultData); INDIRECT_STATE_ATTRIBUTE( Vehicle, ExecutionState, executionState, Vehicle__ExecutionStateEngine ); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, SpeedDemandMPS,speedDemandMPS,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, CurrentSpeedMPS,currentSpeedMPS,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, LocalGroundPitch,localGroundPitch,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, LocalGroundRoll,localGroundRoll,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, RawLocalGroundPitch,rawLocalGroundPitch,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE(Vehicle, RawLocalGroundRoll,rawLocalGroundRoll,Scalar,ScalarClassID); CUSTOM_DIRECT_ATTRIBUTE( Vehicle, VehicleMovingSFX, vehicleMovingSFX, int, IntClassID ); CUSTOM_DIRECT_ATTRIBUTE( Vehicle, VehicleIdleSFX, vehicleIdleSFX, int, IntClassID ); CUSTOM_DIRECT_ATTRIBUTE( Vehicle, VehicleDyingSFX, vehicleDyingSFX, int, IntClassID ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, FullStopTurnRate, fullStopTurnRate, Radian ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, TopSpeedTurnRate, topSpeedTurnRate, Radian ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MaxReverseSpeed, maxReverseSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MinReverseSpeed, minReverseSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MaxSpeed, maxSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MinMaxSpeed, minMaxSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MinSpeed, minSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, Acceleration, acceleration, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, Decceleration, decceleration, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, ReverseAccelerationMultiplier, reverseAccelerationMultiplier, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, ReverseDeccelerationMultiplier, reverseDeccelerationMultiplier, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, TargetLockTime, targetLockTime, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MaxGimpSpeed, maxGimpSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MinStandTransitionSpeed, minStandTransitionSpeed, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, MaxSlope, modelmaxSlope, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, StartSlopeDeceleration, modelstartSlopeDeceleration, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, SlopeDecel1, slopeDecel1, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, SlopeDecel2, slopeDecel2, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, SlopeDecel3, slopeDecel3, Scalar ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, AttackType, m_attackType, int, IntClassID ); DIRECT_GAME_MODEL_ATTRIBUTE( Vehicle__GameModel, TreadLength, m_treadLength, Scalar ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle* Vehicle::Make( CreateMessage *message, ReplicatorID *base_id ) { Check_Object(message); gos_PushCurrentHeap(Heap); Vehicle *new_entity = new Vehicle(DefaultData, message, base_id, NULL); gos_PopCurrentHeap(); Check_Object(new_entity); Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->AddMover(new_entity); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle::Vehicle( ClassData *class_data, CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): MWObject(class_data, message, base_id, element), currentTrailEffect(NULL), m_SensorCellMapX(-1), m_SensorCellMapZ(-1), m_LastSensorCellPositionUpdate(0), m_SecondaryExplosion (NULL) { Check_Pointer(this); Check_Object(message); MW4AI::UserConstants::IncrementRefCount(); CommonCreation(message); engine = NULL; vehicleInterface = NULL; shadow = NULL; // MSL 5.02 Shadow shadowIntensity = 0.0f; respawnCount = 0; m_doesHaveLightAmp = false; teamNumber = MWApplication::No_Team; m_groundRaycastHeight = 20.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle::~Vehicle() { DESTRUCTOR("Vehicle"); Check_Object(this); if (shadow) { Check_Object(shadow); delete shadow; shadow = NULL; // MSL 5.02 Shadow shadowIntensity = 0.0f; } Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->RemoveMover(this); MW4AI::UserConstants::DecrementRefCount(); RemoveFromSensorCellMap(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::Reuse( const CreateMessage *message, ReplicatorID *base_id ) { Check_Object(this); Check_Object(message); STOP(("Not implemented")); BaseClass::Reuse(message, base_id); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::TurnOff (void) { m_LastState = executionState->GetState (); executionState->RequestState(ExecutionStateEngine::AIMotionState); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::TurnOn (void) { lastParameterization = gos_GetElapsedTime (); // executionState->RequestState(ExecutionStateEngine::AnimatedMotionState); if (executionState->GetState () == ExecutionStateEngine::AIMotionState) executionState->RequestState(m_LastState); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::CommonCreation(CreateMessage *message) { Check_Object(this); Check_Object(message); m_DeathDamageMode = m_DeathDamageType = -1; m_LastState = ExecutionStateEngine::DrivingMotionState; Verify (MW4AI::UserConstants::Instance ()); Stuff::Scalar upslope; const GameModel *model = GetGameModel(); Check_Object(model); switch (model->moveTypeFlag) { case MechWarrior4::MWObject__GameModel::LEG_MOVETYPE: case MechWarrior4::MWObject__GameModel::LEGJUMP_MOVETYPE: upslope = Arccos (MW4AI::UserConstants::Instance ()->Get (MW4AI::UserConstants::leg_up_slope)); break; case MechWarrior4::MWObject__GameModel::TRACK_MOVETYPE: upslope = Arccos (MW4AI::UserConstants::Instance ()->Get (MW4AI::UserConstants::track_up_slope)); break; case MechWarrior4::MWObject__GameModel::WHEEL_MOVETYPE: upslope = Arccos (MW4AI::UserConstants::Instance ()->Get (MW4AI::UserConstants::wheel_up_slope)); break; case MechWarrior4::MWObject__GameModel::HOVER_MOVETYPE: upslope = Arccos (MW4AI::UserConstants::Instance ()->Get (MW4AI::UserConstants::hover_up_slope)); break; default: upslope = Pi_Over_2; break; } // if (model->startSlopeDeceleration < upslope) { startSlopeDeceleration = upslope; maxSlope = startSlopeDeceleration + (15.0f * Radians_Per_Degree); } #ifdef LAB_ONLY m_DebugFast = false; #endif speedDemand = 0.0f; yawDemand = 0.0f; pitchDemand = 0.0f; rollDemand = 0.0f; speedDemandMPS = 0.0f; currentSpeedMPS = 0.0f; currentSpeedKPH = 0.0; speedDemandKPH = 0.0; m_needSelfDestruct = 0; dirRequest = Point3D (0,0,0); followDirRequest = false; followDirRequestReverse = false; internalViewPoint = false; usingEyeSpring = false; localGroundRoll = 0.0f; localGroundPitch = 0.0f; rawLocalGroundPitch = localGroundPitch; rawLocalGroundRoll = localGroundRoll; materialHit = -1; currentTrailID = ResourceID::Null; currentTrailEffect.Remove(); vehicleRunsInterface = true; correctingPosition = false; correctingRotation = false; correctionPosition = Point3D::Identity; correctionAngle = YawPitchRoll::Identity; rotationCorrectionTime = 0.0f; positionCorrectionTime = 0.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::Respawn(Entity::CreateMessage *message) { Check_Object(this); Check_Object(message); BaseClass::Respawn(message); CreateMessage *vehicle_message = Cast_Pointer(CreateMessage *, message); CommonCreation(vehicle_message); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Vehicle::GetExecutionSlot() { Check_Object(this); return VehicleExecutionSlot; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::PreCollisionExecute(Time till) { Check_Object(this); PRECOLLISION_LOGIC("Vehicle"); #if defined(LAB_ONLY) if (!instanceName) MWGameInfo::g_LastVehicle[0] = '\0'; else { strncpy(MWGameInfo::g_LastVehicle, instanceName, sizeof(MWGameInfo::g_LastVehicle)-1); MWGameInfo::g_LastVehicle[sizeof(MWGameInfo::g_LastVehicle)-1] = '\0'; } MWGameInfo::g_LastVehiclePos = GetLocalToWorld (); #endif // //---------------------------------------- // Run our interface if we are supposed to //---------------------------------------- // Set_Statistic(Executed_Vehicle_Count, Executed_Vehicle_Count+1); if (vehicleRunsInterface && vehicleInterface != NULL) { Check_Object(vehicleInterface); vehicleInterface->PreCollisionExecute(till); Verify(!vehicleInterface->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(vehicleInterface)); } UpdateSensorCellMapPosition(); // //------------------------------------------------------------- // Let the base class deal with setting up the motion variables //------------------------------------------------------------- // BaseClass::PreCollisionExecute(till); // //---------------------------------------------------------------------- // Any executing vehicle should not be in never execute state and should // always use post collision //---------------------------------------------------------------------- // Check_Object(executionState); int pre_state = executionState->GetState(); Verify(pre_state != ExecutionStateEngine::NeverExecuteState); // //------------------------------------------------------------------------- // Do the appropriate type of simulation. Animated motion state is for BRB //------------------------------------------------------------------------- // FindGroundAngle (); Verify(GetTimeSlice(till) < 1.0f); Scalar time_slice = GetTimeSlice(till); switch (pre_state) { case ExecutionStateEngine::AnimatedMotionState: switch (animStateEngine->GetState()) { case AnimationStateEngine::Test1State: case AnimationStateEngine::Test2State: case AnimationStateEngine::Test3State: case AnimationStateEngine::Test4State: break; default: animStateEngine->RequestState(AnimationStateEngine::Test1State); break; } if (animationArrayCount > 0) { animStateEngine->RunStates(time_slice); } StraightLineMotionSimulation(till); break; // //----------------------------------------------- // Flying or driving state needs to apply gravity //----------------------------------------------- // case ExecutionStateEngine::DrivingMotionState: case ExecutionStateEngine::DyingState: case ExecutionStateEngine::FlyingMotionState: { UnitVector3D world_down_in_local; GetLocalToWorld().GetWorldDownInLocal(&world_down_in_local); localSpaceAcceleration.linearMotion.AddScaled( localSpaceAcceleration.linearMotion, world_down_in_local, g_Gravity ); } break; // //------------------------------------ // This state is not used for vehicles //------------------------------------ // case ExecutionStateEngine::AlwaysExecuteState: STOP(("AlwaysExecuteState is not a valid state for vehicle")); break; case ExecutionStateEngine::AIMotionState: { PRECOLLISION_LOGIC("Vehicle::Boardgame"); } break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #if defined(LAB_ONLY) void Vehicle::SyncMatrices(bool update_matrix) { SYNC_LOGIC("Vehicle"); BaseClass::SyncMatrices(update_matrix); } #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Vehicle::CollisionHandler( Stuff::LinearMatrix4D *new_position, Stuff::DynamicArrayOf *collisions ) { Check_Object(this); Check_Object(collisions); Verify(GetInterestLevel() != DormantInterestLevel); bool shoulddamage=true; // //---------------------------------------------------------- // If we are destroyed, delete the collision list and return //---------------------------------------------------------- // if (IsDestroyed()) { delete collisions; Verify(!newCollisions); return false; } // //-------------------------------- // Ask the AI about the collision //-------------------------------- // if (m_AI) { if (!m_AI->ReactToCollision(collisions,shoulddamage)) // ai will return false if collision should not occur { Verify(!newCollisions); delete collisions; return false; } } // //---------------------------------------- // Turn off collision if we are going fast //---------------------------------------- // #ifdef LAB_ONLY if (m_DebugFast) { Verify(!newCollisions); delete collisions; return false; } #endif // //----------------------- // Iterate the collisions //----------------------- // for (int i=0; iGetLength(); ++i) { CollisionData *data = &(*collisions)[i]; Check_Pointer(data); // //--------------------------------------------------------------------- // Look to see if we have run into a collider, and if so, calculate the // relative velocity //--------------------------------------------------------------------- // Entity *other = data->m_otherEntity; if (other->IsACollider()) { Adept::Mover *adeptmover = Cast_Object(Adept::Mover*, other); Vector3D rel_vel; rel_vel.Subtract(adeptmover->worldSpaceVelocity.linearMotion, worldSpaceVelocity.linearMotion); Scalar speed = rel_vel.GetLengthSquared(); MWObject *mover = Cast_Object(MWObject*, other); // //------------------------------- // If its a mech, get its ratings //------------------------------- // if (other->GetClassID() == MechClassID) { Mech *mech = Cast_Object(Mech*, mover); int mech_class; Scalar damage_received; Scalar mech_speed; if (mech->GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_tonage)) { damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_damage); mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_heavy_building_speed); mech_class = HeavyCanWalkThruType; } else if (mech->GetTonage() >= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_tonage)) { damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_damage); mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_medium_building_speed); mech_class = MediumCanWalkThruType; } else { damage_received = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_damage); mech_speed = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_mech_light_building_speed); mech_class = AnythingCanWalkThruType; } // //---------------------- // See if it squishes us //---------------------- // if (GetWalkThruType() >= mech_class) { if (shoulddamage) { TakeDamageMessage damage_message( GetReplicatorID(), other->GetReplicatorID(), 100000.0f, // MSL 5.05 Advance Mode 0, // Modifier RammingDamageFromAboveType, data->m_normal, data->m_worldIntersectionPoint, 0.0f, false, TakeDamageMessage::DefaultWeaponType ); Receive(&damage_message); } } // //----------------------------------------------- // See if we are going fast enough to get damaged //----------------------------------------------- // else if (speed >= mech_speed) { speed = Sqrt(speed)*mover->GetTonage(); // //------------------------ // Evaluate the DFA states //------------------------ // Scalar min_dfa_vel = MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_speed); Entity::ExecutionStateEngine *engine = mech->executionState; bool their_dfa = mech->worldSpaceVelocity.linearMotion.y <= -min_dfa_vel && engine->GetState() == ExecutionStateEngine::FlyingMotionState; // //--------------------------------------- // Use the appropriate collision modifier //--------------------------------------- // char damage_type; if (their_dfa) { damage_type = RammingDamageFromAboveType; speed *= MW4AI::UserConstants::m_Instance->Get(MW4AI::UserConstants::collision_dfa_damage_given); } else { damage_type = RammingDamageFromAheadType; speed *= damage_received; } // //---------------------------------- // Set the damage message to ourself //---------------------------------- // if (shoulddamage) { // MSL 5.06 Armor Mode MWApplication *m_App; m_App = MWApplication::GetInstance (); m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn; TakeDamageMessage damage_message( GetReplicatorID(), other->GetReplicatorID(), speed, m_ArmorMode, damage_type, data->m_normal, data->m_worldIntersectionPoint, 0.0f, false, TakeDamageMessage::DefaultWeaponType ); Receive(&damage_message); } } } } // //-------------------------------------------------------------- // If we've run into a static object, see if we can just kill it //-------------------------------------------------------------- // else if (GetWalkThruType() <= other->GetWalkThruType()) { // if (shoulddamage) { TakeDamageMessage damage_message( other->GetReplicatorID(), GetReplicatorID(), 100000.0f, // MSL 5.05 Advance Mode 0, RammingDamageFromAboveType, data->m_otherNormal, data->m_worldIntersectionPoint, 0.0f, false, TakeDamageMessage::DefaultWeaponType ); other->Receive(&damage_message); } } } // //----------------- // Stop the vehicle //----------------- // Entity::ExecutionStateEngine *engine = executionState; if (engine->GetState() == ExecutionStateEngine::NeverExecuteState || !IsUsingPostCollision()) { delete collisions; Verify(!newCollisions); return false; } Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this)); newCollisions = collisions; currentSpeedMPS = 0.0f; currentSpeedKPH = currentSpeedMPS * 3.6f; *new_position = GetLocalToParent(); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::PostCollisionExecute(Time till) { Check_Object(this); Check_Object(executionState); POSTCOLLISION_LOGIC("Vehicle"); // //------------------------------------------------------------------------ // If we are trying to go to a particular spot, figure out where that is // relative to us, negating the values if we are trying to back up to that // spot //------------------------------------------------------------------------ // if (followDirRequest) { Point3D distance_to_target; Point3D loc (GetLocalToWorld ()); LinearMatrix4D tempmat (GetLocalToWorld ()); tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis); distance_to_target.MultiplyByInverse(dirRequest, tempmat); if (followDirRequestReverse) { distance_to_target.x = -distance_to_target.x; distance_to_target.z = -distance_to_target.z; } // //------------------------------------------------------------------- // If we are still some distance from the target spot, figure out yaw // to the target angle //------------------------------------------------------------------- // yawDemand = 0.0f; if (!Small_Enough(distance_to_target.z)) { Scalar heading_adjustment = Arctan(distance_to_target.x, distance_to_target.z); // //-------------------------------------------------------------- // Only turn if we are off by more than a degree. If so, figure // out how long we need to turn at full speed to point at the // target //-------------------------------------------------------------- // Scalar turn_amount = Abs(heading_adjustment); if (turn_amount > Radians_Per_Degree) { const GameModel *model = GetGameModel(); Scalar time_slice = GetTimeSlice(till); Scalar turn_step = heading_adjustment * time_slice; Scalar max_step = Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, currentSpeedMPS/GetMaxSpeed()); // Scalar max_step = model->fullStopTurnRate * time_slice; max_step *= time_slice; Verify(max_step >= SMALL); // //------------------------------------------------------------- // If we need to turn more than we can arrange this time slice, // turn at full rate //------------------------------------------------------------- // yawDemand = turn_step/max_step; Clamp(yawDemand, -1.0f, 1.0f); } } #if 0 if (!strnicmp("ambush2", instanceName, 7)) { SPEWALWAYS(("afarrier", (char*)instanceName)); SPEWALWAYS(("afarrier", " local position = %f,%f,%f", loc.x, loc.y, loc.z)); SPEWALWAYS(("afarrier", " world target = %f,%f,%f", dirRequest.x, dirRequest.y, dirRequest.z)); SPEWALWAYS(("afarrier", " local target = %f,%f,%f", distance_to_target.x, distance_to_target.y, distance_to_target.z)); SPEWALWAYS(("afarrier", " yaw = %f", yawDemand)); } #endif } // //------------------------------------------ // Reset the parameterization for next frame //------------------------------------------ // lastParameterization = till; initialLocalToParent = GetLocalToParent(); // //--------------------------------------------------------------------- // We need to execute watchers for our children if they are part of us, // then we create another trail object //--------------------------------------------------------------------- // CreateTrail(); // if(m_needSelfDestruct) // ProcessSelfDestruct(); // //------------------------------------------------ // If we have a shadow, first get its current data //------------------------------------------------ // if (shadow && TiledLightManager::s_ShadowMode != TiledLightManager::e_NoShadows && Mission::GetInstance()->GetMainLight()) { POSTCOLLISION_LOGIC("Vehicle::Cast Shadow"); Check_Object(shadow); gosFX::LightManager::Info info; shadow->GetInfo(&info); // //----------------------------------------------------------------- // Get the orientation of our main light and set our shadow to that //----------------------------------------------------------------- // gosFX::LightManager::Info main_info; gosFX::Light *main_light = Mission::GetInstance()->GetMainLight(); Check_Object(main_light); main_light->GetInfo(&main_info); info.m_origin = main_info.m_origin; // //---------------------------------------------------------- // Cast a ray from our center of collision toward the ground //---------------------------------------------------------- // Stuff::Line3D line; line.m_length = 500.0f; info.m_origin.GetLocalForwardInWorld(&line.m_direction); CollisionVolume *cv = GetSolidVolume(); if (cv) { Check_Object(cv); LinearMatrix4D new_bounds; new_bounds.Multiply(cv->m_localSpaceBounds.localToParent, GetLocalToWorld()); line.m_origin = new_bounds; Stuff::Normal3D normal; CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this); Check_Object(CollisionGrid::Instance); CollisionGrid::Instance->ProjectLine(&query); // //-------------------------------------------------------------------- // Set our shadow position to the end of the line, and compute the new // radius of the light (it will be inner radius / cos(light angle). // We will automatically set the radius to the height of the center // of the collision volume over the vehicles origin //-------------------------------------------------------------------- // Point3D end; line.FindEnd(&end); info.m_origin.BuildTranslation(end); Stuff::Point3D vehicle_translation(GetLocalToWorld()); info.m_inner = line.m_origin.y - vehicle_translation.y; if(Small_Enough(line.m_direction.y)) { info.m_outer=info.m_inner+10.0f; } else { info.m_outer = info.m_inner / -line.m_direction.y; } // MSL 5.02 Shadow // // Needed a way to clip out a shadow when it is out of range. // Out of range is when it is past the fogend setting of the current mission. // // // if (distance to object is > max fog distance then we turn off the lightmap for the shadow, otherwise we turn it on) // // // First get the distance from the vehicle to the camera // if (Adept::Player::GetInstance()->playerInterface) { MWMission * mission = Cast_Object(MWMission*, MWMission::GetInstance()); VehicleInterface * vi = Cast_Object(VehicleInterface*, Adept::Player::GetInstance()->playerInterface); if (vi->m_reticuleCamera && mission) { Stuff::Point3D camera_local_to_world; Stuff::Point3D vehicle_local_to_world; camera_local_to_world = vi->m_reticuleCamera->GetLocalToWorld(); vehicle_local_to_world = this->GetLocalToWorld(); Stuff::Point3D vehicleDistance; vehicleDistance.Subtract(camera_local_to_world, vehicle_local_to_world); Stuff::Scalar vehicle_height = vehicle_local_to_world.y; Stuff::Scalar distanceSquared = vehicleDistance.GetLengthSquared(); Stuff::Scalar fog_start_squared; Stuff::Scalar fog_end_squared; Stuff::Scalar fog_end_height; Stuff::Scalar fog_distance; Stuff::Scalar fog_height; // // Then get the fog distance fog_start_squared = mission->m_generalFogStart * mission->m_generalFogStart; fog_end_squared = mission->m_generalFogEnd * mission->m_generalFogEnd; fog_end_height = mission->m_heightFogEnd; // // Then compare // MidLevelRenderer::MLRShadowLight * mlrshadowlight = shadow->GetMLRLight(); info.m_intensity = shadowIntensity; // default fog_distance = shadowIntensity * ((fog_end_squared - distanceSquared)/(fog_end_squared - fog_start_squared)); fog_height = shadowIntensity * (vehicle_height/fog_end_height); if (mlrshadowlight) { if ((fog_end_squared > distanceSquared) || (vehicle_height < fog_end_height)) { if (fog_end_squared > distanceSquared) { shadow->GetMLRLight()->ShowShadow(true); // // Set the intensity here so it pops less. // if (!Small_Enough(fog_end_squared - fog_start_squared)) { Min_Clamp(distanceSquared, fog_start_squared); fog_distance = shadowIntensity * ((fog_end_squared - distanceSquared)/(fog_end_squared - fog_start_squared)); } } if (fog_distance < fog_height) info.m_intensity = fog_distance; else info.m_intensity = fog_height; } else { shadow->GetMLRLight()->ShowShadow(false); } } } } shadow->ChangeLight(&info); } } // //--------------------------------- // Let the parent handle things now //--------------------------------- // BaseClass::PostCollisionExecute(till); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ComputeForwardSpeed(Stuff::Scalar time_slice) { Check_Object(this); const GameModel *model = GetGameModel(); Check_Object(model); Stuff::Scalar maxSpeedMod; bool wallslope=false; // //---------------------------------------------------- // Set the demands to zero if the vehicle is shut down //---------------------------------------------------- // if (vehicleShutDown) { speedDemand = 0.0f; speedDemandKPH = 0.0f; } Verify (model->moveTypeFlag != MWObject__GameModel::WATER_MOVETYPE); // these should be boats maxSpeedMod = 1.0f; switch (materialHit) { case WaterMaterial: // PAUSE (("vehicle walked on water or swamp material")); case ConcreteMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::WHEEL_MOVETYPE: maxSpeedMod = 1.25f; break; } break; case SnowMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::TRACK_MOVETYPE: maxSpeedMod = 0.5f; break; case MWObject__GameModel::WHEEL_MOVETYPE: maxSpeedMod = 0.25f; break; } break; case FakeShallowWaterMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::WHEEL_MOVETYPE: maxSpeedMod = 0.0f; break; case MWObject__GameModel::TRACK_MOVETYPE: maxSpeedMod = 0.0f; break; } break; case FakeMidWaterMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::WHEEL_MOVETYPE: case MWObject__GameModel::TRACK_MOVETYPE: maxSpeedMod = 0.0f; break; } break; case FakeOceanicWaterMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::WHEEL_MOVETYPE: case MWObject__GameModel::TRACK_MOVETYPE: maxSpeedMod = 0.0f; break; } break; // MSL 5.03 Lava case CrackedLavaMaterial: case OpenLavaMaterial: switch (model->moveTypeFlag) { case MWObject__GameModel::WHEEL_MOVETYPE: case MWObject__GameModel::TRACK_MOVETYPE: //collide against the lava maxSpeedMod = 0.0f; break; } break; } if (maxSpeedMod == 0.0f) // tell the ai we had a collision based on material type { if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData))) { MoverAI *ai = Cast_Object(MoverAI*, m_AI); ai->SlopeCollide(); } } // //------------------------------------------------------------------------ // Figure out our desired speed. If we are stopped, set the KPH variables // to zero and quit //------------------------------------------------------------------------ // if (speedDemand >= 0.0f) speedDemandMPS = (speedDemand * GetMaxSpeed()*maxSpeedMod); else speedDemandMPS = -(speedDemand * model->maxReverseSpeed*maxSpeedMod); if (speedDemandMPS == 0.0f && currentSpeedMPS == 0.0f) { speedDemandKPH = 0.0f; currentSpeedKPH = 0.0f; SetIdle (); return; } // //---------------------------------------------------------------------- // Figure out the grade we are on. If it is less than 45 degrees, we // can do regular motion on it. // // NOTE: This approach is a big steamy pile of doo-doo. I will kill it! //---------------------------------------------------------------------- // Scalar grade; Scalar cosang; UnitVector3D forward; GetLocalToWorld().GetLocalForwardInWorld(&forward); cosang = (forward.x*m_WorldAvgNormal.x)+(forward.y*m_WorldAvgNormal.y)+(forward.z*m_WorldAvgNormal.z); // if (m_LocalNormal.z < 0) if (cosang < 0) // going up the slope, { grade = Abs (m_RawGroundPitch); m_RawGroundPitch = m_RawGroundPitch < 0 ? m_RawGroundPitch * -1.0f : m_RawGroundPitch; } else { grade = 0; m_RawGroundPitch = m_RawGroundPitch > 0 ? m_RawGroundPitch * -1.0f : m_RawGroundPitch; } Scalar decceleration = model->decceleration; // bool ai_grade_collide = false; if (grade <= startSlopeDeceleration) { Scalar clamped_pitch = m_RawGroundPitch; Scalar clamped_roll = rawLocalGroundRoll; // //---------------------------------------------------- // The maximum slope we will request is +/- 44 degrees //---------------------------------------------------- // Scalar max_value = startSlopeDeceleration - Radians_Per_Degree; Clamp(clamped_pitch, -max_value, max_value); Clamp(clamped_roll, -max_value, max_value); // //---------------------------------------------------------------------- // If we are currently driving forward, and we are not heading downhill, // figure out how much to reduce our speed demand by //---------------------------------------------------------------------- // if (currentSpeedMPS > 0.0f) { if (clamped_pitch >= 0.0f) { Stuff::Scalar speed_effect = 0.4f * clamped_pitch / startSlopeDeceleration; speedDemandMPS -= speedDemandMPS * speed_effect; } // //------------------------------------------------------ // Otherwise, if we are driving downhill, speed up a bit //------------------------------------------------------ // else { Stuff::Scalar speed_effect = -0.3f * clamped_pitch / startSlopeDeceleration; speedDemandMPS += speedDemandMPS * speed_effect; } } } // //------------------------------------------------------------------------ // We need to deal if an extreme case, so see if we are running up a cliff // face. If we are, we are going to want to stop //------------------------------------------------------------------------ // else if (m_RawGroundPitch > 0.0f) { speedDemandMPS = 0.0f; // //------------------------------------------------------------------ // If the grade is higher than we can tolerate, this is treated as a // collision - tell the AI //------------------------------------------------------------------ // if (grade >= maxSlope) { // SetCollide(); decceleration = model->slopeDecel3; #if 0 if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData))) { MoverAI *ai = Cast_Object(MoverAI*, m_AI); ai->SlopeCollide(); } #endif wallslope = true; } // //-------------------------------------------------------------------------- // We can tolerate the slope, but will slow down, so pick which deceleration // band to use //-------------------------------------------------------------------------- // else { #if 0 ai_grade_collide = m_AI && m_AI->IsDerivedFrom(MoverAI::DefaultData); if ((m_AI) && (m_AI->IsDerivedFrom (MoverAI::DefaultData))) { MoverAI *ai = Cast_Object(MoverAI*, m_AI); ai->SlopeCollide(); } #endif Verify(startSlopeDeceleration <= (Pi_Over_4+Pi_Over_8)); Scalar band_size = (maxSlope - startSlopeDeceleration)/3.0f; Scalar grade_band_one = startSlopeDeceleration + band_size; if (grade < grade_band_one) decceleration = model->slopeDecel1; else { Scalar grade_band_two = grade_band_one + band_size; decceleration = (grade < grade_band_two) ? model->slopeDecel2 : model->slopeDecel3; } } } // //-------------------------------------------- // Anything can go down - ain't gravity great? //-------------------------------------------- // else { Stuff::Scalar adjust_pitch = -m_RawGroundPitch; Max_Clamp(adjust_pitch, Pi_Over_4); Stuff::Scalar speed_effect = 0.3f * adjust_pitch / Pi_Over_4; speedDemandMPS += speedDemandMPS * speed_effect; } // //-------------------------------------------------------------------- // If we are not going backwards, find out what speed we want after we // consider braking //-------------------------------------------------------------------- // if (currentSpeedMPS >= 0.0f) { Stuff::Scalar decel_speed = currentSpeedMPS - (model->decceleration * time_slice); if (!wallslope) { Min_Clamp (decel_speed,20); } // //-------------------------------------------------------------------- // If we end up wanting to go backwards and this is a collision to the // AI, tell the AI we collided //-------------------------------------------------------------------- // #if 0 if (decel_speed <= 0.0f && ai_grade_collide) { if (m_AI) { MoverAI *ai = Cast_Object(MoverAI*, m_AI); ai->SlopeCollide(); } } #endif // //-------------------------------------- // Otherwise, adjust our speed as needed //-------------------------------------- // if (speedDemandMPS > currentSpeedMPS) { currentSpeedMPS += (model->acceleration * time_slice); Max_Clamp(currentSpeedMPS, speedDemandMPS); } else if (speedDemandMPS < currentSpeedMPS) { currentSpeedMPS -= (model->decceleration * time_slice); Min_Clamp(currentSpeedMPS, speedDemandMPS); } } // //-------------------------------------------------------------- // We are backing up, so tell the AI if we had a grade collision //-------------------------------------------------------------- // else { Stuff::Scalar decel_spped = currentSpeedMPS + (model->reverseDeccelerationMultiplier * time_slice); if (!wallslope) { Max_Clamp (decel_spped,-20); } #if 0 if ((decel_spped >= 0) && (ai_grade_collide)) { if (m_AI) { MoverAI *ai = Cast_Object(MoverAI *,m_AI); ai->SlopeCollide(); } } #endif // //------------------------------------------------------------- // Deal with the stand transition if that is the case we are in //------------------------------------------------------------- // // //------------------------------------- // Otherwise adjust our speed as needed //------------------------------------- // if (speedDemandMPS < currentSpeedMPS) { currentSpeedMPS -= (model->acceleration * model->reverseAccelerationMultiplier * time_slice); Min_Clamp(currentSpeedMPS, speedDemandMPS); } else if (speedDemandMPS > currentSpeedMPS) { currentSpeedMPS += (model->decceleration * model->reverseDeccelerationMultiplier * time_slice); Max_Clamp(currentSpeedMPS, speedDemandMPS); } } // //---------------------------------------------------- // Now adjust all this to the limits in the model file //---------------------------------------------------- // Clamp(currentSpeedMPS, model->maxReverseSpeed*maxSpeedMod, GetMaxSpeed()*maxSpeedMod); // //--------------------------- // Set up the velocity vector //--------------------------- // localSpaceVelocity.linearMotion.z = currentSpeedMPS; // //---------------------- // Set the KPH variables //---------------------- // currentSpeedKPH = currentSpeedMPS * 3.6f; speedDemandKPH = speedDemandMPS * 3.6f; if (currentSpeedKPH == 0) SetIdle (); else SetMoving (); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // called when the unit is dieing and needs to slow to a stop void Vehicle::ComputeFrictionSpeed(Stuff::Scalar time_slice) { Check_Object(this); Stuff::Scalar friction; speedDemand = 0.0f; speedDemandKPH = 0.0f; yawDemand = 0; speedDemandMPS = 0; if (speedDemandMPS == 0.0f && currentSpeedMPS == 0.0f) { speedDemandKPH = 0.0f; currentSpeedKPH = 0.0f; return; } #ifdef _ARMOR const GameModel *model = GetGameModel(); Check_Object(model); Verify (model->moveTypeFlag != MWObject__GameModel::WATER_MOVETYPE); // these should be boats #endif friction = 10.0f; switch (materialHit) { case WaterMaterial: case ConcreteMaterial: friction = 8.0f; break; case SnowMaterial: friction = 5.0f; break; case FakeShallowWaterMaterial: friction = 50.0f; break; case FakeMidWaterMaterial: friction = 1000.0f; // stop it now break; case FakeOceanicWaterMaterial: friction = 1000.0f; // stop it now break; } // //---------------------------------------------------------------------- // Figure out the grade we are on. If it is less than 45 degrees, we // can do regular motion on it. // // NOTE: This approach is a big steamy pile of doo-doo. I will kill it! //---------------------------------------------------------------------- // Scalar grade; Scalar cosang; UnitVector3D forward; GetLocalToWorld().GetLocalForwardInWorld(&forward); cosang = (forward.x*m_WorldAvgNormal.x)+(forward.y*m_WorldAvgNormal.y)+(forward.z*m_WorldAvgNormal.z); if (cosang < 0) // going up the slope, { grade = Abs (m_RawGroundPitch); friction += 2.0f * (((float) sin (grade)) * g_Gravity); } else { grade = Abs (m_RawGroundPitch); friction -= 2.0f * (((float) sin (grade)) * g_Gravity); } Clamp (friction,0.5f,1000.0f); if (currentSpeedMPS < 0) { currentSpeedMPS += friction * time_slice; Max_Clamp (currentSpeedMPS,0); } else { currentSpeedMPS -= friction * time_slice; Min_Clamp (currentSpeedMPS,0); } localSpaceVelocity.linearMotion.z = currentSpeedMPS; // //---------------------- // Set the KPH variables //---------------------- // currentSpeedKPH = currentSpeedMPS * 3.6f; speedDemandKPH = speedDemandMPS * 3.6f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::FindGroundAngle(void) { Check_Object(this); PRECOLLISION_LOGIC("Vehicle::FindGroundAngle"); // //--------------------------------------------------- // Look for the centerpoint of where our feet are now //--------------------------------------------------- // const LinearMatrix4D& local_to_world = GetLocalToWorld(); Stuff::Line3D line; line.m_length = 2000.0f; line.m_direction = Vector3D::Down; line.m_origin = local_to_world; line.m_origin.y += 1000.0f; Stuff::Normal3D normal; CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this); Check_Object(CollisionGrid::Instance); Entity *entity_hit = CollisionGrid::Instance->ProjectLine(&query); if (!entity_hit) STOP(("Vehicle is off edge")); materialHit = query.m_material; // //---------------------------------------------------------------- // Figure out the slope of the ground under the center of the vehicle //---------------------------------------------------------------- // Stuff::Vector3D world_avg_normal(*query.m_normal); m_WorldAvgNormal = world_avg_normal; m_RawGroundPitch = Arccos (world_avg_normal.y); LinearMatrix4D tempmat (GetLocalToWorld ()); tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis); m_LocalNormal.MultiplyByInverse(world_avg_normal, tempmat); rawLocalGroundRoll = -Arctan(m_LocalNormal.x, m_LocalNormal.y); rawLocalGroundPitch = -Arctan(m_LocalNormal.z, m_LocalNormal.y); // //-------------------------------------------------------------- // take our normal sum and figure out the local pitch/roll angle //-------------------------------------------------------------- // localGroundRoll = rawLocalGroundRoll; localGroundPitch = rawLocalGroundPitch; Point3D tr; line.FindEnd(&tr); Check_Object (Map::GetInstance()); Check_Object (Map::GetInstance()->GetGameModel ()); m_WaterDelta = Map::GetInstance()->GetGameModel ()->m_waterLevel - tr.y; if ((m_WaterDelta >= ShallowWaterDepth) && (m_WaterDelta < MidWaterDepth)) { materialHit = FakeShallowWaterMaterial; } else if ((m_WaterDelta >= MidWaterDepth) && (m_WaterDelta < DeepWaterDepth)) { materialHit = FakeMidWaterMaterial; } else if (m_WaterDelta >= DeepWaterDepth) { materialHit = FakeOceanicWaterMaterial; } Min_Clamp (m_WaterDelta,0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::FindGroundAngleUnitDiamond(void) { Check_Object(this); // //---------------------------------------------------- // Figure out where the four points of the diamond are //---------------------------------------------------- // const Stuff::LinearMatrix4D &local_to_world = GetLocalToWorld(); Check_Object(&local_to_world); // //------------------------------------------ // Set up our variables and the query object //------------------------------------------ // Stuff::Point3D local_point; local_point = local_to_world; Stuff::Vector3D world_avg_normal; Stuff::Normal3D normal; Stuff::Line3D line; CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this); // //--------------------------------------------------------------------------- // Test the forward ray. If we don't hit anything, assume the ground is flat //--------------------------------------------------------------------------- // line.m_length = 20.0f; line.m_direction = Vector3D::Down; line.m_origin.Multiply(Stuff::Point3D(0.0f, 0.0f, 1.5f), local_to_world); line.m_origin.y += 5.0f; Check_Object(CollisionGrid::Instance); Stuff::Point3D collide_point; if (CollisionGrid::Instance->ProjectLine(&query)) world_avg_normal = *query.m_normal; else { localGroundPitch = 0; localGroundRoll = 0; return; } // //--------------------- // Test the reverse ray //--------------------- // line.m_length = 20.0f; line.m_origin.Multiply(Stuff::Point3D(0.0f, 0.0f, -1.5f), local_to_world); line.m_origin.y += 5.0f; if (CollisionGrid::Instance->ProjectLine(&query)) world_avg_normal += *query.m_normal; else { localGroundPitch = 0; localGroundRoll = 0; return; } // //------------------ // Test the left ray //------------------ // line.m_length = 20.0f; line.m_origin.Multiply(Stuff::Point3D(1.0f, 0.0f, 0.0f), local_to_world); line.m_origin.y += 5.0f; if (CollisionGrid::Instance->ProjectLine(&query)) world_avg_normal += *query.m_normal; else { localGroundPitch = 0; localGroundRoll = 0; return; } // //------------------- // Test the right ray //------------------- // line.m_length = 20.0f; line.m_origin.Multiply(Stuff::Point3D(-1.0f, 0.0f, 0.0f), local_to_world); line.m_origin.y += 5.0f; if (CollisionGrid::Instance->ProjectLine(&query)) world_avg_normal += *query.m_normal; else { localGroundPitch = 0; localGroundRoll = 0; return; } // //--------------------------------------------------------------------- // put the summed normal into local space, then figure out the relative // roll and pitch angles //--------------------------------------------------------------------- // Stuff::Vector3D local_normal; local_normal.MultiplyByInverse(world_avg_normal, local_to_world); localGroundRoll = Arctan(local_normal.x, local_normal.y); localGroundPitch = Arctan(local_normal.z, local_normal.y); rawLocalGroundPitch = localGroundPitch; rawLocalGroundRoll = localGroundRoll; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::UpdateVehiclePosition(Scalar time_slice) { Check_Object(this); // //--------------------------------------------------------------------- // Apply velocity/acceleration to position and acceleration to velocity //--------------------------------------------------------------------- // PRECOLLISION_LOGIC("Vehicle::UpdateVehiclePosition"); const LinearMatrix4D &vehicle_to_world = GetLocalToWorld(); Point3D world_translation(vehicle_to_world); Vector3D delta; delta.AddScaled( localSpaceVelocity.linearMotion, localSpaceAcceleration.linearMotion, 0.5f * time_slice ); Vector3D world_delta; world_delta.Multiply(delta, vehicle_to_world); Max_Clamp(world_delta.y, 0.0f); world_translation.AddScaled(world_translation, world_delta, time_slice); localSpaceVelocity.linearMotion.y += localSpaceAcceleration.linearMotion.y*time_slice; Max_Clamp(localSpaceVelocity.linearMotion.y, 0.0f); // //-------------------------------------- // Update our turn rates and orientation //-------------------------------------- // const GameModel *model = GetGameModel(); Check_Object(model); Scalar temp = Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, currentSpeedMPS/GetMaxSpeed()); YawPitchRoll new_rotation(vehicle_to_world); temp *= time_slice; new_rotation.yaw += yawDemand * temp; new_rotation.pitch += pitchDemand * temp; new_rotation.roll += rollDemand * temp; // //---------------------------------------------- // Adjust position from network //---------------------------------------------- // YawPitchRoll correction_angle; Point3D correction_position; GetNetworkAdjustment(time_slice, correction_position, correction_angle); new_rotation.yaw.angle += correction_angle.yaw.angle; new_rotation.pitch.angle += correction_angle.pitch.angle; new_rotation.roll.angle += correction_angle.roll.angle; world_translation += correction_position; // //---------------------------------------------- // Cast a ray down to see what we are driving on //---------------------------------------------- // Stuff::Line3D line; line.m_length = m_groundRaycastHeight + 0.001f; line.m_direction = Vector3D::Down; line.m_origin = world_translation; line.m_origin.y += m_groundRaycastHeight; Stuff::Normal3D normal; CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this); Check_Object(CollisionGrid::Instance); // //------------------------------------------------ // If we miss the ground, go to where gravity said //------------------------------------------------ // LinearMatrix4D new_local_to_world; new_local_to_world.BuildRotation(new_rotation); if (!CollisionGrid::Instance->ProjectLine(&query)) { materialHit = MaterialCount; worldSpaceVelocity.linearMotion.Multiply( localSpaceVelocity.linearMotion, vehicle_to_world ); Max_Clamp(worldSpaceVelocity.linearMotion.y, 0.0f); new_local_to_world.BuildTranslation(world_translation); } // //-------------------------------------------------- // Otherwise, adapt the vehicle to the ground normal //-------------------------------------------------- // else { materialHit = query.m_material; line.FindEnd(&world_translation); new_local_to_world.BuildTranslation(world_translation); new_local_to_world.AlignLocalAxisToWorldVector(normal, Y_Axis, X_Axis, Z_Axis); // //-------------------------------------------------- // Update the velocities to conform to the landscape //-------------------------------------------------- // localSpaceVelocity.linearMotion.x = 0.0f; localSpaceVelocity.linearMotion.y = 0.0f; localSpaceVelocity.linearMotion.z = currentSpeedMPS; worldSpaceVelocity.linearMotion.Multiply( localSpaceVelocity.linearMotion, new_local_to_world ); } SetNewLocalToParent(new_local_to_world); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::HookUpSubsystems() { Stuff::ChainIteratorOf iterator(&subsystemsInVehicle); Subsystem *subsystem; while ((subsystem = iterator.ReadAndNext()) != NULL) { if (subsystem->IsDerivedFrom(Engine::DefaultData)) { engine = Cast_Object(Engine *, subsystem); } else if (subsystem->IsDerivedFrom(Torso::DefaultData)) { Torso* torso = Cast_Object(Torso*, subsystem); if (std::find(m_Torsos.begin(),m_Torsos.end(),torso) == m_Torsos.end()) { m_Torsos.push_back(torso); } } //Tell the Damage Zone that holds the subsystem that it is there!!! } if(engine) engine->ConnectEngine(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::BecomeInteresting(bool render_me) { Check_Object(this); LOAD_LOGIC("Become Interesting::Vehicle"); // //-------------------------------------------------------------------- // Let our parent deal with the video renderer. If we have a shadow, // don't make another //-------------------------------------------------------------------- // BaseClass::BecomeInteresting(render_me); CollisionVolume *cv = NULL;; cv = GetSolidVolume(); if (!cv) { cv = this->GetHierarchicalVolume(); } if (cv) { ExtentBox collisionBox(cv->m_localSpaceBounds); Point3D rotated_axis_extents; rotated_axis_extents.Multiply(cv->m_localSpaceBounds.axisExtents, cv->m_localSpaceBounds.localToParent); m_groundRaycastHeight = cv->m_localSpaceBounds.localToParent.entries[7]; m_groundRaycastHeight += Stuff::Fabs(rotated_axis_extents.y); } if (!render_me || shadow) return; // //------------------------------ // Otherwise, load up our shadow //------------------------------ // gosFX::Light *main_light = Mission::GetInstance()->GetMainLight(); const GameModel *model = GetGameModel(); Check_Object(model); if (!model->shadowStream || !main_light) { shadow = NULL; // MSL 5.02 Shadow shadowIntensity = 0.0f; } else { Resource shadow_stream(model->shadowStream); Verify(shadow_stream.DoesResourceExist()); gos_PushCurrentHeap(MidLevelRenderer::LightsHeap); int version = MidLevelRenderer::ReadMLRVersion(&shadow_stream); Check_Object(TiledLightManager::Instance); while (shadow_stream.GetBytesRemaining() > 0) { int light_type; shadow_stream >> light_type; Verify(light_type == MidLevelRenderer::MLRLight::ShadowLight); MidLevelRenderer::MLRShadowLight *shadow_light = new MidLevelRenderer::MLRShadowLight(&shadow_stream, version); Check_Object(shadow_light); shadow = Cast_Object(ShadowLight*, TiledLightManager::Instance->MakeLight(shadow_light)); shadow->m_shadowCaster = GetElement(); // MSL 5.02 Shadow gosFX::LightManager::Info info; shadow->GetInfo(&info); shadowIntensity = info.m_intensity; } gos_PopCurrentHeap(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::BecomeUninteresting() { Check_Object(this); BaseClass::BecomeUninteresting(); // //------------------ // Remove our shadow //------------------ // if (shadow) { Check_Object(shadow); delete shadow; shadow = NULL; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::CreateTrail() { Check_Object(this); POSTCOLLISION_LOGIC("Vehicle::Create Trail"); const GameModel *model = GetGameModel(); Check_Object(model); // //--------------------------------------------------------------------- // If we hit legal material and can have a trail, get the ID of the one // we should use and see if it is the same as the one we currently have //--------------------------------------------------------------------- // if (materialHit>=0 && materialHittrailEffectsTable != ResourceID::Null) { ResourceID trail_id; char material = materialHit; if(GetLocalToWorld().entries[7] - 1.0f <= Map::GetInstance()->GetGameModel ()->m_waterLevel) material = WaterMaterial; model->GetEffectResourceID(&trail_id, model->trailEffectsTable, material); if (trail_id == currentTrailID) return; // //---------------------------------------- // If we currently have an effect, kill it //---------------------------------------- // if (currentTrailEffect.GetCurrent()) { currentTrailEffect.GetCurrent()->executionState->RequestState( Effect::ExecutionStateEngine::StoppingState); currentTrailEffect.Remove(); } // //------------------------------------- // Make the new effect if it isn't null //------------------------------------- // if (trail_id != ResourceID::Null) { Effect *effect = CreateLoopingEffect(trail_id, this, true); if(effect) { Check_Object(effect); effect->BecomeInteresting (true); effect->videoStatus = true; effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState); currentTrailEffect.Add(effect); } } currentTrailID = trail_id; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::RemoveFromExecution() { Check_Object(this); if(currentTrailEffect.GetCurrent()) { currentTrailEffect.GetCurrent()->executionState->RequestState( Effect::ExecutionStateEngine::StoppingState); currentTrailEffect.Remove(); } BaseClass::RemoveFromExecution(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ProcessSelfDestruct() { Check_Object(this); if (!IsDestroyed()) { m_weaponShotMeLast = -50; ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0); // Remove our shadow if (shadow) { Check_Object(shadow); delete shadow; shadow = NULL; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::SelfDestruct() { Check_Object(this); m_whoShotMeLast = GetReplicatorID(); if (!IsDestroyed() && executionState->GetState() != Entity::ExecutionStateEngine::NeverExecuteState) { m_needSelfDestruct = 1; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Stuff::Point3D& Vehicle::EstimateFuturePosition( Stuff::Point3D *new_position, Stuff::Scalar seconds, bool consider_terrain ) { Check_Object(this); Check_Pointer(new_position); // //------------------------------------------------- // If we aren't moving, return our current position //------------------------------------------------- // *new_position = GetLocalToWorld(); if ((Small_Enough(currentSpeedMPS)) || (IsDestroyed() == true)) return *new_position; // //------------------------------------------------------------------------ // Figure out our height based on current position. If we are supposed to // consider the terrain, snap our position to the terrain //------------------------------------------------------------------------ // Stuff::Scalar old_height = new_position->y; if (consider_terrain) { Stuff::Scalar h = GetHeightAtPoint(*new_position, this); if (h != -100000.0f) old_height = h; } // //-------------------------- // Project our forward speed //-------------------------- // Stuff::UnitVector3D local_forward; GetLocalToWorld().GetLocalForwardInWorld(&local_forward); new_position->AddScaled(*new_position, local_forward, seconds * currentSpeedMPS); // //------------------------------------------------------------- // Assume that we swerve left at 1 mps at full stick deflection // // NOTE: This looks like doo-doo too //------------------------------------------------------------- // Stuff::UnitVector3D local_left; GetLocalToWorld().GetLocalLeftInWorld(&local_left); new_position->AddScaled(*new_position, local_left, seconds * yawDemand); // //-------------------------------------------------------------------- // If we are considering terrain, see how our altitude would have been // affected //-------------------------------------------------------------------- // if (consider_terrain) { Stuff::Scalar new_height = GetHeightAtPoint(*new_position, this); if (new_height != -100000.0f) new_position->y += new_height - old_height; } return *new_position; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ClearLancemate(void) { if (MWGUIManager::GetInstance ()) { HUDComm *comm; HUDComponent *hud; hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM); Verify (hud); comm = Cast_Object (HUDComm *,hud); comm->DeselectLancemate (); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ProcessCommand(int command) { MWPlayer *player; MWApplication *app = MWApplication::GetInstance(); if (app->networkingFlag) player = Cast_Object(MWPlayer *, app->servedConnectionData[GetReplicatorID().connectionID].clientPlayer); else player = Cast_Object(MWPlayer *, MWPlayer::GetInstance()); if (app->networkingFlag) { switch(command) { case VehicleCommand::LancemateAttackMyTargetCommand: case VehicleCommand::LancemateDefendMyTargetCommand: case VehicleCommand::LancemateFormOnMeCommand: case VehicleCommand::LancemateHoldFireCommand: case VehicleCommand::LancemateGoToMyNavPointCommand: case VehicleCommand::LancemateStopCommand: case VehicleCommand::LancemateShutDownCommand: case VehicleCommand::LancemateAttackNearestCommand: case VehicleCommand::LancemateRepairCommand: return; } } switch(command) { case VehicleCommand::JumpCommand: JumpRequest(); break; case VehicleCommand::StopJumpCommand: StopJumpRequest(); break; case VehicleCommand::PowerDownCommand: if (vehicleShutDown) ShutDownRequest(false); else ShutDownRequest(true); break; case VehicleCommand::CrouchCommand: CrouchRequest(); break; case VehicleCommand::GetUpCommand: GetUpRequestRequest(); break; case VehicleCommand::PressFlushCommand: SetCooling(1); break; case VehicleCommand::ReleaseFlushCommand: SetCooling(0); break; case VehicleCommand::SelfDestructCommand: SelfDestruct(); break; case VehicleCommand::EjectCommand: Eject (); break; case VehicleCommand::SetTargetCommand: break; case VehicleCommand::ToggleSearchLightCommand: ToggleSearchLight(); break; case VehicleCommand::LancemateAttackMyTargetCommand: if (player->m_LancemateCommandProxy.GetMode() == MWPlayer::LancemateCommandProxy::INVALID) { if (player->m_LancemateCommandProxy.SetMode(MWPlayer::LancemateCommandProxy::LANCEMATE_1) == true) { if (MWGUIManager::GetInstance ()) { HUDComm *comm; HUDComponent *hud; hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM); Verify (hud); comm = Cast_Object (HUDComm *,hud); comm->SelectLancemate (1); } } } else { if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_ATTACKPLAYERSTARGET) == true) { ClearLancemate (); } } break; case VehicleCommand::LancemateDefendMyTargetCommand: if (player->m_LancemateCommandProxy.GetMode() == MWPlayer::LancemateCommandProxy::INVALID) { if (player->m_LancemateCommandProxy.SetMode(MWPlayer::LancemateCommandProxy::LANCEMATE_2) == true) { if (MWGUIManager::GetInstance ()) { HUDComm *comm; HUDComponent *hud; hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM); Verify (hud); comm = Cast_Object (HUDComm *,hud); comm->SelectLancemate (2); } } } else { if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_DEFENDPLAYERSTARGET) == true) { ClearLancemate (); } } break; case VehicleCommand::LancemateFormOnMeCommand: if (player->m_LancemateCommandProxy.GetMode() == MWPlayer::LancemateCommandProxy::INVALID) { if (player->m_LancemateCommandProxy.SetMode(MWPlayer::LancemateCommandProxy::LANCEMATE_3) == true) { if (MWGUIManager::GetInstance ()) { HUDComm *comm; HUDComponent *hud; hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM); Verify (hud); comm = Cast_Object (HUDComm *,hud); comm->SelectLancemate (3); } } } else { if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_FORMONME) == true) { ClearLancemate (); } } break; case VehicleCommand::LancemateHoldFireCommand: if (player->m_LancemateCommandProxy.GetMode() == MWPlayer::LancemateCommandProxy::INVALID) { if (player->m_LancemateCommandProxy.SetMode(MWPlayer::LancemateCommandProxy::LANCEMATE_ALL) == true) { if (MWGUIManager::GetInstance ()) { HUDComm *comm; HUDComponent *hud; hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM); Verify (hud); comm = Cast_Object (HUDComm *,hud); comm->SelectAllLancemates (); } } } else { if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_HOLDFIRE) == true) { ClearLancemate (); } } break; case VehicleCommand::LancemateGoToMyNavPointCommand: if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_GOTOMYNAVPOINT) == true) { ClearLancemate (); } break; case VehicleCommand::LancemateStopCommand: if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_STOP) == true) { ClearLancemate (); } break; case VehicleCommand::LancemateShutDownCommand: if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_SHUTDOWN) == true) { ClearLancemate (); } break; case VehicleCommand::LancemateAttackNearestCommand: if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_ATTACKNEARESTTHREAT) == true) { ClearLancemate (); } break; case VehicleCommand::LancemateRepairCommand: if (player->m_LancemateCommandProxy.IssueCommand(this,MW4AI::LancemateCommands::LANCEMATE_REPAIRATNEARESTREPAIRBAY) == true) { ClearLancemate (); } break; default: break; } } Scalar Vehicle::GetMaxSpeed() { Check_Object(this); if(GetEngine()) return GetEngine()->GetMaxSpeed(); else { const GameModel *model = GetGameModel(); return model->maxSpeed; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::GetNetworkPosition(Stuff::Point3D ¤t_position, Stuff::YawPitchRoll ¤t_rotation) { current_position = GetLocalToWorld(); current_rotation = GetLocalToWorld(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::GetDeadReckonedNetworkPosition(Stuff::Point3D ¤t_position, Stuff::YawPitchRoll ¤t_rotation) { current_position = GetLocalToWorld(); current_rotation = GetLocalToWorld(); current_position += correctionPosition; current_rotation.yaw += correctionAngle.yaw; current_rotation.pitch += correctionAngle.pitch; current_rotation.roll += correctionAngle.roll; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ClearNetworkPosition() { correctionPosition = Point3D::Identity; correctionAngle = YawPitchRoll::Identity; rotationCorrectionTime = 0.0f; positionCorrectionTime = 0.0f; correctingPosition = false; correctingRotation = false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::SetNetworkCorretionPosition(Stuff::Point3D new_position, Stuff::YawPitchRoll new_rotation, Point3D velocity, Scalar vel_request, Scalar latency, Scalar update_rate) { YawPitchRoll original_rotation; Point3D original_translation; original_rotation = GetLocalToWorld(); original_translation = GetLocalToWorld(); new_rotation.Normalize(); original_rotation.Normalize(); correctionAngle.yaw.angle = new_rotation.yaw.angle - original_rotation.yaw.angle; correctionAngle.pitch.angle = new_rotation.pitch.angle - original_rotation.pitch.angle; correctionAngle.roll.angle = new_rotation.roll.angle - original_rotation.roll.angle; correctionAngle.Normalize(); correctionPosition.Subtract(new_position, original_translation); Scalar rotation_length_squared = Abs(correctionAngle.yaw.angle*correctionAngle.yaw.angle + correctionAngle.pitch.angle*correctionAngle.pitch.angle + correctionAngle.roll.angle*correctionAngle.roll.angle); Scalar correction_scale = rotation_length_squared / (15.0f*Degrees_Per_Radian); Clamp(correction_scale, 0.0f, 1.0f); rotationCorrectionTime = Lerp( 0.1f, 0.5f, correction_scale); correction_scale = correctionPosition.GetLengthSquared() / 25.0f; Clamp(correction_scale, 0.0f, 1.0f); positionCorrectionTime = Lerp( 0.1f, 0.5f, correction_scale); correctingPosition = true; correctingRotation = true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Vehicle::GetNetworkAdjustment(Stuff::Scalar time_slice, Point3D &adjustment_position, Stuff::YawPitchRoll &adjustment_rotation) { adjustment_position = Point3D::Identity; adjustment_rotation = YawPitchRoll::Identity; if (correctingPosition) { // if we have an amount of time to correct over if (positionCorrectionTime > 0.0f) { // else incrementaly add in some of that position. Stuff::Scalar lerp_value = positionCorrectionTime / time_slice; Max_Clamp(lerp_value, 1.0f); adjustment_position.Lerp(Point3D::Identity, correctionPosition, lerp_value); correctionPosition -= adjustment_position; positionCorrectionTime -= time_slice; } else { // else we are done adjustment_position = correctionPosition; correctionPosition = Point3D::Identity; positionCorrectionTime = 0.0f; correctingPosition = false; } } if (correctingRotation) { if (rotationCorrectionTime > 0.0f) { Stuff::Scalar lerp_value = rotationCorrectionTime / time_slice; Max_Clamp(lerp_value, 1.0f); adjustment_rotation.Lerp(YawPitchRoll::Identity, correctionAngle, lerp_value); correctionAngle.yaw.angle -= adjustment_rotation.yaw.angle; correctionAngle.pitch -= adjustment_rotation.pitch.angle; correctionAngle.roll.angle -= adjustment_rotation.roll.angle; rotationCorrectionTime -= time_slice; } else { // else we are done adjustment_rotation = correctionAngle; correctionAngle = YawPitchRoll::Identity; rotationCorrectionTime = 0.0f; correctingRotation = false; } } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::ReactToDestruction(int damage_mode, int damage_type) { switch(damage_mode) { case InternalDamageObject::DestructionDamageMode: SetDead (); break; } BaseClass::ReactToDestruction (damage_mode,damage_type); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::AddStatsToString(std::string& s) { if (GetTeam() != MWApplication::No_Team) { s += "Team: "; s += IntToString(GetTeam()); s += " "; } MWObject::AddStatsToString(s); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Vehicle::AddToSensorCellMap() { SensorCellMap* sensor_cell_map = GetSensorCellMap(); if (sensor_cell_map != 0) { sensor_cell_map->Add(this,m_SensorCellMapX,m_SensorCellMapZ); } } void Vehicle::RemoveFromSensorCellMap() { if (m_SensorCellMapX < 0) { return; } SensorCellMap* sensor_cell_map = GetSensorCellMap(); if (sensor_cell_map != 0) { sensor_cell_map->Remove(this,m_SensorCellMapX,m_SensorCellMapZ); } } SensorCellMap* Vehicle::GetSensorCellMap() { if (MWMission::GetInstance() == 0) { return(0); } MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance()); return (&mwmission->m_VehicleAndTurretCellMap); } void Vehicle::UpdateSensorCellMapPosition() { #ifdef NEW_SENSOR_TIMING __int64 start_time = GetCycles(); #endif if (m_LastSensorCellPositionUpdate + sensor_map_update_frequency > gos_GetElapsedTime()) { #ifdef NEW_SENSOR_TIMING tVehicleTime += GetCycles() - start_time; #endif return; } m_LastSensorCellPositionUpdate = gos_GetElapsedTime(); SensorCellMap* sensor_cell_map = GetSensorCellMap(); if (sensor_cell_map == 0) { #ifdef NEW_SENSOR_TIMING tVehicleTime += GetCycles() - start_time; #endif return; } int x,z; sensor_cell_map->GetCellPos(x,z,GetLocalToWorld()); if ((x != m_SensorCellMapX) || (z != m_SensorCellMapZ)) { RemoveFromSensorCellMap(); m_SensorCellMapX = x; m_SensorCellMapZ = z; AddToSensorCellMap(); } #ifdef NEW_SENSOR_TIMING tVehicleTime += GetCycles() - start_time; #endif } void MechWarrior4::VehicleSecurityCheckStop() { _asm { nop } }