diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 03d651177e..556a045c5f 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -149,11 +149,13 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni // Root is the default animation { "root" }, // RootAnim, - // These are selected in the move state based on velocity + // These are selected in the move state based on velocity. { "run", { 0.0f, 1.0f, 0.0f } }, // RunForwardAnim, { "back", { 0.0f,-1.0f, 0.0f } }, // BackBackwardAnim { "side", {-1.0f, 0.0f, 0.0f } }, // SideLeftAnim, { "side_right", { 1.0f, 0.0f, 0.0f } }, // SideRightAnim, + { "turn_left", { 0.0f, 0.0f, 0.0f } }, //Skurps + { "turn_right", { 0.0f, 0.0f, 0.0f } }, //Skurps { "sprint_root" }, { "sprint_forward", { 0.0f, 1.0f, 0.0f } }, @@ -166,12 +168,16 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni { "crouch_backward", { 0.0f,-1.0f, 0.0f } }, { "crouch_side", {-1.0f, 0.0f, 0.0f } }, { "crouch_right", { 1.0f, 0.0f, 0.0f } }, + { "crouch_turn_left", { 0.0f, 0.0f, 0.0f } }, //Skurps + { "crouch_turn_right", { 0.0f, 0.0f, 0.0f } }, //Skurps { "prone_root" }, { "prone_forward", { 0.0f, 1.0f, 0.0f } }, { "prone_backward", { 0.0f,-1.0f, 0.0f } }, { "prone_side", {-1.0f, 0.0f, 0.0f } }, //Skurps { "prone_right", { 1.0f, 0.0f, 0.0f } }, //Skurps + { "prone_turn_left", { 0.0f, 0.0f, 0.0f } }, //Skurps + { "prone_turn_right", { 0.0f, 0.0f, 0.0f } }, //Skurps { "swim_root" }, { "swim_forward", { 0.0f, 1.0f, 0.0f } }, @@ -185,6 +191,9 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni { "standjump" }, // StandJumpAnim { "land" }, // LandAnim { "jet" }, // JetAnim + { "proneIn"}, // ProneInAnim -Skurps + { "proneOut"}, // ProneOutAnim -Skurps + { "dive"}, //DiveAnim - Skurps }; //---------------------------------------------------------------------------- @@ -310,6 +319,7 @@ PlayerData::PlayerData() minProneLookAngle = -.3491f; // Skurps maxProneLookAngle = .3491f; // Skurps maxFreelookAngle = 3.0f; + maxTimeScale = 1.5f; mass = 9.0f; // from ShapeBase @@ -367,18 +377,27 @@ PlayerData::PlayerData() maxUnderwaterForwardSpeed = 6.0f; maxUnderwaterBackwardSpeed = 6.0f; maxUnderwaterSideSpeed = 6.0f; + swimYawScale = 1.0f; //Skurps + swimPitchScale = 1.0f; //Skurps // Crouching crouchForce = 45.0f * 9.0f; maxCrouchForwardSpeed = 4.0f; maxCrouchBackwardSpeed = 4.0f; - maxCrouchSideSpeed = 4.0f; + maxCrouchSideSpeed = 4.0f; + crouchYawScale = 1.0f; //Skurps + crouchPitchScale = 1.0f; //Skurps // Prone proneForce = 45.0f * 9.0f; maxProneForwardSpeed = 2.0f; maxProneBackwardSpeed = 2.0f; - maxProneSideSpeed = 0.0f; + maxProneSideSpeed = 0.0f; + proneYawScale = 1.0f; //Skurps + pronePitchScale = 1.0f; //Skurps + proneOutSequenceTime = 0.0f; //Skurps + proneInSequenceTime = 0.0f; //Skurps + proneDiveSequenceTime = 0.0f; //Skurps // Jetting jetJumpForce = 0; @@ -420,10 +439,10 @@ PlayerData::PlayerData() boxTorsoPercentage = 0.55f; // damage locations - boxTorsoLeftPercentage = 0; //Skurps replaced left/right/front/back head percentages - boxTorsoRightPercentage = 1; //Skurps - boxTorsoBackPercentage = 0; //Skurps - boxTorsoFrontPercentage = 1; //Skurps + boxTorsoLeftPercentage = 0.15f; //Skurps replaced left/right/front/back head percentages + boxTorsoRightPercentage = 0.15f; //Skurps + boxTorsoBackPercentage = 0.15f; //Skurps + boxTorsoFrontPercentage = 0.15f; //Skurps for (S32 i = 0; i < MaxSounds; i++) INIT_SOUNDASSET_ARRAY(PlayerSound, i); @@ -493,7 +512,7 @@ bool PlayerData::preload(bool server, String &errorStr) if (jetMinJumpEnergy < jetJumpEnergyDrain) jetMinJumpEnergy = jetJumpEnergyDrain; - // Validate some of the data + // Validate some of the data if (fallingSpeedThreshold > 0.0f) Con::printf("PlayerData:: Falling speed threshold should be downwards (negative)"); @@ -506,6 +525,7 @@ bool PlayerData::preload(bool server, String &errorStr) Con::printf("PlayerData:: Jump delay exceeds range (0-%d)",jumpDelay); } + Resource shape; if (shapeAssetRef.notNull()) shape = shapeAssetRef.assetPtr->getShapeResource(); @@ -539,8 +559,9 @@ bool PlayerData::preload(bool server, String &errorStr) dp->velocityScale = true; dp->death = false; - if (dp->sequence != -1) + if (dp->sequence != -1){ getGroundInfo(si,thread,dp); + } } for (S32 b = 0; b < shape->sequences.size(); b++) { @@ -550,6 +571,7 @@ bool PlayerData::preload(bool server, String &errorStr) dp->name = shape->getName(shape->sequences[b].nameIndex); dp->velocityScale = false; getGroundInfo(si,thread,dp++); + } } actionCount = dp - actionList; @@ -676,10 +698,14 @@ void PlayerData::getGroundInfo(TSShapeInstance* si, TSThread* thread,ActionAnima else { VectorF save = dp->dir; + si->setSequence(thread,dp->sequence,0); + F32 duration = thread->getSequence()->duration; si->animate(); si->advanceTime(1); si->animateGround(); + + // Linear ground translation si->getGroundTransform().getColumn(3,&dp->dir); if ((dp->speed = dp->dir.len()) < 0.01f) { @@ -696,9 +722,29 @@ void PlayerData::getGroundInfo(TSShapeInstance* si, TSThread* thread,ActionAnima } else dp->dir *= 1.0f / dp->speed; + + // Yaw ground rotation -Skurps + VectorF fwd; + si->getGroundTransform().getColumn(1,&fwd); + fwd.z = 0.0f; + if (fwd.len() > 0.0001f) + { + fwd.normalize(); + F32 yaw = mAtan2(fwd.x, fwd.y); + + // Wrap yaw into [-pi, pi] + yaw = mWrapF(yaw, -M_PI_F, M_PI_F); + + dp->angularSpeed = yaw; // radians per frame + } + else + { + dp->angularSpeed = 0.0f; + } } } + bool PlayerData::isTableSequence(S32 seq) { // The sequences from the table must already have @@ -709,6 +755,12 @@ bool PlayerData::isTableSequence(S32 seq) return false; } +bool PlayerData::isTurnAction(U32 action) //Skurps +{ + return (action == TurnLeftAnim || action == TurnRightAnim || action == CrouchTurnLeftAnim || action == CrouchTurnRightAnim || action == ProneTurnLeftAnim + || action == ProneTurnRightAnim); +} + bool PlayerData::isJumpAction(U32 action) { return (action == JumpAnim || action == StandJumpAnim); @@ -750,14 +802,12 @@ void PlayerData::initPersistFields() "@brief Defines the maximum left and right angles (in radians) the player can " "look in freelook mode.\n\n" ); addFieldV( "minProneLookAngle", TypeF32, Offset(minProneLookAngle, PlayerData), &CommonValidators::DirFloatPi, - "@brief Lowest angle (in radians) the player can look when Prone.\n\n" + "@brief Lowest angle (in radians) the player can look when Prone Should be >= minLookAngle for correct animation position.\n\n" "@note An angle of zero is straight ahead, with positive up and negative down." ); //Skurps addFieldV( "maxProneLookAngle", TypeF32, Offset(maxProneLookAngle, PlayerData), &CommonValidators::DirFloatPi, - "@brief Highest angle (in radians) the player can look when Prone.\n\n" + "@brief Highest angle (in radians) the player can look when Prone. Should be <= maxLookAngle for correct animation position.\n\n" "@note An angle of zero is straight ahead, with positive up and negative down." ); //Skurps - - endGroup( "Camera" ); addGroup( "Movement" ); @@ -916,6 +966,10 @@ void PlayerData::initPersistFields() "@brief Maximum backward speed when underwater.\n\n" ); addFieldV( "maxUnderwaterSideSpeed", TypeRangedF32, Offset(maxUnderwaterSideSpeed, PlayerData), &CommonValidators::PositiveFloat, "@brief Maximum sideways speed when underwater.\n\n" ); + addFieldV( "swimYawScale", TypeRangedF32, Offset(swimYawScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale yaw motion while swimming." ); + addFieldV( "swimPitchScale", TypeRangedF32, Offset(swimPitchScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale pitch motion while swimming." ); endGroup( "Movement: Swimming" ); @@ -929,6 +983,10 @@ void PlayerData::initPersistFields() "@brief Maximum backward speed when crouching.\n\n" ); addFieldV( "maxCrouchSideSpeed", TypeRangedF32, Offset(maxCrouchSideSpeed, PlayerData), &CommonValidators::PositiveFloat, "@brief Maximum sideways speed when crouching.\n\n" ); + addFieldV( "crouchYawScale", TypeRangedF32, Offset(crouchYawScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale yaw motion while crouching." ); + addFieldV( "crouchPitchScale", TypeRangedF32, Offset(crouchPitchScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale pitch motion while crouching." ); endGroup( "Movement: Crouching" ); @@ -942,6 +1000,19 @@ void PlayerData::initPersistFields() "@brief Maximum backward speed when prone (laying down).\n\n" ); addFieldV( "maxProneSideSpeed", TypeRangedF32, Offset(maxProneSideSpeed, PlayerData), &CommonValidators::PositiveFloat, "@brief Maximum sideways speed when prone (laying down).\n\n" ); + addFieldV( "proneDiveSequenceTime", TypeRangedF32, Offset(proneDiveSequenceTime, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Length of the proneRecoverState when diving into prone.\n\n" + "The dive sequence will be scaled to match this.\n"); + addFieldV( "proneInSequenceTime", TypeRangedF32, Offset(proneInSequenceTime, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Length of the proneRecoverState when getting into prone.\n\n" + "The proneIn sequence will be scaled to match this.\n"); + addFieldV( "proneOutSequenceTime", TypeRangedF32, Offset(proneOutSequenceTime, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Length of the proneRecoverState when getting out of prone.\n\n" + "The proneOut sequence will be scaled to match this.\n"); + addFieldV( "proneYawScale", TypeRangedF32, Offset(proneYawScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale yaw motion while prone." ); + addFieldV( "pronePitchScale", TypeRangedF32, Offset(pronePitchScale, PlayerData), &CommonValidators::PositiveFloat, //Skurps + "@brief Amount to scale pitch motion while prone." ); endGroup( "Movement: Prone" ); @@ -1200,6 +1271,7 @@ void PlayerData::packData(BitStream* stream) stream->write(maxFreelookAngle); stream->write(minProneLookAngle);//Skurps stream->write(maxProneLookAngle);//Skurps + stream->write(maxTimeScale); stream->write(mass); @@ -1250,18 +1322,28 @@ void PlayerData::packData(BitStream* stream) stream->write(maxUnderwaterForwardSpeed); stream->write(maxUnderwaterBackwardSpeed); stream->write(maxUnderwaterSideSpeed); + stream->write(swimYawScale); //Skurps + stream->write(swimPitchScale); //Skurps // Crouching stream->write(crouchForce); stream->write(maxCrouchForwardSpeed); stream->write(maxCrouchBackwardSpeed); stream->write(maxCrouchSideSpeed); + stream->write(crouchYawScale); //Skurps + stream->write(crouchPitchScale); //Skurps + // Prone stream->write(proneForce); stream->write(maxProneForwardSpeed); stream->write(maxProneBackwardSpeed); stream->write(maxProneSideSpeed); + stream->write(proneInSequenceTime); //Skurps + stream->write(proneDiveSequenceTime); //Skurps + stream->write(proneOutSequenceTime); //Skurps + stream->write(proneYawScale); //Skurps + stream->write(pronePitchScale); //Skurps // Jetting stream->write(jetJumpForce); @@ -1384,6 +1466,7 @@ void PlayerData::unpackData(BitStream* stream) stream->read(&maxFreelookAngle); stream->read(&minProneLookAngle); // Skurps stream->read(&maxProneLookAngle); // Skurps + stream->read(&maxTimeScale); stream->read(&mass); @@ -1432,19 +1515,28 @@ void PlayerData::unpackData(BitStream* stream) stream->read(&swimForce); stream->read(&maxUnderwaterForwardSpeed); stream->read(&maxUnderwaterBackwardSpeed); - stream->read(&maxUnderwaterSideSpeed); + stream->read(&maxUnderwaterSideSpeed); + stream->read(&swimYawScale); //Skurps + stream->read(&swimPitchScale); //Skurps // Crouching stream->read(&crouchForce); stream->read(&maxCrouchForwardSpeed); stream->read(&maxCrouchBackwardSpeed); stream->read(&maxCrouchSideSpeed); + stream->read(&crouchYawScale); //Skurps + stream->read(&crouchPitchScale); //Skurps // Prone stream->read(&proneForce); stream->read(&maxProneForwardSpeed); stream->read(&maxProneBackwardSpeed); stream->read(&maxProneSideSpeed); + stream->read(&proneInSequenceTime); //Skurps + stream->read(&proneDiveSequenceTime); //Skurps + stream->read(&proneOutSequenceTime); //Skurps + stream->read(&proneYawScale); //Skurps + stream->read(&pronePitchScale); //Skurps // Jetting stream->read(&jetJumpForce); @@ -1598,10 +1690,13 @@ Player::Player() mRot = mDelta.rot; mHead = mDelta.head; mVelocity.set(0.0f, 0.0f, 0.0f); + mAngularVelocity.set(0.0f,0.0f,0.0f); //Skurps + mAnimVelocity.set(0.0f,0.0f,0.0f); //Skurps mDataBlock = 0; mHeadHThread = mHeadVThread = mRecoilThread = mImageStateThread = 0; mArmAnimation.action = PlayerData::NullAnimation; mArmAnimation.thread = 0; + mActionAnimation.action = PlayerData::NullAnimation; mActionAnimation.thread = 0; mActionAnimation.delayTicks = 0; @@ -1877,7 +1972,7 @@ bool Player::onNewDataBlock( GameBaseData *dptr, bool reload ) // Reset the image state driven animation thread. This will be properly built // in onImageStateAnimation() when needed. mImageStateThread = 0; - + // Initialize the primary thread, the actual sequence is // set later depending on player actions. mActionAnimation.action = PlayerData::NullAnimation; @@ -2084,11 +2179,8 @@ void Player::processTick(const Move* move) mDelta.pos += mDelta.warpOffset; mDelta.rot += mDelta.rotOffset; - // Wrap yaw to +/-PI - if (mDelta.rot.z < - M_PI_F) - mDelta.rot.z += M_2PI_F; - else if (mDelta.rot.z > M_PI_F) - mDelta.rot.z -= M_2PI_F; + // Wrap yaw to +/-PI + mDelta.rot.z = mWrapF(mDelta.rot.z, -M_PI_F, M_PI_F); if (!ignore_updates) { @@ -2140,6 +2232,7 @@ void Player::processTick(const Move* move) updateState(); updateMove(move); updateLookAnimation(); + updateDeathOffsets(); updatePos(); } @@ -2255,8 +2348,7 @@ void Player::setState(ActionState state, U32 recoverTicks) if (isProperlyAdded()) { switch (state) { case RecoverState: { - if (mDataBlock->landSequenceTime > 0.0f) - { + if (mDataBlock->landSequenceTime > 0.0f){ PlayerData::ActionAnimation& anim = mDataBlock->actionList[PlayerData::LandAnim]; if (anim.sequence != -1) { @@ -2276,12 +2368,72 @@ void Player::setState(ActionState state, U32 recoverTicks) } break; } - + case ProneRecoverState: { // Skurps + F32 seqTime = 0.0f; + S32 action = -1; + bool ProneIn = mPose == PronePose ? true : false; + VectorF vel; + mWorldToObj.mulV(mVelocity, &vel); + + // Prone In + if (vel.lenSquared() > 0.01f && ProneIn) { + PlayerData::ActionAnimation& anim = mDataBlock->actionList[PlayerData::DiveAnim]; + if (anim.sequence != -1) { + action = PlayerData::DiveAnim; + seqTime = mDataBlock->proneDiveSequenceTime; + } + } + + // Default to ProneIn if Dive failed + if (action == -1 && ProneIn) { + PlayerData::ActionAnimation& anim = mDataBlock->actionList[PlayerData::ProneInAnim]; + if (anim.sequence != -1) { + action = PlayerData::ProneInAnim; + seqTime = mDataBlock->proneInSequenceTime; + } + } + + // Prone Out + if(!ProneIn){ + PlayerData::ActionAnimation& anim = mDataBlock->actionList[PlayerData::ProneOutAnim]; + if (anim.sequence != -1) { + action = PlayerData::ProneOutAnim; + seqTime = mDataBlock->proneOutSequenceTime; + } + } + + if (action != -1 && seqTime > 0.0f) { + setActionThread(action, true, false, true, true); + if (mActionAnimation.thread && mActionAnimation.thread->getSequence()) { + F32 seqLength = mActionAnimation.thread->getSequence()->duration; + F32 timeScale = seqLength / seqTime; + mShapeInstance->setTimeScale(mActionAnimation.thread, timeScale); + + // No move input is allowed during proneRecoverState but we might want some animation driven velocity... + mAnimVelocity.zero(); + if (mShapeInstance && mActionAnimation.thread){ + PlayerData::ActionAnimation &anim = mDataBlock->actionList[mActionAnimation.action]; + if (anim.sequence != -1){ + Point3F groundVel = ((anim.speed * mShapeInstance->getTimeScale(mActionAnimation.thread)) * anim.dir); + + // Convert from object-space to world-space. + MatrixF rot(EulerF(0, 0, mRot.z)); + rot.mulV(groundVel); + + // Move the player with this velocity during the proneRecoverState + mAnimVelocity = groundVel; + } + } + } + } + // Set delay; if nothing valid, mRecoverDelay = 0 (instant pass) + mRecoverDelay = seqTime; + } + default: break; } } - mState = state; } } @@ -2335,7 +2487,10 @@ void Player::updateState() } } break; - + case ProneRecoverState: //Skurps + mRecoverDelay -= TickSec; + if(mRecoverDelay <= 0.0f) + setState(MoveState); default: break; } @@ -2349,6 +2504,9 @@ const char* Player::getStateName() return "Mounted"; if (mState == RecoverState) return "Recover"; + if (mState == ProneRecoverState) + return "ProneRecover"; + return "Move"; } @@ -2502,11 +2660,17 @@ void Player::setPose( Pose pose ) // Initialize our scaled attributes as well... onScaleChanged(); - + // Resize the PhysicsPlayer rep. should we have one if ( mPhysicsRep ) mPhysicsRep->setSpacials( getPosition(), boxSize ); + + // Trigger Prone Recover State -Skurps + if(mPose == PronePose || oldPose == PronePose){ + setState(ProneRecoverState); + } + if ( isServerObject() ) mDataBlock->onPoseChange_callback( this, EngineMarshallData< PlayerPose >(oldPose), EngineMarshallData< PlayerPose >(mPose)); } @@ -2566,7 +2730,7 @@ void Player::updateMove(const Move* move) // Is waterCoverage high enough to be 'swimming'? { - bool swimming = mWaterCoverage > 0.65f && canSwim(); + bool swimming = canSwim(); //Skurps if ( swimming != mSwimming ) { @@ -2727,7 +2891,28 @@ void Player::updateMove(const Move* move) if(doStandardMove) { - F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f); + F32 yawScale = 1.0f; //Skurps + F32 pitchScale = 1.0f; //Skurps + switch (mPose){ + case SprintPose:{ + yawScale = mDataBlock->sprintYawScale; + pitchScale = mDataBlock->sprintPitchScale; + } + case CrouchPose:{ + yawScale = mDataBlock->crouchYawScale; + pitchScale = mDataBlock->crouchPitchScale; + } + case PronePose: { + yawScale = mDataBlock->proneYawScale; + pitchScale = mDataBlock->pronePitchScale; + } + case SwimPose: { + yawScale = mDataBlock->swimYawScale; + pitchScale = mDataBlock->swimPitchScale; + } + } + + F32 p = move->pitch * pitchScale; //Skurps if (p > M_PI_F) p -= M_2PI_F; @@ -2735,34 +2920,45 @@ void Player::updateMove(const Move* move) F32 curMinLookAngle = mPose == PronePose ? mDataBlock->minProneLookAngle : mDataBlock->minLookAngle; F32 curMaxLookAngle = mPose == PronePose ? mDataBlock->maxProneLookAngle : mDataBlock->maxLookAngle; - mHead.x = mClampF(mHead.x + p,curMinLookAngle, - curMaxLookAngle); // Skurps + mHead.x = mClampF(mHead.x + p,curMinLookAngle, curMaxLookAngle); // Skurps - F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f); + F32 y = move->yaw * yawScale; //Skurps if (y > M_PI_F) y -= M_2PI_F; if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson()))) { - mHead.z = mClampF(mHead.z + y, - -mDataBlock->maxFreelookAngle, - mDataBlock->maxFreelookAngle); + mHead.z = mClampF(mHead.z + y, -mDataBlock->maxFreelookAngle, mDataBlock->maxFreelookAngle); + mAngularVelocity.z = 0.0f; //Skurps } else { - mRot.z += y; - // Rotate the head back to the front, center horizontal - // as well if we're controlling another object. - mHead.z *= 0.5f; - if (mControlObject) - mHead.x *= 0.5f; + mRot.z += y; + // --- Begin angular velocity calculation --- Skurps + F32 prevYaw = mRot.z - y; // store the previous yaw + F32 deltaYaw = mRot.z - prevYaw; + deltaYaw = mWrapF(deltaYaw,-M_PI_F, M_PI_F); + + // store angular velocity in radians/sec + mAngularVelocity.z = deltaYaw / TickSec; + // --- End angular velocity calculation --- + + // Rotate the head back to the front, center horizontal + // as well if we're controlling another object. + mHead.z *= 0.5f; + if (mControlObject) + mHead.x *= 0.5f; } // constrain the range of mRot.z + mRot.z = mWrapF(mRot.z, 0.0f, M_2PI_F); + + /* while (mRot.z < 0.0f) mRot.z += M_2PI_F; while (mRot.z > M_2PI_F) mRot.z -= M_2PI_F; + */ } mDelta.rot = mRot; @@ -2854,6 +3050,11 @@ void Player::updateMove(const Move* move) || mActionAnimation.action == PlayerData::LandAnim)) mActionAnimation.action = PlayerData::NullAnimation; } + else if (mState == ProneRecoverState){ // Use the velocity from the animation during ProneRecoverState -Skurps + moveSpeed = mAnimVelocity.len(); + moveVec = mAnimVelocity; + moveVec.normalize(); + } else { moveVec.set(0.0f, 0.0f, 0.0f); @@ -3026,19 +3227,26 @@ void Player::updateMove(const Move* move) // get the head pitch and add it to the moveVec // This more accurate swim vector calc comes from Matt Fairfax - MatrixF xRot; - xRot.set(EulerF(mHead.x, 0, 0)); - zRot.set(EulerF(0, 0, mRot.z)); - MatrixF rot; - rot.mul(zRot, xRot); - rot.getColumn(0,&moveVec); - - moveVec *= move->x; - VectorF tv; - rot.getColumn(1,&tv); - moveVec += tv * move->y; - rot.getColumn(2,&tv); - moveVec += tv * move->z; + // Added a check to keep the player from pose-jittering at the surface -Skurps + F32 offset = getPosition().z + (0.66f * mDataBlock->swimBoxSize.z); + bool rising = (move->y > 0.0f && mHead.x < 0.0f) || (move->y < 0.0f && mHead.x > 0.0f); + bool skipPitch = (offset > mLiquidHeight) && rising; //Skip pitch contribution to velocity -Skurps + + if(!skipPitch){ //Skurps + MatrixF xRot; + xRot.set(EulerF(mHead.x, 0, 0)); + zRot.set(EulerF(0, 0, mRot.z)); + MatrixF rot; + rot.mul(zRot, xRot); + rot.getColumn(0,&moveVec); + + moveVec *= move->x; + VectorF tv; + rot.getColumn(1,&tv); + moveVec += tv * move->y; + rot.getColumn(2,&tv); + moveVec += tv * move->z; + } // Force a 0 move if there is no energy, and only drain // move energy if we're moving. @@ -3211,7 +3419,7 @@ void Player::updateMove(const Move* move) // Adjust velocity with all the move & gravity acceleration // TG: I forgot why doesn't the TickSec multiply happen here... mVelocity += acc; - + // apply horizontal air resistance F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y); @@ -3287,7 +3495,7 @@ void Player::updateMove(const Move* move) { if ( mSwimming ) desiredPose = SwimPose; - else if ( runSurface && move->trigger[sProneTrigger] && canProne() ) //Skurps swapped with crouch so crouch does not need to be released in order to go prone + else if ( move->trigger[sProneTrigger] && canProne() ) //Skurps swapped with crouch so crouch does not need to be released in order to go prone desiredPose = PronePose; else if ( runSurface && move->trigger[sCrouchTrigger] && canCrouch() ) desiredPose = CrouchPose; @@ -3364,8 +3572,8 @@ bool Player::canJetJump() bool Player::canSwim() { - // Make sure swim bounding box would be submerged enough go to swim pose, necessary when crouched or prone in shallow water - Skurps - return mAllowSwimming && ((getPosition().z + mDataBlock->swimBoxSize.z) < mLiquidHeight); + // Make sure swim bounding box is/would be submerged enough for swim pose- Skurps + return mAllowSwimming && ((getPosition().z + (0.65f * mDataBlock->swimBoxSize.z)) < mLiquidHeight); } //Fixed to work with small boxsize.z values - Skurps @@ -3460,28 +3668,23 @@ bool Player::canStand() //Fixed to work with small boxsize.z values - Skurps return mPhysicsRep->testSpacials( getPosition(), mDataBlock->boxSize ); } -bool Player::canProne() -{ - if (!mAllowProne) +bool Player::canProne(){ + if (!mAllowProne || mDamageState != Enabled || isMounted() || mSwimming || mFalling) return false; - if ( mState != MoveState || - mDamageState != Enabled || - isMounted() || - mSwimming || - mFalling ) + if (mState != MoveState && mState != ProneRecoverState) //Skurps return false; // Can't go prone if no prone animation! if ( mDataBlock->actionList[PlayerData::ProneRootAnim].sequence == -1 ) return false; - // Do standard Torque physics test here! - if ( !mPhysicsRep ) + // We are already in this pose, so don't test it again... + if ( mPose == PronePose) return true; - // We are already in this pose, so don't test it again... - if ( mPose == PronePose ) + // Do standard Torque physics test here! + if ( !mPhysicsRep ) return true; return mPhysicsRep->testSpacials( getPosition(), mDataBlock->proneBoxSize ); @@ -3542,19 +3745,16 @@ void Player::updateLookAnimation(F32 dt) // Adjust look pos. This assumes that the animations match // the min and max look angles provided in the datablock. if (mArmAnimation.thread) - { - // Skurps - F32 curMinLookAngle = mPose == PronePose ? mDataBlock->minProneLookAngle : mDataBlock->minLookAngle; - F32 curMaxLookAngle = mPose == PronePose ? mDataBlock->maxProneLookAngle : mDataBlock->maxLookAngle; - + { if(mControlObject) { mShapeInstance->setPos(mArmAnimation.thread,0.5f); } + // Calculations assume maxLookAngle and minLookAngle range is >= than maxProneLookAngle and minProneLookAngle range else { - F32 d = curMaxLookAngle - curMinLookAngle; //Skurps - F32 tp = (renderHead.x - curMinLookAngle) / d; //Skurps + F32 d = mDataBlock->maxLookAngle - mDataBlock->minLookAngle; + F32 tp = (renderHead.x - mDataBlock->minLookAngle) / d; mShapeInstance->setPos(mArmAnimation.thread,mClampF(tp,0,1)); } @@ -3575,10 +3775,8 @@ void Player::updateLookAnimation(F32 dt) } } - //---------------------------------------------------------------------------- // Methods to get delta (as amount to affect velocity by) - bool Player::inDeathAnim() { if ((anim_clip_flags & ANIM_OVERRIDDEN) != 0 && (anim_clip_flags & IS_DEATH_ANIM) == 0) @@ -3841,14 +4039,16 @@ void Player::setActionThread(U32 action,bool forward,bool hold,bool wait,bool fs mActionAnimation.delayTicks = (S32)sNewAnimationTickTime; mActionAnimation.atEnd = false; mActionAnimation.callbackTripped = false; - if (sUseAnimationTransitions && (action != PlayerData::LandAnim || !(mDataBlock->landSequenceTime > 0.0f && !mDataBlock->transitionToLand)) && (isGhost()/* || mActionAnimation.animateOnServer*/)) + if (sUseAnimationTransitions && (action != PlayerData::LandAnim || !(mDataBlock->landSequenceTime > 0.0f && !mDataBlock->transitionToLand)) && (isGhost() || mActionAnimation.animateOnServer)) { // The transition code needs the timeScale to be set in the // right direction to know which way to go. - F32 transTime = sAnimationTransitionTime; + F32 transTime = sAnimationTransitionTime; if (mDataBlock && mDataBlock->isJumpAction(action)) transTime = 0.15f; - + else if (mDataBlock && (mDataBlock->isTurnAction(action) || mDataBlock->isTurnAction(lastAction))) //Skurps + transTime = 0.35f; + F32 timeScale = mActionAnimation.forward ? 1.0f : -1.0f; if (mDataBlock && mDataBlock->isJumpAction(action)) timeScale *= 1.5f; @@ -4020,23 +4220,30 @@ void Player::updateActionThread() // prevent scaling of AFX picked actions if ( (mActionAnimation.action != PlayerData::LandAnim) && (mActionAnimation.action != PlayerData::NullAnimation) && - !(anim_clip_flags & ANIM_OVERRIDDEN)) - { - // Update action animation time scale to match ground velocity - PlayerData::ActionAnimation &anim = - mDataBlock->actionList[mActionAnimation.action]; - F32 scale = 1; - if (anim.velocityScale && anim.speed) { - VectorF vel; - mWorldToObj.mulV(mVelocity,&vel); - scale = mFabs(mDot(vel, anim.dir) / anim.speed); + !(anim_clip_flags & ANIM_OVERRIDDEN) && (mActionAnimation.action != PlayerData::ProneOutAnim) && (mActionAnimation.action != PlayerData::ProneInAnim) + && (mActionAnimation.action != PlayerData::DiveAnim)) // ProneIn/ProneOut/Dive excempt because their duration / scale is determined by datablock values -Skurps + { + // Update action animation time scale to match ground velocity + PlayerData::ActionAnimation &anim = mDataBlock->actionList[mActionAnimation.action]; + F32 scale = 1.0f; + F32 rotScale = 1.0f; //Skurps + + // Linear animation scaling + if (anim.velocityScale && anim.speed) { + VectorF vel; + mWorldToObj.mulV(mVelocity,&vel); + scale = mFabs(mDot(vel, anim.dir) / anim.speed); + } - if (scale > mDataBlock->maxTimeScale) - scale = mDataBlock->maxTimeScale; - } + // Angular animation scaling -Skurps + if (mFabs(mAngularVelocity.z) && anim.angularSpeed != 0.0f){ + F32 yawPerFrame = mAngularVelocity.z * TickSec; + rotScale = mFabs(yawPerFrame / anim.angularSpeed); + } - mShapeInstance->setTimeScale(mActionAnimation.thread, - mActionAnimation.forward? scale: -scale); + F32 finalScale = mMax(scale,rotScale); // Use the greater scale -Skurps + finalScale = mClampF(finalScale,0.0f,mDataBlock->maxTimeScale); + mShapeInstance->setTimeScale(mActionAnimation.thread, mActionAnimation.forward? finalScale: -finalScale); } PROFILE_END(); } @@ -4049,16 +4256,17 @@ void Player::pickBestMoveAction(U32 startAnim, U32 endAnim, U32 * action, bool * VectorF vel; mWorldToObj.mulV(mVelocity,&vel); - if (vel.lenSquared() > 0.01f) - { + bool isMoving = vel.lenSquared() > 0.01f; //Skurps + bool isTurning = mFabs(mAngularVelocity.z) > 0.35f; //Skurps + + // Pick animation that is the best fit for our current (local) velocity + // Assumes that the root (stationary) animation is at startAnim. + if(isMoving){ // Bias the velocity towards picking the forward/backward anims over - // the sideways ones to prevent oscillation between anims. + // the sideways ones to prevent oscillation between anims. vel *= VectorF(0.5f, 1.0f, 0.5f); - - // Pick animation that is the best fit for our current (local) velocity. - // Assumes that the root (stationary) animation is at startAnim. F32 curMax = -0.1f; - for (U32 i = startAnim+1; i <= endAnim; i++) + for (U32 i = startAnim +1; i <= endAnim; i++) { const PlayerData::ActionAnimation &anim = mDataBlock->actionList[i]; if (anim.sequence != -1 && anim.speed) @@ -4086,6 +4294,35 @@ void Player::pickBestMoveAction(U32 startAnim, U32 endAnim, U32 * action, bool * } } } + // Pick animation that is the best fit for current angularVelocity. Checks only side anims and turn-in-place anims, defaults to root if no match. -Skurps + else if (isTurning){ + F32 curMax = 0.0f; + for (U32 i = startAnim +3; i <= endAnim; i++) + { + const PlayerData::ActionAnimation &anim = mDataBlock->actionList[i]; + if (anim.sequence != -1 && anim.angularSpeed) + { + F32 d = mAngularVelocity.z * anim.angularSpeed; + if (d > curMax) + { + curMax = d; + *action = i; + *forward = true; + } + else + { + // Check if reversing this animation would fit (as above) + d *= -0.75f; + if (d > curMax) + { + curMax = d; + *action = i; + *forward = false; + } + } + } + } + } } void Player::pickActionAnimation() @@ -4106,7 +4343,6 @@ void Player::pickActionAnimation() bool forward = true; U32 action = PlayerData::RootAnim; - bool fsp = false; // Jetting overrides the fall animation condition if (mJetting) @@ -4133,22 +4369,22 @@ void Player::pickActionAnimation() else { // Our feet are on something - pickBestMoveAction(PlayerData::RootAnim, PlayerData::SideRightAnim, &action, &forward); + pickBestMoveAction(PlayerData::RootAnim, PlayerData::TurnRightAnim, &action, &forward); } } else if ( mPose == CrouchPose ) { - pickBestMoveAction(PlayerData::CrouchRootAnim, PlayerData::CrouchRightAnim, &action, &forward); + pickBestMoveAction(PlayerData::CrouchRootAnim, PlayerData::CrouchTurnRightAnim, &action, &forward); } else if ( mPose == PronePose ) { - pickBestMoveAction(PlayerData::ProneRootAnim, PlayerData::ProneRightAnim, &action, &forward); //Skurps + pickBestMoveAction(PlayerData::ProneRootAnim, PlayerData::ProneTurnRightAnim, &action, &forward); //Skurps } else if ( mPose == SprintPose ) { pickBestMoveAction(PlayerData::SprintRootAnim, PlayerData::SprintRightAnim, &action, &forward); } - setActionThread(action,forward,false,false,fsp); + setActionThread(action,forward,false,false,false); } void Player::onImage(U32 imageSlot, bool unmount) @@ -5565,7 +5801,6 @@ bool Player::displaceObject(const Point3F& displacement) #endif //---------------------------------------------------------------------------- - void Player::setPosition(const Point3F& pos,const Point3F& rot) { MatrixF mat; @@ -6319,7 +6554,7 @@ void Player::readPacketData(GameConnection *connection, BitStream *stream) if (stream->readFlag()) mJumpDelay = stream->readInt(PlayerData::JumpDelayBits); else - mJumpDelay = 0; + mJumpDelay = 0.0f; Point3F pos,rot; if (stream->readFlag()) { @@ -6589,10 +6824,7 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream) mDelta.rotOffset.z = 0; // Wrap rotation to +/-PI - if(mDelta.rotOffset.z < - M_PI_F) - mDelta.rotOffset.z += M_2PI_F; - else if(mDelta.rotOffset.z > M_PI_F) - mDelta.rotOffset.z -= M_2PI_F; + mDelta.rotOffset.z = mWrapF(mDelta.rotOffset.z, -M_PI_F, M_PI_F); mDelta.rotOffset /= (F32)mDelta.warpTicks; } @@ -6753,8 +6985,9 @@ DefineEngineMethod( Player, getState, const char*, (),, "
  • Mounted - The Player is mounted to an object such as a vehicle.
  • " "
  • Move - The Player is free to move. The usual state.
  • " "
  • Recover - The Player is recovering from a fall. See PlayerData::recoverDelay.
  • \n" + "
  • ProneRecover - The Player is getting in / out of prone. See PlayerData::proneRecoverDelay.
  • \n" //Skurps - "@return The current state; one of: \"Dead\", \"Mounted\", \"Move\", \"Recover\"\n" ) + "@return The current state; one of: \"Dead\", \"Mounted\", \"Move\", \"Recover\",\"ProneRecover\"\n" ) { return object->getStateName(); } @@ -6866,6 +7099,8 @@ DefineEngineMethod( Player, setActionThread, bool, ( const char* name, bool hold "
  • prone_root
  • " "
  • prone_forward
  • " "
  • prone_backward
  • " + "
  • prone_side
  • " + "
  • prone_right
  • " "
  • swim_root
  • " "
  • swim_forward
  • " "
  • swim_backward
  • " @@ -6875,7 +7110,10 @@ DefineEngineMethod( Player, setActionThread, bool, ( const char* name, bool hold "
  • jump
  • " "
  • standjump
  • " "
  • land
  • " - "
  • jet
  • \n\n" + "
  • jet
  • " + "
  • proneIn
  • " + "
  • proneOut
  • " + "
  • dive
  • \n\n" "If the player moves in any direction then the animation sequence set using this " "method will be cancelled and the chosen mation-based sequence will take over. This makes " @@ -7226,7 +7464,6 @@ void Player::updateSplash() } } - //-------------------------------------------------------------------------- void Player::updateFroth( F32 dt ) diff --git a/Engine/source/T3D/player.h b/Engine/source/T3D/player.h index af9477fd8c..53fcc051e4 100644 --- a/Engine/source/T3D/player.h +++ b/Engine/source/T3D/player.h @@ -97,9 +97,8 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i F32 maxLookAngle; ///< Highest angle (radians) the player can look F32 maxFreelookAngle; ///< Max left/right angle the player can look - F32 minProneLookAngle; /// Skurps - F32 maxProneLookAngle; /// Skurps - + F32 minProneLookAngle; //< Lowest angle (radians) the player can look when prone. Should be >= minLookAngle. -Skurps + F32 maxProneLookAngle; ///< Highest angle (radians) the player can look when prone. Should be <= maxLookAngle. -Skurps /// @name Physics constants /// @{ @@ -125,6 +124,10 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i /// sequence's playback will be scaled to match. bool transitionToLand; ///< When going from a fall to a land, should we transition between the two? + F32 proneInSequenceTime; ///< Time for getting in prone, proneIn sequence is scaled to match this-Skurps + F32 proneDiveSequenceTime; ///< Time for diving into prone, dive sequence is scaled to match this-Skurps + F32 proneOutSequenceTime; ///< Time for getting up from prone, proneOut sequence is scaled to match this-Skurps + // Running/Walking F32 runForce; ///< Force used to accelerate player F32 runEnergyDrain; ///< Energy drain/tick @@ -159,18 +162,24 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i F32 maxUnderwaterForwardSpeed; ///< Maximum underwater forward speed when running F32 maxUnderwaterBackwardSpeed; ///< Maximum underwater backward speed when running F32 maxUnderwaterSideSpeed; ///< Maximum underwater side speed when running + F32 swimYawScale; ///< Amount to scale yaw motion while swimming -Skurps + F32 swimPitchScale; ///< Amount to scale pitch motion while swimming -Skurps // Crouching F32 crouchForce; ///< Force used to accelerate player while crouching F32 maxCrouchForwardSpeed; ///< Maximum forward speed when crouching F32 maxCrouchBackwardSpeed; ///< Maximum backward speed when crouching F32 maxCrouchSideSpeed; ///< Maximum side speed when crouching + F32 crouchYawScale; ///< Amount to scale yaw motion while crouching -Skurps + F32 crouchPitchScale; ///< Amount to scale pitch motion while crouching -Skurps // Prone F32 proneForce; ///< Force used to accelerate player while prone F32 maxProneForwardSpeed; ///< Maximum forward speed when prone F32 maxProneBackwardSpeed; ///< Maximum backward speed when prone F32 maxProneSideSpeed; ///< Maximum side speed when prone + F32 proneYawScale; ///< Amount to scale yaw motion while prone -Skurps + F32 pronePitchScale; ///< Amount to scale pitch motion while prone -Skurps // Jetting F32 jetJumpForce; @@ -227,7 +236,7 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i ImpactWaterMedium, ImpactWaterHard, ExitWater, - Crawl,//Skurps + Crawl,//Skurps MaxSounds }; @@ -252,6 +261,7 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i F32 speed; ///< Speed in m/s bool velocityScale; ///< Scale animation by velocity bool death; ///< Are we dying? + F32 angularSpeed; ///< Radians per frame -Skurps }; enum { // *** WARNING *** @@ -263,6 +273,8 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i BackBackwardAnim, SideLeftAnim, SideRightAnim, + TurnLeftAnim, //Skurps + TurnRightAnim, //Skurps SprintRootAnim, SprintForwardAnim, @@ -275,12 +287,16 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i CrouchBackwardAnim, CrouchLeftAnim, CrouchRightAnim, + CrouchTurnLeftAnim, //Skurps + CrouchTurnRightAnim, //Skurps ProneRootAnim, ProneForwardAnim, ProneBackwardAnim, - ProneLeftAnim, //Skurps + ProneLeftAnim, //Skurps ProneRightAnim, //Skurps + ProneTurnLeftAnim, //Skurps + ProneTurnRightAnim, //Skurps SwimRootAnim, SwimForwardAnim, @@ -294,13 +310,15 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i StandJumpAnim, LandAnim, JetAnim, + ProneInAnim, //Skurps + ProneOutAnim, //Skurps + DiveAnim, //Skurps - // - NumTableActionAnims = JetAnim + 1, + NumTableActionAnims = DiveAnim + 1, //Skurps NumExtraActionAnims = 512 - NumTableActionAnims, NumActionAnims = NumTableActionAnims + NumExtraActionAnims, - ActionAnimBits = 9, + ActionAnimBits = 9, NullAnimation = (1 << ActionAnimBits) - 1 }; int mDynamicAnimsStart; @@ -374,6 +392,7 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i void getGroundInfo(TSShapeInstance*,TSThread*,ActionAnimation*); bool isTableSequence(S32 seq); bool isJumpAction(U32 action); + bool isTurnAction(U32 action);//Skurps static void initPersistFields(); void packData(BitStream* stream) override; @@ -469,6 +488,8 @@ class Player: public ShapeBase Point3F mHead; ///< Head rotation, uses only x & z Point3F mRot; ///< Body rotation, uses only z VectorF mVelocity; ///< Velocity + VectorF mAngularVelocity; ///< Angular Velocity (only z), Radians / Sec - Skurps + VectorF mAnimVelocity; ///< Skurps Point3F mAnchorPoint; ///< Pos compression anchor S32 mImpactSound; @@ -486,6 +507,7 @@ class Player: public ShapeBase NullState, MoveState, RecoverState, + ProneRecoverState, // Skurps NumStateBits = 3 }; ActionState mState; ///< What is the player doing? @see ActionState @@ -538,14 +560,16 @@ class Player: public ShapeBase TSThread* mHeadHThread; TSThread* mRecoilThread; TSThread* mImageStateThread; + /// @} bool mInMissionArea; ///< Are we in the mission area? // S32 mRecoverTicks; ///< same as recoverTicks in the player datablock + U32 mReversePending; F32 mRecoverDelay; ///< When bypassing the legacy recover system and only using the land sequence, - /// this is how long the player will be in the land sequence. + /// this is how long the player will be in the land sequence. Also used by proneRecoverState. -Skurps bool mInWater; ///< Is true if WaterCoverage is greater than zero bool mSwimming; ///< Is true if WaterCoverage is above the swimming threshold @@ -644,7 +668,7 @@ class Player: public ShapeBase virtual void updateAttachment(); // PATHSHAPE END ///Update head animation - void updateLookAnimation(F32 dT = 0.f); + void updateLookAnimation(F32 dt = 0.0f); ///Update other animations void updateAnimation(F32 dt);