diff --git a/rwengine/include/ai/CharacterController.hpp b/rwengine/include/ai/CharacterController.hpp index c14e024d..399fae1f 100644 --- a/rwengine/include/ai/CharacterController.hpp +++ b/rwengine/include/ai/CharacterController.hpp @@ -67,7 +67,7 @@ protected: bool updateActivity(); void setActivity(Activity* activity); - float vehicleIdle; + float m_closeDoorTimer; // Goal related variables Goal currentGoal; @@ -190,7 +190,10 @@ namespace Activities { struct ExitVehicle : public CharacterController::Activity { DECL_ACTIVITY( ExitVehicle ) - ExitVehicle( ) + const bool jacked; + + ExitVehicle(bool jacked_ = false) + : jacked(jacked_) {} bool update(CharacterObject *character, CharacterController *controller); diff --git a/rwengine/include/objects/CharacterObject.hpp b/rwengine/include/objects/CharacterObject.hpp index 34ba468e..e9af7f5a 100644 --- a/rwengine/include/objects/CharacterObject.hpp +++ b/rwengine/include/objects/CharacterObject.hpp @@ -65,10 +65,14 @@ struct AnimationGroup Animation* car_open_lhs; Animation* car_getin_lhs; Animation* car_getout_lhs; + Animation* car_jacked_lhs; + Animation* car_pullout_lhs; Animation* car_open_rhs; Animation* car_getin_rhs; Animation* car_getout_rhs; + Animation* car_jacked_rhs; + Animation* car_pullout_rhs; Animation* kd_front; Animation* ko_shot_front; diff --git a/rwengine/src/ai/CharacterController.cpp b/rwengine/src/ai/CharacterController.cpp index 8bcb5db0..43cefeeb 100644 --- a/rwengine/src/ai/CharacterController.cpp +++ b/rwengine/src/ai/CharacterController.cpp @@ -7,11 +7,13 @@ #include #include +constexpr float kCloseDoorIdleTime = 2.f; + CharacterController::CharacterController(CharacterObject* character) : character(character) , _currentActivity(nullptr) , _nextActivity(nullptr) - , vehicleIdle(0.f) + , m_closeDoorTimer(0.f) , currentGoal(None) , leader(nullptr) , targetNode(nullptr) @@ -80,28 +82,27 @@ void CharacterController::update(float dt) } if( _currentActivity == nullptr ) { - if( glm::length( d ) <= 0.1f ) - { - vehicleIdle += dt; - } - else - { - vehicleIdle = 0.f; - } - - if( vehicleIdle >= 1.f ) - { - // If character is idle in vehicle, try to close the door. - auto v = character->getCurrentVehicle(); - auto entryDoor = v->getSeatEntryDoor(character->getCurrentSeat()); - - if( entryDoor && entryDoor->constraint ) - { - character->getCurrentVehicle()->setPartTarget(entryDoor, true, entryDoor->closedAngle); + // If character is idle in vehicle, try to close the door. + auto v = character->getCurrentVehicle(); + auto entryDoor = v->getSeatEntryDoor(character->getCurrentSeat()); + + if (entryDoor && entryDoor->constraint) { + if (glm::length( d ) <= 0.1f) { + if (m_closeDoorTimer >= kCloseDoorIdleTime) { + character->getCurrentVehicle()->setPartTarget(entryDoor, true, entryDoor->closedAngle); + } + m_closeDoorTimer += dt; + } + else { + m_closeDoorTimer = 0.f; } } } } + else + { + m_closeDoorTimer = 0.f; + } if( updateActivity() ) { character->activityFinished(); @@ -219,18 +220,24 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr auto anm_open = character->animations.car_open_lhs; auto anm_enter = character->animations.car_getin_lhs; - + auto anm_pullout = character->animations.car_pullout_lhs; + if( entryDoor->dummy->getDefaultTranslation().x > 0.f ) { anm_open = character->animations.car_open_rhs; anm_enter = character->animations.car_getin_rhs; + anm_pullout = character->animations.car_pullout_rhs; } + + // If there's someone in this seat already, we may have to ask them to leave. + auto currentOccupant= static_cast(vehicle->getOccupant(seat)); + + bool tryToEnter = false; if( entering ) { if( character->animator->getAnimation(AnimIndexAction) == anm_open ) { if( character->animator->isCompleted(AnimIndexAction) ) { - character->playActivityAnimation(anm_enter, false, true); - character->enterVehicle(vehicle, seat); + tryToEnter = true; } else if( entryDoor && character->animator->getAnimationTime(AnimIndexAction) >= 0.5f ) { @@ -241,6 +248,11 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr character->rotation = vehicle->getRotation(); } } + else if (character->animator->getAnimation(AnimIndexAction) == anm_pullout) { + if (character->animator->isCompleted(AnimIndexAction)) { + tryToEnter = true; + } + } else if( character->animator->getAnimation(AnimIndexAction) == anm_enter ) { if( character->animator->isCompleted(AnimIndexAction) ) { // VehicleGetIn is over, finish activity @@ -266,8 +278,7 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr // Determine if the door open animation should be skipped. if( entryDoor == nullptr || (entryDoor->constraint != nullptr && glm::abs(entryDoor->constraint->getHingeAngle()) >= 0.6f ) ) { - character->playActivityAnimation(anm_enter, false, true); - character->enterVehicle(vehicle, seat); + tryToEnter = true; } else { @@ -286,6 +297,18 @@ bool Activities::EnterVehicle::update(CharacterObject *character, CharacterContr character->controller->setMoveDirection({1.f, 0.f, 0.f}); } } + + if (tryToEnter) { + if (currentOccupant != nullptr && currentOccupant != character) { + // Play the pullout animation and tell the other character to get out. + character->playActivityAnimation(anm_pullout, false, true); + currentOccupant->controller->setNextActivity(new Activities::ExitVehicle(true)); + } + else { + character->playActivityAnimation(anm_enter, false, true); + character->enterVehicle(vehicle, seat); + } + } return false; } @@ -294,15 +317,49 @@ bool Activities::ExitVehicle::update(CharacterObject *character, CharacterContro { RW_UNUSED(controller); + if (jacked) { + auto anm_jacked_lhs = character->animations.car_jacked_lhs; + auto anm_jacked_rhs = character->animations.car_jacked_lhs; + auto anm_current = character->animator->getAnimation(AnimIndexAction); + + if (anm_current == anm_jacked_lhs || anm_current == anm_jacked_rhs) { + if (character->animator->isCompleted(AnimIndexAction)) { + return true; + } + } + else { + if (character->getCurrentVehicle() == nullptr) return true; + + auto vehicle = character->getCurrentVehicle(); + auto seat = character->getCurrentSeat(); + auto door = vehicle->getSeatEntryDoor(seat); + + character->rotation = vehicle->getRotation(); + + // Exit the vehicle immediatley + auto exitpos = vehicle->getSeatEntryPosition(seat); + character->enterVehicle(nullptr, seat); + character->setPosition(exitpos); + + if (door->dummy->getDefaultTranslation().x > 0.f) { + character->playActivityAnimation(anm_jacked_rhs, false, true); + } + else { + character->playActivityAnimation(anm_jacked_lhs, false, true); + } + // No need to open the door, it should already be open. + } + return false; + } + if( character->getCurrentVehicle() == nullptr ) return true; auto vehicle = character->getCurrentVehicle(); - auto seat = character->getCurrentSeat(); auto door = vehicle->getSeatEntryDoor(seat); - + auto anm_exit = character->animations.car_getout_lhs; - + if( door->dummy->getDefaultTranslation().x > 0.f ) { anm_exit = character->animations.car_getout_rhs; diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index e2e72e79..3eb8f556 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -52,10 +52,14 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, const animations.car_open_lhs = engine->data->animations["car_open_lhs"]; animations.car_getin_lhs = engine->data->animations["car_getin_lhs"]; animations.car_getout_lhs = engine->data->animations["car_getout_lhs"]; - + animations.car_pullout_lhs = engine->data->animations["car_pullout_lhs"]; + animations.car_jacked_lhs = engine->data->animations["car_jackedlhs"]; + animations.car_open_rhs = engine->data->animations["car_open_rhs"]; animations.car_getin_rhs = engine->data->animations["car_getin_rhs"]; animations.car_getout_rhs = engine->data->animations["car_getout_rhs"]; + animations.car_pullout_rhs = engine->data->animations["car_pullout_rhs"]; + animations.car_jacked_rhs = engine->data->animations["car_jackedrhs"]; animations.kd_front = engine->data->animations["kd_front"]; animations.ko_shot_front = engine->data->animations["ko_shot_front"];