#include "MW4Headers.hpp" #include #include #include "StickyMover.hpp" #include //############################################################################# //########################## ExecutionStateEngine ####################### //############################################################################# StickyMover::ExecutionStateEngine::ClassData* StickyMover::ExecutionStateEngine::DefaultData = NULL; const StateEngine::StateEntry StickyMover::ExecutionStateEngine::StateEntries[]= { STATE_ENTRY(StickyMover__ExecutionStateEngine, StickyExecution) }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::ExecutionStateEngine::InitializeClass() { Check_Object(StateEngine::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( StickyMover__ExecutionStateEngineClassID, "StickyMover::ExecutionStateEngine", BaseClass::DefaultData, ELEMENTS(StateEntries), StateEntries, (Entity::ExecutionStateEngine::Factory)Make, (Entity::ExecutionStateEngine::FactoryRequest::Factory) &FactoryRequest::ConstructFactoryRequest ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::ExecutionStateEngine::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // StickyMover::ExecutionStateEngine* StickyMover::ExecutionStateEngine::Make( StickyMover *weapon, FactoryRequest *request ) { Check_Object(weapon); Check_Object(request); gos_PushCurrentHeap(Heap); StickyMover::ExecutionStateEngine *engine = new StickyMover::ExecutionStateEngine(DefaultData, weapon, request); gos_PopCurrentHeap(); return engine; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::ExecutionStateEngine::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //############################################################################# //############################### StickyMover ############################ //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // StickyMover::ClassData* StickyMover::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::InitializeClass() { Check_Object(StickyMover::ExecutionStateEngine::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( StickyMoverClassID, "MechWarrior4::StickyMover", BaseClass::DefaultData, 0, NULL, (Entity::Factory)Make, (Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage, ExecutionStateEngine::DefaultData, (Entity::GameModel::Factory)GameModel::ConstructGameModel, NULL, (Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify, (Entity::GameModel::ModelWrite)GameModel::WriteToText, (Entity::GameModel::ModelSave)GameModel::SaveGameModel ); Register_Object(DefaultData); DIRECT_GAME_MODEL_ATTRIBUTE( StickyMover__GameModel, ActiveTime, activeTime, Scalar ); DIRECT_GAME_MODEL_ATTRIBUTE( StickyMover__GameModel, IdleLoopResource, idleLoopResource, ResourceID ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // StickyMover* StickyMover::Make( CreateMessage *message, ReplicatorID *base_id ) { Check_Object(message); gos_PushCurrentHeap(Heap); Check_Object(EntityManager::GetInstance()); StickyMover *new_entity; Entity *entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID); if (entity) { new_entity = Cast_Object(StickyMover*, entity); new_entity->Reuse(message, base_id); } else new_entity = new StickyMover(DefaultData, message, base_id, NULL); gos_PopCurrentHeap(); Check_Object(new_entity); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // StickyMover::StickyMover( ClassData *class_data, CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): WeaponMover(class_data, message, base_id, element), attachedEntity(this), idleEffect(NULL) { Check_Pointer(this); Check_Object(message); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // StickyMover::~StickyMover() { DESTRUCTOR("StickyMover"); Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::SentenceToDeathRow() { Check_Object(this); if(idleEffect.GetCurrent() != NULL) { idleEffect.GetCurrent()->SentenceToDeathRow(); } BaseClass::SentenceToDeathRow (); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::PreCollisionExecute(Time till) { Check_Object(this); PRECOLLISION_LOGIC("Sticky Mover"); //MUST SKIP WEAPONMOVE PRE COLLISION SO COPY THIS STUFF HERE! Vector3D distance; Point3D initial_position; initial_position = initialLocalToParent; Point3D pointStartThisFrame; pointStartThisFrame = GetLocalToParent(); distance.Subtract(pointStartThisFrame, initial_position); Scalar maxDistanceSquared = maxDistance * maxDistance; Set_Statistic(Executed_WeaponMover_Count, Executed_WeaponMover_Count+1); UsePostCollision(); Mover::PreCollisionExecute(till); Check_Object(executionState); int execution_state = executionState->GetState(); if(execution_state == ExecutionStateEngine::StraightLineMotionState) { Point3D current_position; ElementRenderer::Element *element = GetElement(); current_position = element->GetNewLocalToParent(); distance.Subtract(current_position, initial_position); // // We still need to run post collision this frame on anything within our // range, we can't just skip in the same frame as we went to far so clamp // the far point. // if(distance.GetLengthSquared() >= maxDistanceSquared) { // // Clamp the end point // Vector3D direction; direction.Normalize(distance); Line3D line; line.m_origin = initial_position; line.m_direction = direction; line.m_length = maxDistance+1.0f; line.FindEnd(&pointStartThisFrame); // reusing variable LinearMatrix4D new_local_to_parent; new_local_to_parent = element->GetNewLocalToParent(); new_local_to_parent.BuildTranslation(pointStartThisFrame); SetNewLocalToParent(new_local_to_parent); } } BlowUpIfOffMap(); // //---------------------------------------------------- // Make sure we use post collision and call our parent //---------------------------------------------------- // switch(execution_state) { case ExecutionStateEngine::StickyExecutionState: { const GameModel *model = GetGameModel(); Check_Object(model); if((GetTimeParameter(till) >= model->activeTime) || (attachedEntity.GetCurrent() == NULL) || (attachedEntity.GetCurrent()->IsDestroyed())) { SentenceToDeathRow(); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool StickyMover::CollisionHandler( Stuff::LinearMatrix4D *new_position, Stuff::DynamicArrayOf *collisions ) { Check_Object(this); Check_Object(collisions); Verify(GetInterestLevel() != DormantInterestLevel); Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this)); // //---------------------------------------------- //This is where we need to start the follow code //---------------------------------------------- // CollisionData *data = &(*collisions)[0]; Check_Pointer(data); Check_Object(executionState); executionState->RequestState(ExecutionStateEngine::StickyExecutionState); *new_position = LinearMatrix4D::Identity; new_position->AlignLocalAxisToWorldVector(data->m_normal, Y_Axis, X_Axis, Z_Axis); new_position->BuildTranslation(data->m_worldIntersectionPoint); SetNewLocalToParent(*new_position); lastParameterization = gos_GetElapsedTime(); attachedEntity.Remove(); attachedEntity.Add(data->m_otherEntity); SetFollowing(); entityOffset.MultiplyByInverse(data->m_worldIntersectionPoint, data->m_otherEntity->GetLocalToWorld()); if(trailEffect.GetCurrent()) trailEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState); OnActiveTimeStart(); // //-------------------------------------------------- //This is so the Narc will not block the target Mech //-------------------------------------------------- // SetCollisionMask(NeverCollidesMask); CreateIdleEffect(); PostCollision(collisions); Entity::ExecutionStateEngine *engine = executionState; if (engine->GetState() == ExecutionStateEngine::NeverExecuteState) { Verify(!newCollisions); delete collisions; } else newCollisions = collisions; return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::PostCollisionExecute(Time till) { Check_Object(this); POSTCOLLISION_LOGIC("StickyMover"); Check_Object(executionState); int execution_state = executionState->GetState(); switch(execution_state) { case ExecutionStateEngine::StickyExecutionState: { Entity *attached_entity; attached_entity = attachedEntity.GetCurrent(); if(attached_entity) { Check_Object(attached_entity); LinearMatrix4D new_position; Point3D new_location; LinearMatrix4D entity_location; UnitQuaternion rotation; rotation = GetLocalToWorld(); entity_location = attached_entity->GetLocalToWorld(); new_location.Multiply(entityOffset, entity_location); new_position.BuildTranslation(new_location); new_position.BuildRotation(rotation); SetNewLocalToParent(new_position); SyncMatrices(true); } else { SentenceToDeathRow(); } break; } } BaseClass::PostCollisionExecute(till); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::CreateIdleEffect() { Check_Object(this); const GameModel *model = GetGameModel(); Check_Object(model); if(model->idleLoopResource != ResourceID::Null) { Resource idle_resource(model->idleLoopResource); if(idle_resource.DoesResourceExist()) { ClassID class_ID; class_ID = GetClassIDFromDataListID(model->idleLoopResource); Verify(class_ID != NullClassID); Effect::CreateMessage effect_create_message( sizeof(Effect::CreateMessage), DefaultEventPriority, CreateMessage::DefaultFlags, class_ID, Effect::DefaultFlags|Effect::LoopFlag, model->idleLoopResource, GetElement()->GetNewLocalToParent(), 0.0f, ExecutionStateEngine::AlwaysExecuteState, NameTable::NullObjectID, Entity::DefaultAlignment ); MemoryStream stream(&effect_create_message, effect_create_message.messageLength); Entity *entity; ReplicatorID trail_id = Connection::Hermit->GetNextReplicatorID(); entity = CreateEntity(&stream, &trail_id, false); Check_Object(entity); Check_Object(Map::GetInstance()); Map::GetInstance()->AddChild(entity); Effect *effect = Cast_Object(Effect *, entity); idleEffect.Add(effect); effect->SetFollowEntity(this); effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState); entity->SyncMatrices(true); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void StickyMover::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); }