Update player.cpp

1.added min and max prone look angle to datablock
2.added crawlsound, triggered like footsteps by animation trigger 3
3.added missing code for prone_side and prone_right animations
4.replaced box left/right/back/front head percentages with torso percentages, makes more sense for general use.
5.getDamageLocation() overhauled for better results in every pose
6.tweak to canSwim() to make sure player is actually submerged enough for the swim bounding box
7.fixed canCrouch(), canProne(), and canStand() calculations to work with lower boxSize.z values.
8.swapped order of canCrouch() and canProne() checks crouch so crouch does not need to be released in order to go prone  (allows for scripting momentary crouch but toggle prone type setup if desired)
9.Added an engineMethod to check canProne() from script
10.tweaked canSprint to not allow if mWaterCoverage > 0.5
This commit is contained in:
Sir-Skurpsalot 2026-04-14 21:35:46 -06:00 committed by GitHub
parent 12dddd07b5
commit 08bda4008b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -170,6 +170,8 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni
{ "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
{ "swim_root" },
{ "swim_forward", { 0.0f, 1.0f, 0.0f } },
@ -185,7 +187,6 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni
{ "jet" }, // JetAnim
};
//----------------------------------------------------------------------------
typedef PlayerData::Sounds playerSoundsEnum;
@ -211,6 +212,7 @@ ImplementEnumType(playerSoundsEnum, "enum types.\n"
{ playerSoundsEnum::ImpactWaterMedium, "ImpactWaterMedium","..." },
{ playerSoundsEnum::ImpactWaterHard, "ImpactWaterHard","..." },
{ playerSoundsEnum::ExitWater, "ExitWater","..." },
{ playerSoundsEnum::Crawl, "Crawl","..." }, //Skurps
EndImplementEnumType;
//----------------------------------------------------------------------------
@ -305,6 +307,8 @@ PlayerData::PlayerData()
pickupRadius = 0.0f;
minLookAngle = -1.4f;
maxLookAngle = 1.4f;
minProneLookAngle = -.3491f; // Skurps
maxProneLookAngle = .3491f; // Skurps
maxFreelookAngle = 3.0f;
maxTimeScale = 1.5f;
@ -416,10 +420,10 @@ PlayerData::PlayerData()
boxTorsoPercentage = 0.55f;
// damage locations
boxHeadLeftPercentage = 0;
boxHeadRightPercentage = 1;
boxHeadBackPercentage = 0;
boxHeadFrontPercentage = 1;
boxTorsoLeftPercentage = 0; //Skurps replaced left/right/front/back head percentages
boxTorsoRightPercentage = 1; //Skurps
boxTorsoBackPercentage = 0; //Skurps
boxTorsoFrontPercentage = 1; //Skurps
for (S32 i = 0; i < MaxSounds; i++)
INIT_SOUNDASSET_ARRAY(PlayerSound, i);
@ -736,6 +740,14 @@ void PlayerData::initPersistFields()
addFieldV( "maxFreelookAngle", TypeRangedF32, Offset(maxFreelookAngle, PlayerData), &CommonValidators::PositiveFloat,
"@brief Defines the maximum left and right angles (in radians) the player can "
"look in freelook mode.\n\n" );
addField( "minProneLookAngle", TypeF32, Offset(minProneLookAngle, PlayerData),
"@brief Lowest angle (in radians) the player can look when Prone.\n\n"
"@note An angle of zero is straight ahead, with positive up and negative down." ); //Skurps
addField( "maxProneLookAngle", TypeF32, Offset(maxProneLookAngle, PlayerData),
"@brief Highest angle (in radians) the player can look when Prone.\n\n"
"@note An angle of zero is straight ahead, with positive up and negative down." ); //Skurps
endGroup( "Camera" );
@ -992,28 +1004,29 @@ void PlayerData::initPersistFields()
"@brief Collision bounding box used when the player is swimming.\n\n"
"@see boundingBox" );
addFieldV( "boxHeadPercentage", TypeRangedF32, Offset(boxHeadPercentage, PlayerData), &CommonValidators::NormalizedFloat,
// Damage collision boxes changed by Skurps
addField( "boxHeadPercentage", TypeF32, Offset(boxHeadPercentage, PlayerData),
"@brief Percentage of the player's bounding box height that represents the head.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
addFieldV( "boxTorsoPercentage", TypeRangedF32, Offset(boxTorsoPercentage, PlayerData), &CommonValidators::NormalizedFloat,
addField( "boxTorsoPercentage", TypeF32, Offset(boxTorsoPercentage, PlayerData),
"@brief Percentage of the player's bounding box height that represents the torso.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
addFieldV( "boxHeadLeftPercentage", TypeRangedF32, Offset(boxHeadLeftPercentage, PlayerData), &CommonValidators::NormalizedFloat,
"@brief Percentage of the player's bounding box width that represents the left side of the head.\n\n"
addField( "boxTorsoLeftPercentage", TypeF32, Offset(boxTorsoLeftPercentage, PlayerData),
"@brief Percentage of the player's bounding box width that represents the left side of the torso.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
addFieldV( "boxHeadRightPercentage", TypeRangedF32, Offset(boxHeadRightPercentage, PlayerData), &CommonValidators::NormalizedFloat,
"@brief Percentage of the player's bounding box width that represents the right side of the head.\n\n"
addField( "boxTorsoRightPercentage", TypeF32, Offset(boxTorsoRightPercentage, PlayerData),
"@brief Percentage of the player's bounding box width that represents the right side of the torso.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
addFieldV( "boxHeadBackPercentage", TypeRangedF32, Offset(boxHeadBackPercentage, PlayerData), &CommonValidators::NormalizedFloat,
"@brief Percentage of the player's bounding box depth that represents the back side of the head.\n\n"
addField( "boxTorsoBackPercentage", TypeF32, Offset(boxTorsoBackPercentage, PlayerData),
"@brief Percentage of the player's bounding box depth that represents the back side of the torso.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
addFieldV( "boxHeadFrontPercentage", TypeRangedF32, Offset(boxHeadFrontPercentage, PlayerData), &CommonValidators::NormalizedFloat,
"@brief Percentage of the player's bounding box depth that represents the front side of the head.\n\n"
addField( "boxTorsoFrontPercentage", TypeF32, Offset(boxTorsoFrontPercentage, PlayerData),
"@brief Percentage of the player's bounding box depth that represents the front side of the torso.\n\n"
"Used when computing the damage location.\n"
"@see Player::getDamageLocation" );
@ -1174,6 +1187,8 @@ void PlayerData::packData(BitStream* stream)
stream->write(minLookAngle);
stream->write(maxLookAngle);
stream->write(maxFreelookAngle);
stream->write(minProneLookAngle);//Skurps
stream->write(maxProneLookAngle);//Skurps
stream->write(maxTimeScale);
stream->write(mass);
@ -1356,6 +1371,8 @@ void PlayerData::unpackData(BitStream* stream)
stream->read(&minLookAngle);
stream->read(&maxLookAngle);
stream->read(&maxFreelookAngle);
stream->read(&minProneLookAngle); // Skurps
stream->read(&maxProneLookAngle); // Skurps
stream->read(&maxTimeScale);
stream->read(&mass);
@ -2319,29 +2336,44 @@ const char* Player::getStateName()
return "Move";
}
//Skurps - overhaul
void Player::getDamageLocation(const Point3F& in_rPos, const char *&out_rpVert, const char *&out_rpQuad)
{
// TODO: This will be WRONG when player is prone or swimming!
Point3F newPoint;
mWorldToObj.mulP(in_rPos, &newPoint);
Point3F boxSize = mObjBox.getExtents();
F32 zHeight = boxSize.z;
F32 zTorso = mDataBlock->boxTorsoPercentage;
F32 zHead = mDataBlock->boxHeadPercentage;
F32 yLength = boxSize.y;
F32 torsoLimit = mDataBlock->boxTorsoPercentage;
F32 headLimit = mDataBlock->boxHeadPercentage;
zTorso *= zHeight;
zHead *= zHeight;
if(mPose == PronePose)
{
torsoLimit = (torsoLimit * yLength) - (yLength / 2);
headLimit = (headLimit * yLength) - (yLength / 2);
if (newPoint.z <= zTorso)
out_rpVert = "legs";
else if (newPoint.z <= zHead)
out_rpVert = "torso";
else
out_rpVert = "head";
if(newPoint.y <= torsoLimit)
out_rpVert = "legs";
else if(newPoint.y <= headLimit)
out_rpVert = "torso";
else
out_rpVert = "head";
}
else
{
torsoLimit *= zHeight;
headLimit *= zHeight;
if(String::compare(out_rpVert, "head") != 0)
if (newPoint.z <= torsoLimit)
out_rpVert = "legs";
else if (newPoint.z <= headLimit)
out_rpVert = "torso";
else
out_rpVert = "head";
}
if(dStrcmp(out_rpVert, "torso") != 0)
{
if (newPoint.y >= 0.0f)
{
@ -2360,40 +2392,36 @@ void Player::getDamageLocation(const Point3F& in_rPos, const char *&out_rpVert,
}
else
{
F32 backToFront = boxSize.x;
F32 leftToRight = boxSize.y;
F32 xWidth = boxSize.x;
F32 backPoint = backToFront * mDataBlock->boxHeadBackPercentage;
F32 frontPoint = backToFront * mDataBlock->boxHeadFrontPercentage;
F32 leftPoint = leftToRight * mDataBlock->boxHeadLeftPercentage;
F32 rightPoint = leftToRight * mDataBlock->boxHeadRightPercentage;
//boxTorsoBackPercentage and boxTorsoLeftPercentage should both be negative floats
F32 backPoint = yLength * mDataBlock->boxTorsoBackPercentage;
F32 frontPoint = yLength * mDataBlock->boxTorsoFrontPercentage;
F32 leftPoint = xWidth * mDataBlock->boxTorsoLeftPercentage;
F32 rightPoint = xWidth * mDataBlock->boxTorsoRightPercentage;
S32 index = 0;
if (newPoint.y < backPoint)
index += 0;
else if (newPoint.y >= frontPoint)
S32 index = 0; //Middle hits are cases 0-2
if (newPoint.y < backPoint) //Back hits are cases 3-5
index += 3;
else
else if (newPoint.y >= frontPoint) //Front hits are cases 6-8
index += 6;
if (newPoint.x < leftPoint)
index += 0;
else if (newPoint.x >= rightPoint)
if (newPoint.x < leftPoint) //Base number + 1 is left side
index += 1;
else
else if (newPoint.x >= rightPoint) //Base number + 2 is right side
index += 2;
switch (index)
{
case 0: out_rpQuad = "left_back"; break;
case 1: out_rpQuad = "middle_back"; break;
case 2: out_rpQuad = "right_back"; break;
case 3: out_rpQuad = "left_middle"; break;
case 4: out_rpQuad = "middle_middle"; break;
case 5: out_rpQuad = "right_middle"; break;
case 6: out_rpQuad = "left_front"; break;
case 7: out_rpQuad = "middle_front"; break;
case 8: out_rpQuad = "right_front"; break;
case 0: out_rpQuad = "middle_middle"; break; // "Middle middle" sounds confusing but it is the case that occurs when shot in the back when prone
case 1: out_rpQuad = "middle_left"; break;
case 2: out_rpQuad = "middle_right"; break;
case 3: out_rpQuad = "back_middle"; break;
case 4: out_rpQuad = "back_left"; break;
case 5: out_rpQuad = "back_right"; break;
case 6: out_rpQuad = "front_middle"; break;
case 7: out_rpQuad = "front_left"; break;
case 8: out_rpQuad = "front_right"; break;
default:
AssertFatal(0, "Bad non-tant index");
@ -2686,8 +2714,13 @@ void Player::updateMove(const Move* move)
F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f);
if (p > M_PI_F)
p -= M_2PI_F;
mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
mDataBlock->maxLookAngle);
//Skurps - use different min/max if prone
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
F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f);
if (y > M_PI_F)
@ -3234,11 +3267,11 @@ void Player::updateMove(const Move* move)
if ( !mIsAiControlled )
{
if ( mSwimming )
desiredPose = SwimPose;
else if ( runSurface && move->trigger[sCrouchTrigger] && canCrouch() )
desiredPose = CrouchPose;
else if ( runSurface && move->trigger[sProneTrigger] && canProne() )
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
desiredPose = PronePose;
else if ( runSurface && move->trigger[sCrouchTrigger] && canCrouch() )
desiredPose = CrouchPose;
else if ( move->trigger[sSprintTrigger] && canSprint() )
desiredPose = SprintPose;
else if ( canStand() )
@ -3311,27 +3344,27 @@ bool Player::canJetJump()
}
bool Player::canSwim()
{
// Not used!
//return mState == MoveState && mDamageState == Enabled && !isMounted() && mEnergy >= mDataBlock->minSwimEnergy && mWaterCoverage >= 0.8f;
return mAllowSwimming;
{
// 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);
}
//Fixed to work with small boxsize.z values - Skurps
bool Player::canCrouch()
{
if (!mAllowCrouching)
return false;
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
mSwimming ||
mFalling )
return false;
// Can't crouch if no crouch animation!
if ( mDataBlock->actionList[PlayerData::CrouchRootAnim].sequence == -1 )
return false;
return false;
// We are already in this pose, so don't test it again...
if ( mPose == CrouchPose )
@ -3340,22 +3373,13 @@ bool Player::canCrouch()
// Do standard Torque physics test here!
if ( !mPhysicsRep )
{
F32 radius;
if ( mPose == PronePose )
radius = mDataBlock->proneBoxSize.z;
else
return true;
// use our X and Y dimentions on our boxsize as the radii for our search, and the difference between a standing position
// and the position we currently are in.
Point3F extent( mDataBlock->crouchBoxSize.x / 2, mDataBlock->crouchBoxSize.y / 2, mDataBlock->crouchBoxSize.z - radius );
//Changed from stock because math does not work with small z values -Skurps
Point3F extent( mDataBlock->crouchBoxSize.x / 2, mDataBlock->crouchBoxSize.y / 2, mDataBlock->crouchBoxSize.z / 2);
Point3F position = getPosition();
position.z += radius;
position.z += (mDataBlock->crouchBoxSize.z / 2); //gets a position at the center of proposed crouch box.
// Use these radii to create a box that represents the difference between a standing position and the position
// we want to move into.
// Box shaped like new desired pose
Box3F B(position - extent, position + extent, true);
EarlyOutPolyList polyList;
@ -3376,39 +3400,27 @@ bool Player::canCrouch()
return mPhysicsRep->testSpacials( getPosition(), mDataBlock->crouchBoxSize );
}
bool Player::canStand()
{
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
bool Player::canStand() //Fixed to work with small boxsize.z values - Skurps
{
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
mSwimming )
return false;
// We are already in this pose, so don't test it again...
if ( mPose == StandPose )
if ( mPose == StandPose || mPose == SprintPose || mPose == SwimPose )
return true;
// Do standard Torque physics test here!
if ( !mPhysicsRep )
{
F32 radius;
if (mPose == CrouchPose)
radius = mDataBlock->crouchBoxSize.z;
else if (mPose == PronePose)
radius = mDataBlock->proneBoxSize.z;
else
return true;
// use our X and Y dimentions on our boxsize as the radii for our search, and the difference between a standing position
// and the position we currently are in.
Point3F extent( mDataBlock->boxSize.x / 2, mDataBlock->boxSize.y / 2, mDataBlock->boxSize.z - radius );
Point3F extent( mDataBlock->boxSize.x / 2, mDataBlock->boxSize.y / 2, mDataBlock->boxSize.z /2 );
Point3F position = getPosition();
position.z += radius;
position.z += (mDataBlock->boxSize.z / 2); //gets a position at the center of proposed stand box.
// Use these radii to create a box that represents the difference between a standing position and the position
// we want to move into.
// Box shaped like new desired pose
Box3F B(position - extent, position + extent, true);
EarlyOutPolyList polyList;
@ -3434,9 +3446,9 @@ bool Player::canProne()
if (!mAllowProne)
return false;
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
if ( mState != MoveState ||
mDamageState != Enabled ||
isMounted() ||
mSwimming ||
mFalling )
return false;
@ -3458,7 +3470,8 @@ bool Player::canProne()
bool Player::canSprint()
{
return mAllowSprinting && mState == MoveState && mDamageState == Enabled && !isMounted() && mEnergy >= mDataBlock->minSprintEnergy && !mSwimming;
//Incorporate wading in deep water check -Skurps
return mAllowSprinting && mState == MoveState && mDamageState == Enabled && !isMounted() && mEnergy >= mDataBlock->minSprintEnergy && !mSwimming && mWaterCoverage < 0.5f;
}
//----------------------------------------------------------------------------
@ -3511,14 +3524,19 @@ void Player::updateLookAnimation(F32 dt)
// 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);
}
else
{
F32 d = mDataBlock->maxLookAngle - mDataBlock->minLookAngle;
F32 tp = (renderHead.x - mDataBlock->minLookAngle) / d;
F32 d = curMaxLookAngle - curMinLookAngle; //Skurps
F32 tp = (renderHead.x - curMinLookAngle) / d; //Skurps
mShapeInstance->setPos(mArmAnimation.thread,mClampF(tp,0,1));
}
}
@ -3948,6 +3966,11 @@ void Player::updateActionThread()
if (footfallSoundOverride <= 0)
playFootstepSound( triggeredLeft, material, rInfo.object );
}
}
//Prone crawl sound - Skurps
if( mShapeInstance->getTriggerState( 3 ) )
{
playCrawlSound();
}
}
@ -4100,7 +4123,7 @@ void Player::pickActionAnimation()
}
else if ( mPose == PronePose )
{
pickBestMoveAction(PlayerData::ProneRootAnim, PlayerData::ProneBackwardAnim, &action, &forward);
pickBestMoveAction(PlayerData::ProneRootAnim, PlayerData::ProneRightAnim, &action, &forward); //Skurps
}
else if ( mPose == SprintPose )
{
@ -4329,7 +4352,6 @@ void Player::onImageStateAnimation(U32 imageSlot, const char* seqName, bool dire
if (mDataBlock->allowImageStateAnimation && isGhost())
{
MountedImage& image = mMountedImageList[imageSlot];
// Just as with onImageAnimThreadChange we're going to apply various prefixes to determine the final sequence to use.
// Here is the order:
// imageBasePrefix_scriptPrefix_baseAnimName
@ -4449,7 +4471,7 @@ void Player::onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBa
return;
}
// Just as with ShapeBase::udpateAnimThread we're going to apply various prefixes to determine the final sequence to use.
// Just as with ShapeBase::updateAnimThread we're going to apply various prefixes to determine the final sequence to use.
// Here is the order:
// imageBasePrefix_scriptPrefix_baseAnimName
// imageBasePrefix_baseAnimName
@ -6399,7 +6421,10 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
mRot.z = mWrapF(mRot.z, 0.0f, M_2PI_F);
stream->writeFloat(mRot.z / M_2PI_F, 7);
stream->writeSignedFloat(mHead.x / (mDataBlock->maxLookAngle - mDataBlock->minLookAngle), 6);
//Skurps - use different min/max if prone
F32 curMinLookAngle = mPose == PronePose ? mDataBlock->minProneLookAngle : mDataBlock->minLookAngle;
F32 curMaxLookAngle = mPose == PronePose ? mDataBlock->maxProneLookAngle : mDataBlock->maxLookAngle;
stream->writeSignedFloat(mHead.x / ( curMaxLookAngle - curMinLookAngle), 6); //Skurps
stream->writeSignedFloat(mHead.z / mDataBlock->maxFreelookAngle, 6);
mDelta.move.pack(stream);
stream->writeFlag(!(mask & NoWarpMask));
@ -6505,7 +6530,10 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
rot.y = rot.x = 0.0f;
rot.z = stream->readFloat(7) * M_2PI_F;
mHead.x = stream->readSignedFloat(6) * (mDataBlock->maxLookAngle - mDataBlock->minLookAngle);
//Skurps - use different min/max if prone
F32 curMinLookAngle = mPose == PronePose ? mDataBlock->minProneLookAngle : mDataBlock->minLookAngle; //Skurps
F32 curMaxLookAngle = mPose == PronePose ? mDataBlock->maxProneLookAngle : mDataBlock->maxLookAngle; //Skurps
mHead.x = stream->readSignedFloat(6) * (curMaxLookAngle - curMinLookAngle); //Skurps
mHead.z = stream->readSignedFloat(6) * mDataBlock->maxFreelookAngle;
mDelta.move.unpack(stream);
@ -6918,6 +6946,13 @@ DefineEngineMethod( Player, checkDismountPoint, bool, ( Point3F oldPos, Point3F
return object->checkDismountPosition(oldPosMat, posMat);
}
//Skurps
DefineEngineMethod( Player, canProne, bool, ( ),,
"@brief checks if the engine would allow prone.\n")
{
return object->canProne();
}
DefineEngineMethod( Player, getNumDeathAnimations, S32, ( ),,
"@brief Get the number of death animations available to this player.\n\n"
"Death animations are assumed to be named death1-N using consecutive indices." )
@ -7087,6 +7122,13 @@ void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, S
}
}
//Skurps
void Player:: playCrawlSound()
{
MatrixF crawlMat = getTransform();
SFX->playOnce(mDataBlock->getPlayerSoundProfile( PlayerData::Crawl ), &crawlMat);
}
void Player:: playImpactSound()
{
if( mWaterCoverage == 0.0f )