//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames // Copyright (C) 2015 Faust Logic, Inc. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// #ifndef _PLAYER_H_ #define _PLAYER_H_ #ifndef _SHAPEBASE_H_ #include "T3D/shapeBase.h" #endif #ifndef _BOXCONVEX_H_ #include "collision/boxConvex.h" #endif #include "T3D/assets/SoundAsset.h" #include "T3D/gameBase/gameProcess.h" class Material; class ParticleEmitter; class ParticleEmitterData; class DecalData; class SplashData; class PhysicsPlayer; class Player; #ifdef TORQUE_OPENVR class OpenVRTrackedObject; #endif #ifdef TORQUE_NAVIGATION_ENABLED #include "navigation/navPath.h" #include "navigation/navMesh.h" #include "navigation/coverPoint.h" #endif // TORQUE_NAVIGATION_ENABLED //---------------------------------------------------------------------------- struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already in shapebasedata. */ { typedef ShapeBaseData Parent; enum Constants { RecoverDelayBits = 7, JumpDelayBits = 7, NumSpineNodes = 6, ImpactBits = 3, NUM_SPLASH_EMITTERS = 3, BUBBLE_EMITTER = 2, }; bool renderFirstPerson; ///< Render the player shape in first person /// Render shadows while in first person when /// renderFirstPerson is disabled. bool firstPersonShadows; StringTableEntry imageAnimPrefix; ///< Passed along to mounted images to modify /// animation sequences played in third person. [optional] bool allowImageStateAnimation; ///< When true a new thread is added to the player to allow for /// mounted images to request a sequence be played on the player /// through the image's state machine. It is only optional so /// that we don't create a TSThread on the player if we don't /// need to. AssetRef shapeFPAssetRef[ShapeBase::MaxMountedImages]; StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify /// animation sequences played in first person. [optional] U32 mCRCFP[ShapeBase::MaxMountedImages]; ///< Computed CRC values for the first person mounted image shapes /// Depends on the ShapeBaseData computeCRC field. bool mValidShapeFP[ShapeBase::MaxMountedImages]; ///< Indicates that there is a valid first person mounted image shape F32 pickupRadius; ///< Radius around player for items (on server) F32 maxTimeScale; ///< Max timeScale for action animations F32 minLookAngle; ///< Lowest angle (radians) the player can look F32 maxLookAngle; ///< Highest angle (radians) the player can look F32 maxFreelookAngle; ///< Max left/right angle the player can look 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 /// @{ F32 maxStepHeight; ///< Maximum height the player can step up F32 runSurfaceAngle; ///< Maximum angle from vertical in degrees the player can run up F32 horizMaxSpeed; ///< Max speed attainable in the horizontal F32 horizResistSpeed; ///< Speed at which resistance will take place F32 horizResistFactor; ///< Factor of resistance once horizResistSpeed has been reached F32 upMaxSpeed; ///< Max vertical speed attainable F32 upResistSpeed; ///< Speed at which resistance will take place F32 upResistFactor; ///< Factor of resistance once upResistSpeed has been reached F32 fallingSpeedThreshold; ///< Downward speed at which we consider the player falling S32 recoverDelay; ///< # tick F32 recoverRunForceScale; ///< RunForce multiplier in recover state F32 landSequenceTime; ///< If greater than 0 then the legacy fall recovery system will be bypassed /// in favour of just playing the player's land sequence. The time to /// recover from a fall then becomes this parameter's time and the land /// 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 F32 minRunEnergy; ///< Minimum energy required to run F32 maxForwardSpeed; ///< Maximum forward speed when running F32 maxBackwardSpeed; ///< Maximum backward speed when running F32 maxSideSpeed; ///< Maximum side speed when running // Jumping F32 jumpForce; ///< Force exerted per jump F32 jumpEnergyDrain; ///< Energy drained per jump F32 minJumpEnergy; ///< Minimum energy required to jump F32 minJumpSpeed; ///< Minimum speed needed to jump F32 maxJumpSpeed; ///< Maximum speed before the player can no longer jump F32 jumpSurfaceAngle; ///< Angle from vertical in degrees where the player can jump S32 jumpDelay; ///< Delay time in ticks between jumps // Sprinting F32 sprintForce; ///< Force used to accelerate player F32 sprintEnergyDrain; ///< Energy drain/tick F32 minSprintEnergy; ///< Minimum energy required to sprint F32 maxSprintForwardSpeed; ///< Maximum forward speed when sprinting F32 maxSprintBackwardSpeed; ///< Maximum backward speed when sprinting F32 maxSprintSideSpeed; ///< Maximum side speed when sprinting F32 sprintStrafeScale; ///< Amount to scale strafing motion vector while sprinting F32 sprintYawScale; ///< Amount to scale yaw motion while sprinting F32 sprintPitchScale; ///< Amount to scale pitch motion while sprinting bool sprintCanJump; ///< Can the player jump while sprinting // Swimming F32 swimForce; ///< Force used to accelerate player while swimming 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; F32 jetJumpEnergyDrain; ///< Energy per jump F32 jetMinJumpEnergy; F32 jetMinJumpSpeed; F32 jetMaxJumpSpeed; F32 jetJumpSurfaceAngle; ///< Angle vertical degrees /// @} /// @name Hitboxes /// @{ F32 boxHeadPercentage; F32 boxTorsoPercentage; //Skurps changed from Head to Torso F32 boxTorsoLeftPercentage; F32 boxTorsoRightPercentage; F32 boxTorsoBackPercentage; F32 boxTorsoFrontPercentage; /// @} F32 minImpactSpeed; ///< Minimum impact speed required to apply fall damage F32 minLateralImpactSpeed; ///< Minimum impact speed required to apply non-falling damage. F32 decalOffset; F32 groundImpactMinSpeed; ///< Minimum impact speed required to apply fall damage with the ground VectorF groundImpactShakeFreq; ///< Frequency in each direction for the camera to shake VectorF groundImpactShakeAmp; ///< How much to shake F32 groundImpactShakeDuration; ///< How long to shake F32 groundImpactShakeFalloff; ///< How fast the shake disapates /// Zounds! enum Sounds { FootSoft, FootHard, FootMetal, FootSnow, WaterStart, FootShallowSplash, FootWading, FootUnderWater, FootBubbles, MoveBubbles, WaterBreath, ImpactStart, ImpactSoft, ImpactHard, ImpactMetal, ImpactSnow, ImpactWaterEasy, ImpactWaterMedium, ImpactWaterHard, ExitWater, Crawl,//Skurps MaxSounds }; DECLARE_SOUNDASSET_ARRAY(PlayerData, PlayerSound, Sounds::MaxSounds); Point3F boxSize; ///< Width, depth, height Point3F crouchBoxSize; Point3F proneBoxSize; Point3F swimBoxSize; /// Animation and other data initialized in onAdd struct ActionAnimationDef { const char* name; ///< Sequence name struct Vector { F32 x,y,z; } dir; ///< Default direction }; struct ActionAnimation { const char* name; ///< Sequence name S32 sequence; ///< Sequence index VectorF dir; ///< Dir of animation ground transform 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 *** // These enum values are used to index the ActionAnimationList // array instantiated in player.cc // The first several are selected in the move state based on velocity RootAnim, RunForwardAnim, BackBackwardAnim, SideLeftAnim, SideRightAnim, TurnLeftAnim, //Skurps TurnRightAnim, //Skurps SprintRootAnim, SprintForwardAnim, SprintBackwardAnim, SprintLeftAnim, SprintRightAnim, CrouchRootAnim, CrouchForwardAnim, CrouchBackwardAnim, CrouchLeftAnim, CrouchRightAnim, CrouchTurnLeftAnim, //Skurps CrouchTurnRightAnim, //Skurps ProneRootAnim, ProneForwardAnim, ProneBackwardAnim, ProneLeftAnim, //Skurps ProneRightAnim, //Skurps ProneTurnLeftAnim, //Skurps ProneTurnRightAnim, //Skurps SwimRootAnim, SwimForwardAnim, SwimBackwardAnim, SwimLeftAnim, SwimRightAnim, // These are set explicitly based on player actions FallAnim, JumpAnim, StandJumpAnim, LandAnim, JetAnim, ProneInAnim, //Skurps ProneOutAnim, //Skurps DiveAnim, //Skurps NumTableActionAnims = DiveAnim + 1, //Skurps NumExtraActionAnims = 512 - NumTableActionAnims, NumActionAnims = NumTableActionAnims + NumExtraActionAnims, ActionAnimBits = 9, NullAnimation = (1 << ActionAnimBits) - 1 }; int mDynamicAnimsStart; static ActionAnimationDef ActionAnimationList[NumTableActionAnims]; ActionAnimation actionList[NumActionAnims]; U32 actionCount; U32 lookAction; S32 spineNode[NumSpineNodes]; S32 pickupDelta; ///< Base off of pcikupRadius F32 runSurfaceCos; ///< Angle from vertical in cos(runSurfaceAngle) F32 jumpSurfaceCos; ///< Angle from vertical in cos(jumpSurfaceAngle) enum Impacts { ImpactNone, ImpactNormal, }; enum Recoil { LightRecoil, MediumRecoil, HeavyRecoil, NumRecoilSequences }; S32 recoilSequence[NumRecoilSequences]; /// @name Particles /// All of the data relating to environmental effects /// @{ ParticleEmitterData * footPuffEmitter; S32 footPuffID; S32 footPuffNumParts; F32 footPuffRadius; DecalData* decalData; S32 decalID; ParticleEmitterData * dustEmitter; S32 dustID; SplashData* splash; S32 splashId; F32 splashVelocity; F32 splashAngle; F32 splashFreqMod; F32 splashVelEpsilon; F32 bubbleEmitTime; F32 medSplashSoundVel; F32 hardSplashSoundVel; F32 exitSplashSoundVel; F32 footSplashHeight; // Air control F32 airControl; // Jump off surfaces at their normal rather than straight up bool jumpTowardsNormal; StringTableEntry mControlMap; // For use if/when mPhysicsPlayer is created StringTableEntry physicsPlayerType; ParticleEmitterData* splashEmitterList[NUM_SPLASH_EMITTERS]; S32 splashEmitterIDList[NUM_SPLASH_EMITTERS]; /// @} // DECLARE_CONOBJECT(PlayerData); PlayerData(); bool preload(bool server, String &errorStr) override; 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; void unpackData(BitStream* stream) override; void onShapeChanged() { reloadOnLocalClient(); } /// @name Callbacks /// @{ DECLARE_CALLBACK( void, onPoseChange, ( Player* obj, const char* oldPose, const char* newPose ) ); DECLARE_CALLBACK( void, onStartSwim, ( Player* obj ) ); DECLARE_CALLBACK( void, onStopSwim, ( Player* obj ) ); DECLARE_CALLBACK( void, onStartSprintMotion, ( Player* obj ) ); DECLARE_CALLBACK( void, onStopSprintMotion, ( Player* obj ) ); DECLARE_CALLBACK( void, doDismount, ( Player* obj ) ); DECLARE_CALLBACK( void, onEnterLiquid, ( Player* obj, F32 coverage, const char* type ) ); DECLARE_CALLBACK( void, onLeaveLiquid, ( Player* obj, const char* type ) ); DECLARE_CALLBACK( void, animationDone, ( Player* obj, const char* animName) ); DECLARE_CALLBACK( void, onEnterMissionArea, ( Player* obj ) ); DECLARE_CALLBACK( void, onLeaveMissionArea, ( Player* obj ) ); /// @} protected: void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } }; //---------------------------------------------------------------------------- class Player: public ShapeBase { public: typedef ShapeBase Parent; enum Pose { StandPose = 0, SprintPose, CrouchPose, PronePose, SwimPose, NumPoseBits = 3 }; /// The ExtendedMove position/rotation index used for head movements static S32 smExtendedMoveHeadPosRotIndex; protected: /// Bit masks for different types of events enum MaskBits { ActionMask = Parent::NextFreeMask << 0, MoveMask = Parent::NextFreeMask << 1, ImpactMask = Parent::NextFreeMask << 2, TriggerMask = Parent::NextFreeMask << 3, NextFreeMask = Parent::NextFreeMask << 4 }; SimObjectPtr mSplashEmitter[PlayerData::NUM_SPLASH_EMITTERS]; F32 mBubbleEmitterTime; /// Client interpolation/warp data struct StateDelta { Move move; ///< Last move from server F32 dt; ///< Last interpolation time /// @name Interpolation data /// @{ Point3F pos; Point3F rot; Point3F head; VectorF posVec; VectorF rotVec; VectorF headVec; /// @} /// @name Warp data /// @{ S32 warpTicks; Point3F warpOffset; Point3F rotOffset; /// @} }; StateDelta mDelta; ///< Used for interpolation on the client. @see StateDelta S32 mPredictionCount; ///< Number of ticks to predict // Current pos, vel etc. 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; bool mUseHeadZCalc; ///< Including mHead.z in transform calculations F32 mLastAbsoluteYaw; ///< Stores that last absolute yaw value as passed in by ExtendedMove F32 mLastAbsolutePitch; ///< Stores that last absolute pitch value as passed in by ExtendedMove F32 mLastAbsoluteRoll; ///< Stores that last absolute roll value as passed in by ExtendedMove S32 mMountPending; ///< mMountPending suppresses tickDelay countdown so players will sit until ///< their mount, or another animation, comes through (or 13 seconds elapses). /// Main player state enum ActionState { NullState, MoveState, RecoverState, ProneRecoverState, // Skurps NumStateBits = 3 }; ActionState mState; ///< What is the player doing? @see ActionState bool mFalling; ///< Falling in mid-air? S32 mJumpDelay; ///< Delay till next jump Pose mPose; bool mAllowJumping; bool mAllowJetJumping; bool mAllowSprinting; bool mAllowCrouching; bool mAllowProne; bool mAllowSwimming; S32 mContactTimer; ///< Ticks since last contact Point3F mJumpSurfaceNormal; ///< Normal of the surface the player last jumped on U32 mJumpSurfaceLastContact; ///< How long it's been since the player landed (ticks) F32 mWeaponBackFraction; ///< Amount to slide the weapon back (if it's up against something) SFXSource* mMoveBubbleSound; ///< Sound for moving bubbles SFXSource* mWaterBreathSound; ///< Sound for underwater breath SimObjectPtr mControlObject; ///< Controlling object /// @name Animation threads & data /// @{ struct ActionAnimation { S32 action; TSThread* thread; S32 delayTicks; // before picking another. bool forward; bool firstPerson; bool waitForEnd; bool holdAtEnd; bool animateOnServer; bool atEnd; bool callbackTripped; bool useSynchedPos; } mActionAnimation; struct ArmAnimation { U32 action; TSThread* thread; } mArmAnimation; TSThread* mArmThread; TSThread* mHeadVThread; 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. 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 // PlayerData* mDataBlock; ///< MMmmmmm...datablock... Point3F mLastPos; ///< Holds the last position for physics updates Point3F mLastWaterPos; ///< Same as mLastPos, but for water #ifdef TORQUE_OPENVR SimObjectPtr mControllers[2]; #endif struct ContactInfo { bool contacted, jump, run; SceneObject *contactObject; VectorF contactNormal; void clear() { contacted=jump=run=false; contactObject = NULL; contactNormal.set(1,1,1); } ContactInfo() { clear(); } } mContactInfo; struct Death { F32 lastPos; Point3F posAdd; VectorF rotate; VectorF curNormal; F32 curSink; void clear() {dMemset(this, 0, sizeof(*this)); initFall();} VectorF getPosAdd() {VectorF ret(posAdd); posAdd.set(0,0,0); return ret;} bool haveVelocity() {return posAdd.x != 0 || posAdd.y != 0;} void initFall() {curNormal.set(0,0,1); curSink = 0;} Death() {clear();} MatrixF* fallToGround(F32 adjust, const Point3F& pos, F32 zrot, F32 boxRad); } mDeath; PhysicsPlayer *mPhysicsRep; // First person mounted image shapes TSShapeInstance* mShapeFPInstance[ShapeBase::MaxMountedImages]; TSThread *mShapeFPAmbientThread[ShapeBase::MaxMountedImages]; TSThread *mShapeFPVisThread[ShapeBase::MaxMountedImages]; TSThread *mShapeFPAnimThread[ShapeBase::MaxMountedImages]; TSThread *mShapeFPFlashThread[ShapeBase::MaxMountedImages]; TSThread *mShapeFPSpinThread[ShapeBase::MaxMountedImages]; public: // New collision OrthoBoxConvex mConvex; Box3F mWorkingQueryBox; /// Standing / Crouched / Prone or Swimming Pose getPose() const { return mPose; } virtual const char* getPoseName() const; /// Setting this from script directly might not actually work, /// This is really just a helper for the player class so that its bounding box /// will get resized appropriately when the pose changes void setPose( Pose pose ); PhysicsPlayer* getPhysicsRep() const { return mPhysicsRep; } #ifdef TORQUE_OPENVR void setControllers(Vector controllerList); #endif protected: void setState(ActionState state, U32 ticks=0); void updateState(); // Jetting bool mJetting; ///Update the movement virtual void updateMove(const Move *move); ///Interpolate movement Point3F _move( const F32 travelTime, Collision *outCol ); F32 _doCollisionImpact( const Collision *collision, bool fallingCollision); void _handleCollision( const Collision &collision ); virtual bool updatePos(const F32 travelTime = TickSec); // PATHSHAPE virtual void updateAttachment(); // PATHSHAPE END ///Update head animation void updateLookAnimation(F32 dt = 0.0f); ///Update other animations void updateAnimation(F32 dt); void updateAnimationTree(bool firstPerson); bool step(Point3F *pos,F32 *maxStep,F32 time); ///See if the player is still in the mission area void checkMissionArea(); virtual U32 getArmAction() const { return mArmAnimation.action; } virtual bool setArmThread(U32 action); virtual void setActionThread(U32 action,bool forward,bool hold = false,bool wait = false,bool fsp = false, bool forceSet = false); virtual void updateActionThread(); virtual void pickBestMoveAction(U32 startAnim, U32 endAnim, U32 * action, bool * forward) const; virtual void pickActionAnimation(); /// @name Mounted objects /// @{ void onUnmount( SceneObject *obj, S32 node ) override; void unmount() override; /// @} void setPosition(const Point3F& pos,const Point3F& viewRot); void setRenderPosition(const Point3F& pos,const Point3F& viewRot,F32 dt=-1); void _findContact( SceneObject **contactObject, VectorF *contactNormal, Vector *outOverlapObjects ); void findContact( bool *run, bool *jump, VectorF *contactNormal ); void buildImagePrefixPaths(String* prefixPaths); S32 findPrefixSequence(String* prefixPaths, const String& baseSeq); S32 convertActionToImagePrefix(U32 action); void onImage(U32 imageSlot, bool unmount) override; void onImageRecoil(U32 imageSlot,ShapeBaseImageData::StateData::RecoilState) override; void onImageStateAnimation(U32 imageSlot, const char* seqName, bool direction, bool scaleToState, F32 stateTimeOutValue) override; const char* getImageAnimPrefix(U32 imageSlot, S32 imageShapeIndex) override; void onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState, const char* anim, F32 pos, F32 timeScale, bool reset=false) override; void onImageAnimThreadUpdate(U32 imageSlot, S32 imageShapeIndex, F32 dt) override; void updateDamageLevel() override; void updateDamageState() override; /// Set which client is controlling this player void setControllingClient(GameConnection* client) override; void calcClassRenderData() override; /// Play sound for foot contact. /// /// @param triggeredLeft If true, left foot hit; right otherwise. /// @param contactMaterial Material onto which the player stepped; may be NULL. /// @param contactObject Object onto which the player stepped; may be NULL. void playFootstepSound( bool triggeredLeft, Material* contactMaterial, SceneObject* contactObject ); /// Skurps prone crawl sound void playCrawlSound(); /// Play an impact sound. void playImpactSound(); /// Are we in the process of dying? bool inDeathAnim(); F32 deathDelta(Point3F &delta); void updateDeathOffsets(); bool inSittingAnim(); /// @name Water /// @{ void updateSplash(); ///< Update the splash effect void updateFroth( F32 dt ); ///< Update any froth void updateWaterSounds( F32 dt ); ///< Update water sounds void createSplash( Point3F &pos, F32 speed ); ///< Creates a splash bool collidingWithWater( Point3F &waterHeight ); ///< Are we colliding with water? /// @} void disableHeadZCalc() { mUseHeadZCalc = false; } void enableHeadZCalc() { mUseHeadZCalc = true; } public: DECLARE_CONOBJECT(Player); DECLARE_CATEGORY("Actor \t Controllable"); Player(); ~Player(); static void consoleInit(); /// @name Transforms /// @{ void setTransform(const MatrixF &mat) override; void getEyeTransform(MatrixF* mat) override; void getEyeBaseTransform(MatrixF* mat, bool includeBank) override; void getRenderEyeTransform(MatrixF* mat) override; void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank) override; void getCameraParameters(F32 *min, F32 *max, Point3F *offset, MatrixF *rot) override; void getMuzzleTransform(U32 imageSlot,MatrixF* mat) override; void getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat) override; void getMuzzleVector(U32 imageSlot,VectorF* vec) override; /// @} F32 getSpeed() const; Point3F getVelocity() const override; void setVelocity(const VectorF& vel) override; /// Apply an impulse at the given point, with magnitude/direction of vec void applyImpulse(const Point3F& pos,const VectorF& vec) override; /// Get the rotation of the player const Point3F& getRotation() { return mRot; } /// Get the rotation of the head of the player const Point3F& getHeadRotation() { return mHead; } void getDamageLocation(const Point3F& in_rPos, const char *&out_rpVert, const char *&out_rpQuad); void allowAllPoses(); void allowJumping(bool state) { mAllowJumping = state; } void allowJetJumping(bool state) { mAllowJetJumping = state; } void allowSprinting(bool state) { mAllowSprinting = state; } void allowCrouching(bool state) { mAllowCrouching = state; } void allowProne(bool state) { mAllowProne = state; } void allowSwimming(bool state) { mAllowSwimming = state; } bool canJump(); ///< Can the player jump? bool canJetJump(); ///< Can the player jet? bool canSwim(); ///< Can the player swim? bool canCrouch(); bool canStand(); bool canProne(); bool canSprint(); bool haveContact() const { return !mContactTimer; } ///< Is it in contact with something void getMuzzlePointAI( U32 imageSlot, Point3F *point ); F32 getMaxForwardVelocity() const { return (mDataBlock != NULL ? mDataBlock->maxForwardSpeed : 0); } bool isDisplacable() const override; Point3F getMomentum() const override; void setMomentum(const Point3F &momentum) override; bool displaceObject(const Point3F& displaceVector) override; bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here? // bool onAdd() override; void onRemove() override; bool onNewDataBlock( GameBaseData *dptr, bool reload ) override; void onScaleChanged() override; Box3F mScaledBox; // Animation const char* getStateName(); bool setActionThread(const char* sequence,bool hold,bool wait,bool fsp = false); const String& getArmThread() const; bool setArmThread(const char* sequence); // Object control void setControlObject(ShapeBase *obj) override; ShapeBase* getControlObject() override; // void updateWorkingCollisionSet(); void processTick(const Move *move) override; void interpolateTick(F32 delta) override; void advanceTime(F32 dt) override; bool castRay(const Point3F &start, const Point3F &end, RayInfo* info) override; bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) override; void buildConvex(const Box3F& box, Convex* convex) override; bool isControlObject(); void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *) override; void writePacketData(GameConnection *conn, BitStream *stream) override; void readPacketData (GameConnection *conn, BitStream *stream) override; U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream) override; void unpackUpdate(NetConnection *conn, BitStream *stream) override; void prepRenderImage( SceneRenderState* state ) override; virtual void renderConvex( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); void renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRenderState *state ) override; protected: static void afx_consoleInit(); void afx_init(); U32 afx_packUpdate(NetConnection*, U32 mask, BitStream*, U32 retMask); void afx_unpackUpdate(NetConnection*, BitStream*); private: static bool sCorpsesHiddenFromRayCast; public: void restoreAnimation(U32 tag) override; U32 getAnimationID(const char* name) override; U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim) override; F32 getAnimationDurationByID(U32 anim_id) override; bool isBlendAnimation(const char* name) override; const char* getLastClipName(U32 clip_tag) override; void unlockAnimation(U32 tag, bool force=false) override; U32 lockAnimation() override; bool isAnimationLocked() const override { return ((anim_clip_flags & BLOCK_USER_CONTROL) != 0); } protected: bool overrideLookAnimation; F32 armLookOverridePos; F32 headVLookOverridePos; F32 headHLookOverridePos; public: void setLookAnimationOverride(bool flag); void copyHeadRotation(const Player* p) { mHead = p->mHead; } public: bool ignore_updates; void resetContactTimer() { mContactTimer = 0; } protected: U8 move_trigger_states; U32 fx_s_triggers; U32 mark_fx_c_triggers; U32 fx_c_triggers; F32 z_velocity; bool mark_idle; F32 idle_timer; bool mark_s_landing; void process_client_triggers(bool triggeredLeft, bool triggeredRight); public: enum { // server events PLAYER_MOVE_TRIGGER_0 = BIT(0), PLAYER_MOVE_TRIGGER_1 = BIT(1), PLAYER_MOVE_TRIGGER_2 = BIT(2), PLAYER_MOVE_TRIGGER_3 = BIT(3), PLAYER_MOVE_TRIGGER_4 = BIT(4), PLAYER_MOVE_TRIGGER_5 = BIT(5), PLAYER_LANDING_S_TRIGGER = BIT(6), PLAYER_FIRE_S_TRIGGER = PLAYER_MOVE_TRIGGER_0, PLAYER_FIRE_ALT_S_TRIGGER = PLAYER_MOVE_TRIGGER_1, PLAYER_JUMP_S_TRIGGER = BIT(7), // client events PLAYER_LF_FOOT_C_TRIGGER = BIT(16), PLAYER_RT_FOOT_C_TRIGGER = BIT(17), PLAYER_LANDING_C_TRIGGER = BIT(18), PLAYER_IDLE_C_TRIGGER = BIT(19), }; U32 getClientEventTriggers() const { return fx_c_triggers; } U32 getServerEventTriggers() const { return fx_s_triggers; } protected: F32 speed_bias; F32 speed_bias_goal; bool override_movement; Point3F movement_data; U8 movement_op; U32 last_movement_tag; static U32 unique_movement_tag_counter; public: void setMovementSpeedBias(F32 bias); U32 setMovementOverride(F32 bias, const Point3F* mov=0, U32 op=1); void restoreMovement(U32 tag); protected: S32 footfallDecalOverride; S32 footfallSoundOverride; S32 footfallDustOverride; bool noFootfallFX; public: void overrideFootfallFX(bool decals=true, bool sounds=true, bool dust=true); void restoreFootfallFX(bool decals=true, bool sounds=true, bool dust=true); }; typedef Player::Pose PlayerPose; DefineEnumType( PlayerPose ); #endif