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