Files
2025-09-29 00:52:08 +02:00

832 lines
30 KiB
XML
Executable File

USING "minigames_helpers.sch"
USING "minigame_UIInputs.sch"
USING "tennis_ai.sch"
USING "tennis_debug.sch"
/// PURPOSE:
ENUM SHOT_TYPE_ENUM
SHOT_NORMAL,
SHOT_TOPSPIN,
SHOT_LOB,
SHOT_BACKSPIN,
SHOT_STRONG,
SHOT_DROP,
SERVE,
TOSS
ENDENUM
ENUM TENNIS_DIVE_DiveType
TENNIS_DIVE_NoDive = 0,
TENNIS_DIVE_DiveLeft_TopLeft, //AnimationsToBlend: Left_TopLeft, Left_TopRight, Left_BottomLeft
TENNIS_DIVE_DiveLeft_BottomRight, //AnimationsToBlend: Left_BottomLeft, Left_TopRight, Left_BottomRight
TENNIS_DIVE_DiveRight_TopLeft, //AnimationsToBlend: Right_TopLeft, Right_TopRight, Right_BottomRight
TENNIS_DIVE_DiveRight_BottomRight //AnimationsToBlend: Right_TopLeft, Right_TopRight, Right_BottomRight
ENDENUM
ENUM RUN_DIRECTION
RUN_FORWARD,
RUN_BACKWARD,
RUN_LEFT,
RUN_RIGHT,
RUN_NEUTRAL
ENDENUM
ENUM TENNIS_PLAYER_ID
TENNIS_PLAYER_AWAY = 0,
TENNIS_PLAYER_HOME = 1,
TENNIS_PLAYERS = 2
ENDENUM
ENUM TENNIS_SWING_STATES
TSS_BACKHAND_TS_HI = 0,
TSS_BACKHAND_TS_MID,
TSS_BACKHAND_TS_LOW,
TSS_BACKHAND_BS_HI,
TSS_BACKHAND_BS_MID,
TSS_BACKHAND_BS_LOW,
TSS_BACKHAND_TS_HI_SKIP, //6
TSS_BACKHAND_TS_MID_SKIP,
TSS_BACKHAND_TS_LOW_SKIP,
TSS_BACKHAND_BS_HI_SKIP,
TSS_BACKHAND_BS_MID_SKIP,
TSS_BACKHAND_BS_LOW_SKIP,
TSS_FOREHAND_TS_HI, //12
TSS_FOREHAND_TS_MID,
TSS_FOREHAND_TS_LOW,
TSS_FOREHAND_BS_HI,
TSS_FOREHAND_BS_MID,
TSS_FOREHAND_BS_LOW,
TSS_FOREHAND_SMASH,
TSS_FOREHAND_SMASH_LEFT,
TSS_FOREHAND_SMASH_RIGHT,
TSS_FOREHAND_TS_HI_SKIP, //21
TSS_FOREHAND_TS_MID_SKIP,
TSS_FOREHAND_TS_LOW_SKIP,
TSS_FOREHAND_BS_HI_SKIP,
TSS_FOREHAND_BS_MID_SKIP,
TSS_FOREHAND_BS_LOW_SKIP,
TSS_FOREHAND_SMASH_SKIP,
TSS_FOREHAND_SMASH_LEFT_SKIP,
TSS_FOREHAND_SMASH_RIGHT_SKIP,
TSS_CLOSE_BH_TS_HI, //30
TSS_CLOSE_BH_TS_MID,
TSS_CLOSE_BH_TS_LOW,
TSS_CLOSE_BH_BS_HI,
TSS_CLOSE_BH_BS_MID,
TSS_CLOSE_BH_BS_LOW,
TSS_CLOSE_FH_TS_HI, //36
TSS_CLOSE_FH_TS_MID,
TSS_CLOSE_FH_TS_LOW,
TSS_CLOSE_FH_BS_HI,
TSS_CLOSE_FH_BS_MID,
TSS_CLOSE_FH_BS_LOW,
TSS_CLOSE_BH_TS_HI_SKIP, //42
TSS_CLOSE_BH_TS_MID_SKIP,
TSS_CLOSE_BH_TS_LOW_SKIP,
TSS_CLOSE_BH_BS_HI_SKIP,
TSS_CLOSE_BH_BS_MID_SKIP,
TSS_CLOSE_BH_BS_LOW_SKIP,
TSS_CLOSE_FH_TS_HI_SKIP, //48
TSS_CLOSE_FH_TS_MID_SKIP,
TSS_CLOSE_FH_TS_LOW_SKIP,
TSS_CLOSE_FH_BS_HI_SKIP,
TSS_CLOSE_FH_BS_MID_SKIP,
TSS_CLOSE_FH_BS_LOW_SKIP,
TSS_LUNGE_BACKHAND_HI, //54
TSS_LUNGE_BACKHAND_MID,
TSS_LUNGE_BACKHAND_LOW,
TSS_LUNGE_FOREHAND_HI,
TSS_LUNGE_FOREHAND_MID,
TSS_LUNGE_FOREHAND_LOW,
TSS_FOREHAND_TS_LO_FAR, //60
TSS_FOREHAND_TS_MID_FAR,
TSS_FOREHAND_TS_HI_FAR,
TSS_CLOSE_BH_LO, //63
TSS_CLOSE_BH_MID,
TSS_CLOSE_BH_HI,
TSS_CLOSE_FH_LO,
TSS_CLOSE_FH_MID,
TSS_CLOSE_FH_HI,
TSS_MID_BH_LO, //69
TSS_MID_BH_MID,
TSS_MID_BH_HI,
TSS_DIVE_BACKHAND, //72
TSS_DIVE_FOREHAND,
TSS_SERVE_TOSS, //74
TSS_NO_SWING,
TSS_WAITING,
TSS_MAX_SWINGS
ENDENUM
ENUM TENNIS_PLAYER_BITMASKS
TPB_CAN_CHARGE_STRONG_SWING = BIT0,
TPB_RAGE_ANIM = BIT1,
TPB_SERVE_EXECUTING = BIT2,
TPB_MISSED_THE_BALL = BIT3,
TPB_ALLOW_AI_ASSIST = BIT4,
TPB_DIVE_ROLL_FINISHING = BIT5, // mostly deprecated
TPB_STOP_METER = BIT6,
TPB_MOVE_ENABLED = BIT7,
TPB_HIT_BY_BALL = BIT8,
TPB_WANTS_TO_SWING = BIT9,
TPB_TENNIS_SWING_EVENT_FLAG = BIT10, // This flag is very very important and should only be reset in prepare serve or thru the SWING_ANIM_COMPLETE function. Never on its own.
TPB_TASKED_BACK_TO_COURT = BIT11,
TPB_MUST_RELEASE = BIT12,
TPB_FORCED_UPDATE = BIT13,
TPB_DROP_OUT_OF_TENNIS_MODE = BIT14,
TPB_REDUCE_PREDICTION_CALC = BIT15,
TPB_SWINGING_AIMLESSLY = BIT16
ENDENUM
FUNC STRING GET_STRING_FROM_TENNIS_PLAYER_BITMASK(TENNIS_PLAYER_BITMASKS eMask)
SWITCH eMask
CASE TPB_RAGE_ANIM RETURN "TPB_RAGE_ANIM"
CASE TPB_SERVE_EXECUTING RETURN "TPB_SERVE_EXECUTING"
CASE TPB_MISSED_THE_BALL RETURN "TPB_MISSED_THE_BALL"
CASE TPB_ALLOW_AI_ASSIST RETURN "TPB_ALLOW_AI_ASSIST"
CASE TPB_DIVE_ROLL_FINISHING RETURN "TPB_DIVE_ROLL_FINISHING"
CASE TPB_STOP_METER RETURN "TPB_STOP_METER"
CASE TPB_MOVE_ENABLED RETURN "TPB_MOVE_ENABLED"
CASE TPB_HIT_BY_BALL RETURN "TPB_HIT_BY_BALL"
CASE TPB_WANTS_TO_SWING RETURN "TPB_WANTS_TO_SWING"
CASE TPB_TENNIS_SWING_EVENT_FLAG RETURN "TPB_TENNIS_SWING_EVENT_FLAG"
CASE TPB_CAN_CHARGE_STRONG_SWING RETURN "TPB_CAN_CHARGE_STRONG_SWING"
CASE TPB_MUST_RELEASE RETURN "TPB_MUST_RELEASE"
CASE TPB_TASKED_BACK_TO_COURT RETURN "TPB_TASKED_BACK_TO_COURT"
CASE TPB_FORCED_UPDATE RETURN "TPB_FORCED_UPDATE"
CASE TPB_DROP_OUT_OF_TENNIS_MODE RETURN "TPB_DROP_OUT_OF_TENNIS_MODE"
CASE TPB_REDUCE_PREDICTION_CALC RETURN "TPB_REDUCE_PREDICTION_CALC"
CASE TPB_SWINGING_AIMLESSLY RETURN "TPB_SWINGING_AIMLESSLY"
ENDSWITCH
RETURN "Unknown TENNIS_PLAYER_BITMASKS Bitmask"
ENDFUNC
STRUCT DAMPED_MOTION_STRUCT
FLOAT pos // updated from velocity
FLOAT vel // updated from previous velocity and dampening
ENDSTRUCT
STRUCT LAUNCH_DETAILS
INT iForce
INT iAngle
ENDSTRUCT
FORWARD ENUM LAUNCH_DETAIL_ENUM
FORWARD ENUM TENNIS_BALL_SPIN
ENUM TENNIS_GENDER
GENDER_FEMALE = 0,
GENDER_MALE = 1,
GENDER_NEUTRAL = 2
ENDENUM
STRUCT TENNIS_PLAYER
FLOAT fLeftRight // Stores the leftRight value we use to aim shots with
TENNIS_PLAYER_ID eCourtSide
INT boolBitmasks
LAUNCH_DETAIL_ENUM launchGrade
TENNIS_AI_PLAYER playerAI
PLAYER_CONTROL_TYPE controlType
PED_INDEX pIndex
OBJECT_INDEX oTennisRacket
SHOT_TYPE_ENUM ShotType
RUN_DIRECTION running = RUN_NEUTRAL
TENNIS_SWING_STATES eSwingState
VECTOR vPos //player position
VECTOR vMyForward
VECTOR vMyRight
VECTOR vPrevBatPos
VECTOR vMarkerPos // X Marker position that's actually shown
// VECTOR vDiveBarycentricBlend
TENNIS_DIVE_DiveType eDiveSelection
INT iFramesTrunc
SEQUENCE_INDEX seqWalk
INT iSequenceThreshold
INT iSwingAnimFrameStamp
PEDHEADSHOT_ID myPedHeadshot
INT iFailSafe
TENNIS_GENDER genderPlayer = GENDER_NEUTRAL
//Human only variables
FLOAT fPow, fTimer // fPow is for the serve power, fTimer is for when the player aims too far out
FLOAT fServeBlend = 0.5 // Used in the serve MoVE Network to blend between states
FLOAT fStrongSwingTimer // the cooldown on the strong swing
FLOAT fStrongSwingHoldTimer // times how long to hold the button to get a strong swing
INT iSwingDelayStamp // Delays the player's ability to swing
FLOAT fStrengthBoost = 1.0 // Float value to increase shot strength by, based on player Strength
FLOAT fAnimSpeed = 1.0
FLOAT fReactTimer
FLOAT fReactLimit
FLOAT fVertBlend, fHorBlend // Blends for the 4-way dive blend thru the MoVE network
FLOAT fXDirHeldTimer
structTimer meterDelayTimer
INT iAnalogXValue // Stores the valus of X when a swing button is pressed, used when delaying calculations like the tap-twice serve
INT iDiveReactAnimStamp // Time stamp for when a dive or react finishes and can be blended out of
// Cached prediction values
VECTOR vBallVelCached
FLOAT fBallAirTimeCached
TENNIS_BALL_SPIN eSpinCached
FLOAT fSpinTimerCached
INT iBouncesCached
FLOAT fFrameTimeCached
// VECTOR vFuturePoints[MAX_FUTURE_POINTS] // Moving to thisProps to cut down on stack size
TEXT_LABEL_31 texVoice
// VECTOR vCachedMarker, vActualMarker // Used in MP for lerping the X Marker
ENDSTRUCT
PROC SET_TENNIS_PLAYER_SWING_ANIM_FRAME_STAMP(TENNIS_PLAYER &thisPlayer, INT iNewStamp)
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_SWING_ANIM_FRAME_STAMP :: iNewStamp=", iNewStamp)
thisPlayer.iSwingAnimFrameStamp = iNewStamp
ENDPROC
FUNC INT GET_TENNIS_PLAYER_SWING_ANIM_FRAME_STAMP(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iSwingAnimFrameStamp
ENDFUNC
PROC SET_TENNIS_PLAYER_DIVE_REACT_STAMP(TENNIS_PLAYER &thisPlayer, INT iNewStamp)
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_DIVE_REACT_STAMP :: iNewStamp=", iNewStamp)
thisPlayer.iDiveReactAnimStamp = iNewStamp
ENDPROC
FUNC INT GET_TENNIS_PLAYER_DIVE_REACT_STAMP(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iDiveReactAnimStamp
ENDFUNC
/// PURPOSE:
/// Used primarily for AI, ARE_TENNIS_PLAYERS_IN_POSITION uses this to break out a little early
/// PARAMS:
/// thisPlayer -
/// iNewThreshold -
PROC SET_TENNIS_PLAYER_SEQUENCE_THRESHOLD(TENNIS_PLAYER &thisPlayer, INT iNewThreshold)
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_SEQUENCE_THRESHOLD :: iNewThreshold=", iNewThreshold)
thisPlayer.iSequenceThreshold = iNewThreshold
ENDPROC
FUNC INT GET_TENNIS_PLAYER_SEQUENCE_THRESHOLD(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iSequenceThreshold
ENDFUNC
PROC SET_TENNIS_PLAYER_VOICE(TENNIS_PLAYER &thisPlayer, STRING sVoice)
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_VOICE :: ", thisPlayer.playerAI.texName, " to ", sVoice)
thisPlayer.texVoice = sVoice
ENDPROC
FUNC TEXT_LABEL_31 GET_TENNIS_PLAYER_VOICE(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.texVoice
ENDFUNC
PROC SET_TENNIS_PLAYER_DIRECTION_HELD_TIMER(TENNIS_PLAYER &thisPlayer, FLOAT fNewTime)
thisPlayer.fXDirHeldTimer = fNewTime
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_DIRECTION_HELD_TIMER(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fXDirHeldTimer
ENDFUNC
PROC SET_TENNIS_PLAYER_PREDICTION_VARIABLES_FROM_CACHE(TENNIS_PLAYER &thisPlayer, VECTOR &vBallVel, FLOAT &fBallAirTime, TENNIS_BALL_SPIN &eSpin, FLOAT &fSpinTimer, INT &iBounces)
vBallVel = thisPlayer.vBallVelCached
fBallAirTime = thisPlayer.fBallAirTimeCached
eSpin = thisPlayer.eSpinCached
fSpinTimer = thisPlayer.fSpinTimerCached
iBounces = thisPlayer.iBouncesCached
// fFrameTime
ENDPROC
PROC CACHE_TENNIS_PLAYER_PREDICTION_VARIABLES(TENNIS_PLAYER &thisPlayer, VECTOR vBallVel, FLOAT fBallAirTime, TENNIS_BALL_SPIN eSpin, FLOAT fSpinTimer, INT iBounces)
thisPlayer.vBallVelCached = vBallVel
thisPlayer.fBallAirTimeCached = fBallAirTime
thisPlayer.eSpinCached = eSpin
thisPlayer.fSpinTimerCached = fSpinTimer
thisPlayer.iBouncesCached = iBounces
ENDPROC
FUNC STRING GET_STRING_FROM_TENNIS_DIVE_SELECTION(TENNIS_DIVE_DiveType diveType)
SWITCH(diveType)
CASE TENNIS_DIVE_DiveLeft_TopLeft
RETURN "TENNIS_DIVE_DiveLeft_TopLeft"
CASE TENNIS_DIVE_DiveLeft_BottomRight
RETURN "TENNIS_DIVE_DiveLeft_BottomRight"
CASE TENNIS_DIVE_DiveRight_TopLeft
RETURN "TENNIS_DIVE_DiveRight_TopLeft"
CASE TENNIS_DIVE_DiveRight_BottomRight
RETURN "TENNIS_DIVE_DiveRight_BottomRight"
ENDSWITCH
RETURN "Unknown"
ENDFUNC
FUNC STRING GET_STRING_FROM_TENNIS_PLAYER_ID(TENNIS_PLAYER_ID ePlayer)
RETURN PICK_STRING(ePlayer = TENNIS_PLAYER_AWAY, "TENNIS_PLAYER_AWAY",
PICK_STRING(ePlayer = TENNIS_PLAYER_HOME, "TENNIS_PLAYER_HOME",
PICK_STRING(ePlayer = TENNIS_PLAYERS, "TENNIS_PLAYERS",
"Unknown Tennis Player ID")))
ENDFUNC
PROC RESET_TENNIS_PLAYER_REACT_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fReactTimer = 0.0
CPRINTLN(DEBUG_TENNIS, "RESET_TENNIS_PLAYER_REACT_TIMER :: called on ", thisPlayer.playerAI.texName)
ENDPROC
PROC INCREASE_TENNIS_PLAYER_REACT_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fReactTimer += GET_FRAME_TIME()
CPRINTLN(DEBUG_TENNIS, "INCREASE_TENNIS_PLAYER_REACT_TIMER :: ", thisPlayer.playerAI.texName, "'s fReactTimer=", thisPlayer.fReactTimer)
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_REACT_TIMER(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fReactTimer
ENDFUNC
PROC SET_TENNIS_PLAYER_REACT_LIMIT(TENNIS_PLAYER &thisPlayer, FLOAT fNewLimit)
thisPlayer.fReactLimit = fNewLimit
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_REACT_LIMIT :: ", thisPlayer.playerAI.texName, "'s fReactLimit=", thisPlayer.fReactLimit)
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_REACT_LIMIT(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fReactLimit
ENDFUNC
PROC SET_TENNIS_PLAYER_DIVE_BLEND_VERTICAL(TENNIS_PLAYER &thisPlayer, FLOAT fNewVert)
thisPlayer.fVertBlend = fNewVert
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_DIVE_BLEND_VERTICAL(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fVertBlend
ENDFUNC
PROC SET_TENNIS_PLAYER_DIVE_BLEND_HORIZONTAL(TENNIS_PLAYER &thisPlayer, FLOAT fNewHor)
thisPlayer.fHorBlend = fNewHor
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_DIVE_BLEND_HORIZONTAL(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fHorBlend
ENDFUNC
PROC SET_TENNIS_PLAYER_FLAG(TENNIS_PLAYER &thisPlayer, TENNIS_PLAYER_BITMASKS eMask)
#IF IS_DEBUG_BUILD
IF NOT IS_BITMASK_AS_ENUM_SET( thisPlayer.boolBitmasks, eMask )
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_FLAG :: Setting ", thisPlayer.playerAI.texName, ", ", GET_STRING_FROM_TENNIS_PLAYER_BITMASK(eMask))
ENDIF
#ENDIF
SET_BITMASK_AS_ENUM(thisPlayer.boolBitmasks, eMask)
ENDPROC
PROC CLEAR_TENNIS_PLAYER_FLAG(TENNIS_PLAYER &thisPlayer, TENNIS_PLAYER_BITMASKS eMask)
#IF IS_DEBUG_BUILD
IF IS_BITMASK_AS_ENUM_SET( thisPlayer.boolBitmasks, eMask )
CDEBUG2LN(DEBUG_TENNIS, "CLEAR_TENNIS_PLAYER_FLAG :: ", thisPlayer.playerAI.texName, ", ", GET_STRING_FROM_TENNIS_PLAYER_BITMASK(eMask))
ENDIF
#ENDIF
CLEAR_BITMASK_AS_ENUM(thisPlayer.boolBitmasks, eMask)
ENDPROC
FUNC BOOL IS_TENNIS_PLAYER_FLAG_SET(TENNIS_PLAYER &thisPlayer, TENNIS_PLAYER_BITMASKS eMask)
RETURN IS_BITMASK_AS_ENUM_SET(thisPlayer.boolBitmasks, eMask)
ENDFUNC
PROC SET_TENNIS_PLAYER_DIVE_SELECTION(TENNIS_PLAYER &thisPlayer, TENNIS_DIVE_DiveType eDive)
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_DIVE_SELECTION :: ", thisPlayer.playerAI.texName, ", ", GET_STRING_FROM_TENNIS_DIVE_SELECTION(eDive))
#IF IS_DEBUG_BUILD
#IF TENNIS_DEBUG_RECORDING
DEBUG_RECORD_STRING("SET_TENNIS_PLAYER_DIVE_SELECTION", GET_STRING_FROM_TENNIS_DIVE_SELECTION(eDive))
#ENDIF
#ENDIF
thisPlayer.eDiveSelection = eDive
ENDPROC
FUNC TENNIS_DIVE_DiveType GET_TENNIS_PLAYER_DIVE_SELECTION(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.eDiveSelection
ENDFUNC
PROC SET_TENNIS_PLAYER_ANIM_SPEED(TENNIS_PLAYER &thisPlayer, FLOAT fNewSpeed)
// CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_ANIM_SPEED(", fNewSpeed, ")")
thisPlayer.fAnimSpeed = fNewSpeed
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_ANIM_SPEED(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fAnimSpeed
ENDFUNC
PROC SET_TENNIS_PLAYER_SWING_DELAY_STAMP(TENNIS_PLAYER &thisPlayer, INT iNewStamp)
CDEBUG3LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_SWING_DELAY_STAMP set to ", iNewStamp)
thisPlayer.iSwingDelayStamp = iNewStamp
ENDPROC
FUNC INT GET_TENNIS_PLAYER_SWING_DELAY_STAMP(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iSwingDelayStamp
ENDFUNC
PROC SET_TENNIS_PLAYER_TRUNCATE_FRAMES(TENNIS_PLAYER &thisPlayer, INT iNewTrunc)
thisPlayer.iFramesTrunc = iNewTrunc
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_TRUNCATE_FRAMES(", thisPlayer.iFramesTrunc, ")")
ENDPROC
FUNC INT GET_TENNIS_PLAYER_TRUNCATE_FRAMES(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iFramesTrunc
ENDFUNC
/// PURPOSE:
/// Mutator
/// PARAMS:
/// thisPlayer -
/// fNewBoost -
PROC SET_TENNIS_PLAYER_STRENGTH_BOOST(TENNIS_PLAYER &thisPlayer, FLOAT fNewBoost)
thisPlayer.fStrengthBoost = fNewBoost
ENDPROC
/// PURPOSE:
/// Accessor
/// PARAMS:
/// thisPlayer -
/// RETURNS:
///
FUNC FLOAT GET_TENNIS_PLAYER_STRENGTH_BOOST(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fStrengthBoost
ENDFUNC
PROC SET_TENNIS_PLAYER_STORED_LAUNCH_GRADE(TENNIS_PLAYER &thisPlayer, LAUNCH_DETAIL_ENUM newGrade)
thisPlayer.launchGrade = newGrade
ENDPROC
FUNC LAUNCH_DETAIL_ENUM GET_TENNIS_PLAYER_STORED_LAUNCH_GRADE(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.launchGrade
ENDFUNC
PROC INCREASE_TENNIS_PLAYER_STRONG_SWING_HOLD_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fStrongSwingHoldTimer += GET_FRAME_TIME()
CDEBUG3LN(DEBUG_TENNIS, "INCREASE_TENNIS_PLAYER_STRONG_SWING_HOLD_TIMER: ", thisPlayer.playerAI.texName, " fStrongSwingHoldTimer=", thisPlayer.fStrongSwingHoldTimer)
ENDPROC
PROC RESET_TENNIS_PLAYER_STRONG_SWING_HOLD_TIMER(TENNIS_PLAYER &thisPlayer)
// CPRINTLN(DEBUG_TENNIS, "RESET_TENNIS_PLAYER_STRONG_SWING_HOLD_TIMER called")
thisPlayer.fStrongSwingHoldTimer = 0
ENDPROC
FUNC FLOAT GET_TENNIS_PLAYER_STRONG_SWING_HOLD_TIMER(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fStrongSwingHoldTimer
ENDFUNC
FUNC BOOL HAS_TENNIS_PLAYER_ACTIVATED_STRONG_SWING(TENNIS_PLAYER &thisPlayer)
// CPRINTLN(DEBUG_TENNIS, "HAS_TENNIS_PLAYER_ACTIVATED_STRONG_SWING returning ", thisPlayer.playerAI.texName)
RETURN thisPlayer.fStrongSwingHoldTimer > STRONG_SWING_HOLD_THRESHOLD
ENDFUNC
PROC SET_TENNIS_PLAYER_MARKER_POS(TENNIS_PLAYER &thisPlayer, VECTOR &vNewPos)
thisPlayer.vMarkerPos = vNewPos
ENDPROC
FUNC VECTOR GET_TENNIS_PLAYER_MARKER_POS(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.vMarkerPos
ENDFUNC
PROC RESET_TENNIS_PLAYER_STRONG_SWING_COOLDOWN(TENNIS_PLAYER &thisPlayer)
thisPlayer.fStrongSwingTimer = 0
ENDPROC
PROC UPDATE_TENNIS_PLAYER_STRONG_SWING_COOLDOWN(TENNIS_PLAYER &thisPlayer)
thisPlayer.fStrongSwingTimer += GET_FRAME_TIME()
ENDPROC
/// PURPOSE:
/// determines if the cooldown time between strong swing shots has passed
/// PARAMS:
/// thisPlayer -
/// RETURNS:
/// TRUE if timer > STRONG_SWING_THRESHOLD
FUNC BOOL CAN_TENNIS_PLAYER_USE_STRONG_SWING(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fStrongSwingTimer > STRONG_SWING_THRESHOLD
ENDFUNC
PROC SET_TENNIS_PLAYER_ANALOG_X_VALUE(TENNIS_PLAYER &thisPlayer, INT iExValue)
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_ANALOG_X_VALUE as ", iExValue)
thisPlayer.iAnalogXValue = iExValue
ENDPROC
FUNC INT GET_TENNIS_PLAYER_ANALOG_X_VALUE(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.iAnalogXValue
ENDFUNC
/// PURPOSE:
/// Co-opts the fPow variable to add more power if the player is holding the button
/// PARAMS:
/// thisPlayer -
PROC INCREMENT_TENNIS_PLAYER_POWER_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fPow += GET_FRAME_TIME()
ENDPROC
/// PURPOSE:
/// Resets the fPow, should be used when launching the ball
/// PARAMS:
/// thisPlayer -
PROC RESET_TENNIS_PLAYER_POWER_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fPow = 0
ENDPROC
/// PURPOSE:
/// Used for determining to add power to a swing, NOT FOR SERVES
/// PARAMS:
/// thisPlayer -
/// RETURNS:
/// The fPow timer value in seconds
FUNC FLOAT GET_TENNIS_PLAYER_POWER_TIMER(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fPow
ENDFUNC
/// PURPOSE:
/// Sets the player's fTimer to 0
/// PARAMS:
/// thisPlayer -
PROC RESET_TENNIS_PLAYER_SWING_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fTimer = 0
ENDPROC
/// PURPOSE:
/// Increments the player's fTimer by GET_FRAME_TIME()
/// PARAMS:
/// thisPlayer -
PROC INCREMENT_TENNIS_PLAYER_SWING_TIMER(TENNIS_PLAYER &thisPlayer)
thisPlayer.fTimer += GET_FRAME_TIME()
ENDPROC
/// PURPOSE:
///
/// PARAMS:
/// thisPlayer -
/// RETURNS:
/// Returns the player's fTimer in seconds
FUNC FLOAT GET_TENNIS_PLAYER_SWING_TIMER(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.fTimer
ENDFUNC
#IF IS_DEBUG_BUILD
FUNC STRING GET_SHOT_NAME(SHOT_TYPE_ENUM shot)
SWITCH(shot)
CASE SHOT_NORMAL RETURN "SHOT_NORMAL"
CASE SHOT_TOPSPIN RETURN "SHOT_TOPSPIN"
CASE SHOT_LOB RETURN "SHOT_LOB"
CASE SHOT_BACKSPIN RETURN "SHOT_BACKSPIN"
CASE SHOT_STRONG RETURN "SHOT_STRONG"
CASE SHOT_DROP RETURN "SHOT_DROP"
CASE SERVE RETURN "SERVE"
CASE TOSS RETURN "TOSS"
ENDSWITCH
RETURN "Unknown"
ENDFUNC
#ENDIF
/// PURPOSE:
/// Mutator
/// PARAMS:
/// thisPlayer -
/// newShotType -
PROC SET_TENNIS_PLAYER_STROKE(TENNIS_PLAYER &thisPlayer, SHOT_TYPE_ENUM newShotType)
thisPlayer.ShotType = newShotType
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_STROKE :: ", thisPlayer.playerAI.texName, " with ", GET_SHOT_NAME(newShotType))
#IF IS_DEBUG_BUILD
#IF TENNIS_DEBUG_RECORDING
DEBUG_RECORD_STRING("SET_TENNIS_PLAYER_STROKE", GET_SHOT_NAME(newShotType))
#ENDIF
#ENDIF
ENDPROC
/// PURPOSE:
/// Accessor
/// PARAMS:
/// thisPlayer -
/// RETURNS:
///
FUNC SHOT_TYPE_ENUM GET_TENNIS_PLAYER_STROKE(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.ShotType
ENDFUNC
PROC SET_TENNIS_PLAYER_TO_TENNIS_MODE(PED_INDEX ped, BOOL bEnable)
IF DOES_ENTITY_EXIST(ped) AND NOT IS_PED_INJURED(ped)
CPRINTLN(DEBUG_TENNIS, "IS_TENNIS_PED_MALE: ePed = ", NATIVE_TO_INT(ped))
enumCharacterList ePed = GET_PLAYER_PED_ENUM(ped)
CPRINTLN(DEBUG_TENNIS, "IS_TENNIS_PED_MALE: ePed = ", ePed)
IF ePed = NO_CHARACTER
ePed = GET_NPC_PED_ENUM(ped)
CPRINTLN(DEBUG_TENNIS, "IS_TENNIS_PED_MALE: ePed = NO_CHARACTER, ePed = ", ePed)
ENDIF
BOOL bUseFemaleClipset
#IF NOT IS_TENNIS_MULTIPLAYER
PED_INDEX player = PLAYER_PED_ID()
CPRINTLN(DEBUG_TENNIS, "IS_TENNIS_PED_MALE: player = ", NATIVE_TO_INT(player))
IF ePed = CHAR_MICHAEL
OR ePed = CHAR_FRANKLIN
OR ePed = CHAR_TREVOR
OR ped = player
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_TO_TENNIS_MODE IS_TENNIS_PED_MALE: ePed = ",ePed)
bUseFemaleClipset = FALSE
ELIF IS_PED_MALE(ped)
AND ePed <> CHAR_JIMMY
bUseFemaleClipset = FALSE
ELSE
bUseFemaleClipset = TRUE
ENDIF
#ENDIF
#IF IS_TENNIS_MULTIPLAYER
bUseFemaleClipset = IS_PED_FEMALE(ped)
#ENDIF
CDEBUG2LN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_TO_TENNIS_MODE :: ", PICK_STRING(bEnable, "Enabling Tennis Mode", "Disabling Tennis Mode"), ", bUseFemaleClipset=", PICK_STRING(bUseFemaleClipset, "TRUE", "FALSE"))
ENABLE_TENNIS_MODE(ped, bEnable, bUseFemaleClipset)
DEBUG_PRINTCALLSTACK()
ENDIF
ENDPROC
PROC SET_TENNIS_PLAYER_INDEX(TENNIS_PLAYER &thisPlayer, PED_INDEX new_pIndex)
thisPlayer.pIndex = new_pIndex
ENDPROC
FUNC PED_INDEX GET_TENNIS_PLAYER_INDEX(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.pIndex
ENDFUNC
FUNC TENNIS_SWING_STATES GET_TENNIS_PLAYER_SWING_STATE(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.eSwingState
ENDFUNC
FUNC STRING GET_STRING_FROM_TENNIS_SWING_STATE(TENNIS_SWING_STATES state)
SWITCH(state)
CASE TSS_BACKHAND_TS_HI RETURN "TSS_BACKHAND_TS_HI"
CASE TSS_BACKHAND_TS_MID RETURN "TSS_BACKHAND_TS_MID"
CASE TSS_BACKHAND_TS_LOW RETURN "TSS_BACKHAND_TS_LOW"
CASE TSS_BACKHAND_BS_HI RETURN "TSS_BACKHAND_BS_HI"
CASE TSS_BACKHAND_BS_MID RETURN "TSS_BACKHAND_BS_MID"
CASE TSS_BACKHAND_BS_LOW RETURN "TSS_BACKHAND_BS_LOW"
CASE TSS_FOREHAND_TS_HI RETURN "TSS_FOREHAND_TS_HI"
CASE TSS_FOREHAND_TS_MID RETURN "TSS_FOREHAND_TS_MID"
CASE TSS_FOREHAND_TS_LOW RETURN "TSS_FOREHAND_TS_LOW"
CASE TSS_FOREHAND_BS_HI RETURN "TSS_FOREHAND_BS_HI"
CASE TSS_FOREHAND_BS_MID RETURN "TSS_FOREHAND_BS_MID"
CASE TSS_FOREHAND_BS_LOW RETURN "TSS_FOREHAND_BS_LOW"
CASE TSS_FOREHAND_SMASH RETURN "TSS_FOREHAND_SMASH"
CASE TSS_FOREHAND_SMASH_LEFT RETURN "TSS_FOREHAND_SMASH_LEFT"
CASE TSS_FOREHAND_SMASH_RIGHT RETURN "TSS_FOREHAND_SMASH_RIGHT"
CASE TSS_CLOSE_BH_TS_HI RETURN "TSS_CLOSE_BH_TS_HI"
CASE TSS_CLOSE_BH_TS_MID RETURN "TSS_CLOSE_BH_TS_MID"
CASE TSS_CLOSE_BH_TS_LOW RETURN "TSS_CLOSE_BH_TS_LOW"
CASE TSS_CLOSE_BH_BS_HI RETURN "TSS_CLOSE_BH_BS_HI"
CASE TSS_CLOSE_BH_BS_MID RETURN "TSS_CLOSE_BH_BS_MID"
CASE TSS_CLOSE_BH_BS_LOW RETURN "TSS_CLOSE_BH_BS_LOW"
CASE TSS_CLOSE_FH_TS_HI RETURN "TSS_CLOSE_FH_TS_HI"
CASE TSS_CLOSE_FH_TS_MID RETURN "TSS_CLOSE_FH_TS_MID"
CASE TSS_CLOSE_FH_TS_LOW RETURN "TSS_CLOSE_FH_TS_LOW"
CASE TSS_CLOSE_FH_BS_HI RETURN "TSS_CLOSE_FH_BS_HI"
CASE TSS_CLOSE_FH_BS_MID RETURN "TSS_CLOSE_FH_BS_MID"
CASE TSS_CLOSE_FH_BS_LOW RETURN "TSS_CLOSE_FH_BS_LOW"
CASE TSS_DIVE_BACKHAND RETURN "TSS_DIVE_BACKHAND"
CASE TSS_DIVE_FOREHAND RETURN "TSS_DIVE_FOREHAND"
CASE TSS_LUNGE_BACKHAND_HI RETURN "TSS_LUNGE_BACKHAND_HI"
CASE TSS_LUNGE_BACKHAND_MID RETURN "TSS_LUNGE_BACKHAND_MID"
CASE TSS_LUNGE_BACKHAND_LOW RETURN "TSS_LUNGE_BACKHAND_LOW"
CASE TSS_LUNGE_FOREHAND_HI RETURN "TSS_LUNGE_FOREHAND_HI"
CASE TSS_LUNGE_FOREHAND_MID RETURN "TSS_LUNGE_FOREHAND_MID"
CASE TSS_LUNGE_FOREHAND_LOW RETURN "TSS_LUNGE_FOREHAND_LOW"
CASE TSS_SERVE_TOSS RETURN "TSS_SERVE_TOSS"
CASE TSS_NO_SWING RETURN "TSS_NO_SWING"
CASE TSS_BACKHAND_TS_HI_SKIP RETURN "TSS_BACKHAND_TS_HI_SKIP"
CASE TSS_BACKHAND_TS_MID_SKIP RETURN "TSS_BACKHAND_TS_MID_SKIP"
CASE TSS_BACKHAND_TS_LOW_SKIP RETURN "TSS_BACKHAND_TS_LOW_SKIP"
CASE TSS_BACKHAND_BS_HI_SKIP RETURN "TSS_BACKHAND_BS_HI_SKIP"
CASE TSS_BACKHAND_BS_MID_SKIP RETURN "TSS_BACKHAND_BS_MID_SKIP"
CASE TSS_BACKHAND_BS_LOW_SKIP RETURN "TSS_BACKHAND_BS_LOW_SKIP"
CASE TSS_FOREHAND_TS_HI_SKIP RETURN "TSS_FOREHAND_TS_HI_SKIP"
CASE TSS_FOREHAND_TS_MID_SKIP RETURN "TSS_FOREHAND_TS_MID_SKIP"
CASE TSS_FOREHAND_TS_LOW_SKIP RETURN "TSS_FOREHAND_TS_LOW_SKIP"
CASE TSS_FOREHAND_BS_HI_SKIP RETURN "TSS_FOREHAND_BS_HI_SKIP"
CASE TSS_FOREHAND_BS_MID_SKIP RETURN "TSS_FOREHAND_BS_MID_SKIP"
CASE TSS_FOREHAND_BS_LOW_SKIP RETURN "TSS_FOREHAND_BS_LOW_SKIP"
CASE TSS_FOREHAND_SMASH_SKIP RETURN "TSS_FOREHAND_SMASH_SKIP"
CASE TSS_FOREHAND_SMASH_LEFT_SKIP RETURN "TSS_FOREHAND_SMASH_LEFT_SKIP"
CASE TSS_FOREHAND_SMASH_RIGHT_SKIP RETURN "TSS_FOREHAND_SMASH_RIGHT_SKIP"
CASE TSS_CLOSE_BH_TS_HI_SKIP RETURN "TSS_CLOSE_BH_TS_HI_SKIP"
CASE TSS_CLOSE_BH_TS_MID_SKIP RETURN "TSS_CLOSE_BH_TS_MID_SKIP"
CASE TSS_CLOSE_BH_TS_LOW_SKIP RETURN "TSS_CLOSE_BH_TS_LOW_SKIP"
CASE TSS_CLOSE_BH_BS_HI_SKIP RETURN "TSS_CLOSE_BH_BS_HI_SKIP"
CASE TSS_CLOSE_BH_BS_MID_SKIP RETURN "TSS_CLOSE_BH_BS_MID_SKIP"
CASE TSS_CLOSE_BH_BS_LOW_SKIP RETURN "TSS_CLOSE_BH_BS_LOW_SKIP"
CASE TSS_CLOSE_FH_TS_HI_SKIP RETURN "TSS_CLOSE_FH_TS_HI_SKIP"
CASE TSS_CLOSE_FH_TS_MID_SKIP RETURN "TSS_CLOSE_FH_TS_MID_SKIP"
CASE TSS_CLOSE_FH_TS_LOW_SKIP RETURN "TSS_CLOSE_FH_TS_LOW_SKIP"
CASE TSS_CLOSE_FH_BS_HI_SKIP RETURN "TSS_CLOSE_FH_BS_HI_SKIP"
CASE TSS_CLOSE_FH_BS_MID_SKIP RETURN "TSS_CLOSE_FH_BS_MID_SKIP"
CASE TSS_CLOSE_FH_BS_LOW_SKIP RETURN "TSS_CLOSE_FH_BS_LOW_SKIP"
CASE TSS_FOREHAND_TS_LO_FAR RETURN "TSS_FOREHAND_TS_LO_FAR"
CASE TSS_FOREHAND_TS_MID_FAR RETURN "TSS_FOREHAND_TS_MID_FAR"
CASE TSS_FOREHAND_TS_HI_FAR RETURN "TSS_FOREHAND_TS_HI_FAR"
CASE TSS_CLOSE_BH_LO RETURN "TSS_CLOSE_BH_LO"
CASE TSS_CLOSE_BH_MID RETURN "TSS_CLOSE_BH_MID"
CASE TSS_CLOSE_BH_HI RETURN "TSS_CLOSE_BH_HI"
CASE TSS_CLOSE_FH_LO RETURN "TSS_CLOSE_FH_LO"
CASE TSS_CLOSE_FH_MID RETURN "TSS_CLOSE_FH_MID"
CASE TSS_CLOSE_FH_HI RETURN "TSS_CLOSE_FH_HI"
CASE TSS_MID_BH_LO RETURN "TSS_MID_BH_LO"
CASE TSS_MID_BH_MID RETURN "TSS_MID_BH_MID"
CASE TSS_MID_BH_HI RETURN "TSS_MID_BH_HI"
CASE TSS_WAITING RETURN "TSS_WAITING"
ENDSWITCH
RETURN "!!UNKNOWN!!"
ENDFUNC
FUNC TEXT_LABEL_31 GET_ANIMATION_NAME_FOR_DIVE(TENNIS_DIVE_DiveType type, INT iVecValue)
TEXT_LABEL_31 texReturn = ""
IF (iVecValue < 0 OR iVecValue > 2)
#IF IS_DEBUG_BUILD
#IF TENNIS_DEBUG_RECORDING
TEXT_LABEL_15 anim = iVecValue
DEBUG_RECORD_STRING("GET_ANIMATION_NAME_FOR_DIVE", anim)
#ENDIF
#ENDIF
RETURN texReturn
ENDIF
#IF IS_DEBUG_BUILD
#IF TENNIS_DEBUG_RECORDING
DEBUG_RECORD_STRING("GET_ANIMATION_NAME_FOR_DIVE - type", GET_STRING_FROM_TENNIS_DIVE_SELECTION(type))
#ENDIF
#ENDIF
SWITCH(type)
CASE TENNIS_DIVE_DiveLeft_TopLeft
SWITCH(iVecValue)
CASE 0 texReturn = "dive_bh_long_hi" BREAK
CASE 1 texReturn = "dive_bh_short_hi" BREAK
CASE 2 texReturn = "dive_bh_long_lo" BREAK
ENDSWITCH
BREAK
CASE TENNIS_DIVE_DiveLeft_BottomRight
SWITCH(iVecValue)
CASE 0 texReturn = "dive_bh_long_lo" BREAK
CASE 1 texReturn = "dive_bh_short_hi" BREAK
CASE 2 texReturn = "dive_bh_short_lo" BREAK
ENDSWITCH
BREAK
CASE TENNIS_DIVE_DiveRight_TopLeft
SWITCH(iVecValue)
CASE 0 texReturn = "dive_fh_short_hi" BREAK
CASE 1 texReturn = "dive_fh_long_hi" BREAK
CASE 2 texReturn = "dive_fh_long_lo" BREAK
ENDSWITCH
BREAK
CASE TENNIS_DIVE_DiveRight_BottomRight
SWITCH(iVecValue)
CASE 0 texReturn = "dive_fh_short_hi" BREAK
CASE 1 texReturn = "dive_fh_long_hi" BREAK
CASE 2 texReturn = "dive_fh_long_lo" BREAK
ENDSWITCH
BREAK
ENDSWITCH
RETURN texReturn
ENDFUNC
PROC SET_TENNIS_PLAYER_SWING_STATE(TENNIS_PLAYER &thisPlayer, TENNIS_SWING_STATES newSwingState)
IF thisPlayer.eSwingState = TSS_NO_SWING AND newSwingState <> TSS_NO_SWING
thisPlayer.eSwingState = newSwingState
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_MOVE_ENABLED)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_SWING_STATE ", GET_STRING_FROM_TENNIS_SWING_STATE(newSwingState), ", ", thisPlayer.playerAI.texName)
#ENDIF
ELIF thisPlayer.eSwingState <> TSS_NO_SWING AND newSwingState = TSS_NO_SWING
thisPlayer.eSwingState = newSwingState
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_TENNIS, "SET_TENNIS_PLAYER_SWING_STATE TSS_NO_SWING, ", thisPlayer.playerAI.texName)
#ENDIF
ENDIF
ENDPROC
PROC SET_TENNIS_RACKET(TENNIS_PLAYER &thisPlayer, OBJECT_INDEX thisRacket)
thisPlayer.oTennisRacket = thisRacket
ENDPROC
FUNC OBJECT_INDEX GET_TENNIS_RACKET(TENNIS_PLAYER &thisPlayer)
RETURN thisPlayer.oTennisRacket
ENDFUNC
PROC CLEAR_TENNIS_PLAYER_CONTROL_BITS(TENNIS_PLAYER &thisPlayer)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_AI_HAS_SWUNG)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_CHECK_FOR_OOB)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_CHECK_REACTS)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_DONT_CHASE)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_PLYR_RUN_LR_HELD)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_PREVENT_DBL_SWING)
CLEAR_TENNIS_AI_FLAG(thisPlayer.playerAI, TAF_PREVENT_MP_TENNIS_MODE_UPDATE)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_ALLOW_AI_ASSIST)
// CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_CAN_CHARGE_STRONG_SWING)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_HIT_BY_BALL)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_MISSED_THE_BALL)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_MOVE_ENABLED)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_RAGE_ANIM)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_WANTS_TO_SWING)
CLEAR_TENNIS_PLAYER_FLAG(thisPlayer, TPB_SERVE_EXECUTING)
CPRINTLN(DEBUG_TENNIS, "Control Bits cleared for ped on eCourtSide, ", thisPlayer.playerAI.texName)
ENDPROC
//EOF