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

2244 lines
82 KiB
Scheme
Executable File

USING "minigames_helpers.sch"
USING "golf.sch"
USING "golf_mp.sch"
USING "golf_mp_client.sch"
USING "golf_clubs.sch"
USING "golf_course_lib.sch"
USING "golf_swing_meter.sch"
USING "golf_fx_lib.sch"
USING "golf_anims_lib.sch"
USING "shared_hud_displays.sch"
USING "clothes_shop_private.sch"
/// PURPOSE:
/// Requesting all assets needed for golf
/// PARAMS:
/// streamedAssets - asset streaming array for golf
PROC GOLF_STREAM_ASSETS(STREAMED_MODEL &streamedAssets[])
#IF NOT GOLF_IS_MP
ADD_STREAMED_MODEL(streamedAssets, A_M_Y_GOLFER_01)
#IF NOT GOLF_IS_AI_ONLY
ADD_STREAMED_MODEL(streamedAssets, A_M_M_GOLFER_01)
#ENDIF
#ENDIF
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_PUTTER_01)
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_BALL)
ADD_STREAMED_MODEL(streamedAssets, Prop_Golf_Pitcher_01)
#IF NOT PUTTING_GREEN
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_WOOD_01)
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_IRON_01)
ADD_STREAMED_MODEL(streamedAssets, CADDY)
#IF NOT GOLF_IS_AI_ONLY
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_BAG_01B)
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLFFLAG)
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_TEE )
ADD_STREAMED_MODEL(streamedAssets, PROP_GOLF_MARKER_01)
#ENDIF
#ENDIF
REQUEST_ALL_MODELS(streamedAssets)
ENDPROC
PROC GOLF_STREAM_UI(GOLF_HELPERS &thisHelpers)
LOAD_MENU_ASSETS()
REQUEST_ANIM_DICT(GET_GOLF_BASIC_ANIMATION_DICTIONARY_NAME())
REQUEST_ANIM_DICT(GET_GOLF_EXTRA_ANIMATION_DICTIONARY_NAME())
REQUEST_ANIM_DICT(GET_GOLF_IDLE_ANIMATION_DICTIONARY(TRUE))
REQUEST_ANIM_DICT(GET_GOLF_IDLE_ANIMATION_DICTIONARY(FALSE))
REQUEST_ANIM_DICT(GET_HOLE_PREVIEW_ANIM_DICT())
REQUEST_ANIM_DICT(GET_GOLF_REACTION_ANIM_DICT(NULL, FALSE))
IS_END_OF_GOLF_CUTSCENE_LOADED()
#IF NOT GOLF_IS_MP
REQUEST_ANIM_DICT(GET_GOLF_REACTION_ANIM_DICT(PLAYER_PED_ID(), TRUE))
REQUEST_ANIM_DICT(GET_GOLF_REACTION_ANIM_DICT(PLAYER_PED_ID(), FALSE))
REQUEST_ANIM_SET("move_m@golfer@")
#ENDIF
#IF GOLF_IS_MP
REQUEST_ANIM_DICT("reaction@shove")
#ENDIF
thisHelpers.golfUI = REQUEST_SCALEFORM_MOVIE("golf")
thisHelpers.floatingUI = REQUEST_SCALEFORM_MOVIE("golf_floating_ui")
thisHelpers.leaderboardUI = REQUEST_SC_LEADERBOARD_UI()
REQUEST_GOLF_SPLASH_SCALEFORM()
REQUEST_SCRIPT_AUDIO_BANK("GOLF_I")
REQUEST_SCRIPT_AUDIO_BANK("GOLF_2")
REQUEST_SCRIPT_AUDIO_BANK("GOLF_3")
REQUEST_PTFX_ASSET()
REQUEST_STREAMED_TEXTURE_DICT(GET_GOLF_TEXTURE_DICTIONARY_NAME())
#IF GOLF_IS_MP
//REQUEST_SCALEFORM_MOVIE("MPHUD")
#ENDIF
ENDPROC
/// PURPOSE:
/// Checks to see if all assets are streamed for golf
/// PARAMS:
/// streamedAssets - streaming array
/// RETURNS:
/// TRUE if all of the golf assets are streamed
FUNC BOOL GOLF_ASSETS_ARE_STREAMED(GOLF_HELPERS &thisHelpers,STREAMED_MODEL &streamedAssets[])
IF NOT ARE_MODELS_STREAMED(streamedAssets)
CDEBUG1LN(DEBUG_GOLF,"Models not loaded in")
RETURN FALSE
ENDIF
IF NOT HAS_ANIM_DICT_LOADED(GET_GOLF_BASIC_ANIMATION_DICTIONARY_NAME())
CDEBUG1LN(DEBUG_GOLF,"Basic golf dictionanry not loaded in")
RETURN FALSE
ENDIF
IF NOT HAS_ANIM_DICT_LOADED(GET_GOLF_EXTRA_ANIMATION_DICTIONARY_NAME())
CDEBUG1LN(DEBUG_GOLF,"Extra golf dictionanry not loaded in")
RETURN FALSE
ENDIF
#IF NOT GOLF_IS_MP
IF NOT HAS_ANIM_SET_LOADED("move_m@golfer@")
CDEBUG1LN(DEBUG_GOLF,"walking golf dictionanry not loaded in")
RETURN FALSE
ENDIF
#ENDIF
#IF GOLF_IS_MP
IF NOT LOAD_MENU_ASSETS()
CDEBUG1LN(DEBUG_GOLF,"golf menu not loaded in")
RETURN FALSE
ENDIF
#ENDIF
IF NOT HAS_SCALEFORM_MOVIE_LOADED(thisHelpers.golfUI)
CDEBUG1LN(DEBUG_GOLF,"golf UI not loaded in")
RETURN FALSE
ENDIF
IF NOT HAS_SCALEFORM_MOVIE_LOADED(thisHelpers.floatingUI)
CDEBUG1LN(DEBUG_GOLF,"floating UI not loaded in")
RETURN FALSE
ENDIF
IF NOT IS_GOLF_SPLASH_LOADED()
CDEBUG1LN(DEBUG_GOLF,"splash UI not loaded in")
RETURN FALSE
ENDIF
IF NOT REQUEST_SCRIPT_AUDIO_BANK("GOLF_I")
CDEBUG1LN(DEBUG_GOLF,"audio 1 not loaded in")
RETURN FALSE
ENDIF
IF NOT REQUEST_SCRIPT_AUDIO_BANK("GOLF_2")
CDEBUG1LN(DEBUG_GOLF,"audio 2 not loaded in")
RETURN FALSE
ENDIF
IF NOT REQUEST_SCRIPT_AUDIO_BANK("GOLF_3")
CDEBUG1LN(DEBUG_GOLF,"audio 3 not loaded in")
RETURN FALSE
ENDIF
IF NOT HAS_PTFX_ASSET_LOADED()
CDEBUG1LN(DEBUG_GOLF,"PTFX not loaded in")
RETURN FALSE
ENDIF
IF NOT HAS_STREAMED_TEXTURE_DICT_LOADED(GET_GOLF_TEXTURE_DICTIONARY_NAME())
CDEBUG1LN(DEBUG_GOLF,"texture Dictionary not loaded in")
RETURN FALSE
ENDIF
CDEBUG1LN(DEBUG_GOLF,"Everything loaded")
RETURN TRUE
ENDFUNC
FUNC BOOL DOES_PLAYER_OWN_GOLF_HOUSE()
RETURN GET_CURRENT_PROPERTY_OWNER(PROPERTY_GOLF_CLUB) = GET_CURRENT_PLAYER_PED_ENUM()
// RETURN GET_CURRENT_PROPERTY_OWNER(PROPERTY_GOLF_CLUB) != NO_CHARACTER
ENDFUNC
FUNC BOOL DOES_GOLF_NAV_MESH_BLOCKING_OBJECT_EXIST(GOLF_HELPERS &thisHelpers)
IF thisHelpers.iBlockNavMeshIndex < 0
RETURN FALSE
ENDIF
RETURN DOES_NAVMESH_BLOCKING_OBJECT_EXIST(thisHelpers.iBlockNavMeshIndex)
ENDFUNC
FUNC INT GET_GOLF_PLAYER_CASH()
#IF GOLF_IS_MP
RETURN GET_PLAYER_CASH(PLAYER_ID())
#ENDIF
RETURN GET_TOTAL_CASH(GET_CURRENT_PLAYER_PED_ENUM())
ENDFUNC
PROC GOLF_SPEND_CASH(INT iCost)
#IF GOLF_IS_MP
// GIVE_LOCAL_PLAYER_CnC_CASH(-iCost)
// INCREMENT_BY_MP_FLOAT_CHARACTER_STAT(MP_STAT_MONEY_SPENT_IN_STRIP_CLUBS, TO_FLOAT(iCost))
EXIT
#ENDIF
DEBIT_BANK_ACCOUNT(GET_CURRENT_PLAYER_PED_ENUM(), BAAC_LOS_SANTOS_GOLF_CLUB, iCost)
ENDPROC
FUNC MODEL_NAMES GET_GOLF_PED_MODEL(PED_TYPE &pedType, FLOAT fPercentagetMale = 1.01)
IF GET_RANDOM_FLOAT_IN_RANGE() < fPercentagetMale
pedType = PEDTYPE_CIVMALE
RETURN A_M_Y_GOLFER_01
ENDIF
pedType = PEDTYPE_CIVFEMALE
RETURN A_F_Y_GOLFER_01
ENDFUNC
PROC SET_PLAYER_GOLF_OUTFIT(GOLF_HELPERS &thisHelpers)
PED_INDEX playerPed = PLAYER_PED_ID()
GET_PED_VARIATIONS(playerPed, thisHelpers.sPedVariations)
IF NOT DOES_PLAYER_OWN_GOLF_HOUSE()
SetPedCompItemCurrent fpSetPedCompItemCurrent = &SET_PED_COMP_ITEM_CURRENT_SP
REMOVE_ALL_MASKS(playerPed, fpSetPedCompItemCurrent)
REMOVE_PED_HELMET(PLAYER_PED_ID(), TRUE)
SET_GOLF_OUTFIT(playerPed)
CLEAR_PED_WETNESS(playerPed)
ENDIF
ENDPROC
PROC RESET_GOLF_PLAYER_OUTFIT(GOLF_HELPERS &thisHelpers)
SET_PED_VARIATIONS(PLAYER_PED_ID(), thisHelpers.sPedVariations)
CLEAR_PED_WETNESS(PLAYER_PED_ID())
#IF GOLF_IS_MP
FINALIZE_HEAD_BLEND(PLAYER_PED_ID())
#ENDIF
ENDPROC
PROC ADD_GOLF_FOURSOME_TO_GROUP(GOLF_FOURSOME &thisFoursome)
#IF GOLF_IS_AI_ONLY
EXIT
#ENDIF
#IF GOLF_IS_MP
EXIT
#ENDIF
IF NOT DOES_GROUP_EXIST(GET_PED_GROUP_INDEX(PLAYER_PED_ID()))
EXIT //no player group exist?
ENDIF
INT iPlayerIndex
INT iPlayerCartIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, GET_GOLF_FOURSOME_LOCAL_PLAYER(thisFoursome))
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
PED_INDEX pedGolfer = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iPlayerIndex)
IF NOT IS_PED_INJURED(pedGolfer)
IF NOT IS_PED_IN_GROUP(pedGolfer)
//if this golfer is sharing a cart with me
AND iPlayerCartIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, iPlayerIndex)
SET_PED_AS_GROUP_MEMBER(pedGolfer, GET_PED_GROUP_INDEX(PLAYER_PED_ID()))
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC REMOVE_GOLF_FOURSOME_FROM_GROUP(GOLF_FOURSOME &thisFoursome)
#IF GOLF_IS_AI_ONLY
EXIT
#ENDIF
#IF GOLF_IS_MP
EXIT
#ENDIF
IF NOT DOES_GROUP_EXIST(GET_PED_GROUP_INDEX(PLAYER_PED_ID()))
EXIT //no player group exist?
ENDIF
INT iPlayerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
PED_INDEX pedGolfer = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iPlayerIndex)
IF NOT IS_PED_INJURED(pedGolfer)
IF IS_PED_IN_GROUP(pedGolfer)
IF pedGolfer != PLAYER_PED_ID()
REMOVE_PED_FROM_GROUP(pedGolfer)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC SET_GOLF_FOURSOME_RELATIONSHIP_HASH(GOLF_FOURSOME &thisFoursome, GOLF_HELPERS &thisHelpers)
ADD_RELATIONSHIP_GROUP("golferRelGroup", thisHelpers.golfersRelationshipHash)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, thisHelpers.golfersRelationshipHash, RELGROUPHASH_CIVFEMALE)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, thisHelpers.golfersRelationshipHash, RELGROUPHASH_CIVMALE)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, thisHelpers.golfersRelationshipHash, RELGROUPHASH_PLAYER)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, RELGROUPHASH_PLAYER, thisHelpers.golfersRelationshipHash)
INT iPlayerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
IF iPlayerIndex != 0 //player ped should not be added to group
SET_PED_RELATIONSHIP_GROUP_HASH(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iPlayerIndex), thisHelpers.golfersRelationshipHash)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Checks to see if the player is in BALL_RADIUS of the next shot (tee or ball). For free form navigation, tells the game to make the player address the ball
/// PARAMS:
/// thisPlayerCore -
/// RETURNS:
/// TRUE if the player is within BALL_RADIUS of the next shot position, false otherwise
FUNC BOOL GOLF_IS_PLAYER_APPROACHING_BALL(GOLF_PLAYER_CORE &thisPlayerCore)
IF NOT DOES_ENTITY_EXIST(GET_GOLF_PLAYER_PED(thisPlayerCore))
RETURN FALSE
ENDIF
FLOAT fDistSqToBall = VDIST2(GET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisPlayerCore)), GET_GOLF_PLAYER_BALL_POSITION(thisPlayerCore))
IF (fDistSqToBall < (BALL_RADIUS*BALL_RADIUS) OR IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_WAS_IN_CART))
AND (NOT IS_PED_RAGDOLL(GET_GOLF_PLAYER_PED(thisPlayerCore)) AND NOT IS_ENTITY_IN_AIR(GET_GOLF_PLAYER_PED(thisPlayerCore))
AND NOT IS_PED_GETTING_UP(GET_GOLF_PLAYER_PED(thisPlayerCore)))
RETURN TRUE
ENDIF
IF IS_PED_IN_ANY_VEHICLE(GET_GOLF_PLAYER_PED(thisPlayerCore))
IF fDistSqToBall < (BALL_IN_VEHICLE_RADIUS*BALL_IN_VEHICLE_RADIUS)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if any player in a foursome is in BALL_RADIUS of the next shot (tee or ball). For free form navigation, tells the game to make the player address the ball
/// PARAMS:
/// thisFoursome -
/// RETURNS:
/// TRUE if any player is within BALL_RADIUS of the next shot position, false otherwise
FUNC BOOL GOLF_IS_ANY_PLAYER_APPROACHING_BALL(GOLF_FOURSOME &thisFoursome)
INT currentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) currentPlayer
IF GOLF_IS_PLAYER_APPROACHING_BALL(thisFoursome.playerCore[currentPlayer])
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if all players in a foursome have completed their tee shots on the current hole
/// PARAMS:
/// thisFoursome - Foursome to check
/// iExcludeIndex - optional exclusion index - don't check this player
/// RETURNS:
/// TRUE if all players aside from iExcludeIndex have completed their tee shot
FUNC BOOL ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(GOLF_FOURSOME &thisFoursome, INT iExcludeIndex = -1)
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF iExcludeIndex < 0 OR iExcludeIndex != iCurrentPlayer
IF GET_GOLF_PLAYER_SHOTS_ON_HOLE(thisFoursome.playerCore[iCurrentPlayer]) < 1 AND GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisfoursome, iCurrentPlayer) != GPS_DONE_WITH_HOLE
RETURN FALSE
ENDIF
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Checks to see if all players in a foursome have completed their tee shots in their last shot
/// PARAMS:
/// thisFoursome - Foursome to check
/// iExcludeIndex - optional exclusion index - don't check this player
/// RETURNS:
/// TRUE if all players aside from iExcludeIndex have completed their tee shot in the previous shot
FUNC BOOL ARE_ALL_PLAYERS_RECENTLY_DONE_WITH_TEE_SHOT(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, INT iExcludeIndex = -1)
IF NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome, iExcludeIndex)
//CDEBUG1LN(DEBUG_GOLF,"NOT ALL PLAYERS DONE WITH TEE SHOT")
RETURN FALSE
ENDIF
IF NOT WAS_TEE_SHOT(thisCourse, thisFoursome)
//CDEBUG1LN(DEBUG_GOLF,"PREVIOUS LIE IS NOT TEE")
RETURN FALSE
ENDIF
IF IS_TEE_SHOT(thisCourse, thisFoursome)
//CDEBUG1LN(DEBUG_GOLF,"LIE IS STILL TEE")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Checks ot see if a player is done with his current shot
/// PARAMS:
/// thisPlayerCore -
/// RETURNS:
/// TRUE if player has completed his current shot (and its time to move to the next shooter)
FUNC BOOL IS_PLAYER_DONE_WITH_SHOT(GOLF_PLAYER_CORE &thisPlayerCore)
IF GET_GOLF_PLAYER_STATE(thisPlayerCore) = GPS_DONE_WITH_SHOT OR GET_GOLF_PLAYER_STATE(thisPlayerCore) = GPS_DONE_WITH_HOLE
OR IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_PLAYER_REMOVED)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if all players are done with their shots. Not sure if this is currently used
/// PARAMS:
/// thisFoursome -
/// bHumanOnly -
/// RETURNS:
///
FUNC BOOL ARE_ALL_PLAYERS_DONE_WITH_SHOT(GOLF_FOURSOME &thisFoursome, BOOL bHumanOnly = FALSE)
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF GET_GOLF_PLAYER_STATE(thisFoursome.playerCore[iCurrentPlayer]) != GPS_DONE_WITH_SHOT AND (GET_GOLF_PLAYER_CONTROL(thisFoursome.playerCore[iCurrentPlayer]) != COMPUTER OR NOT bHumanOnly)
RETURN FALSE
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Checks to see if any players in a foursome are still on their tee shot
/// PARAMS:
/// thisCourse -
/// thisFoursome -
/// RETURNS:
///
FUNC BOOL IS_ANY_PLAYER_ON_THE_TEE(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome)
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF IS_TEE_SHOT(thisCourse, thisFoursome, iCurrentPlayer)
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL IS_ANY_PLAYER_ON_THE_GREEN(GOLF_FOURSOME &thisFoursome)
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[iCurrentPlayer]) = LIE_GREEN
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL ARE_ALL_PLAYERS_ON_THE_GREEN(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[iCurrentPlayer]) != LIE_GREEN
AND GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[iCurrentPlayer]) != LIE_CUP
AND GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, iCurrentPlayer) != GPS_DONE_WITH_HOLE
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, iCurrentPlayer, GOLF_STROKE_LIMIT)
AND NOT IS_SHOT_LIMIT_EXCEEDED(thisFoursome, thisCourse, iCurrentPlayer)
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, iCurrentPlayer, GOLF_PLAYER_REMOVED)
RETURN FALSE
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
//PURPOSE:
// Checks if any foursome is playing on a hole
//PARAMS:
// thisFoursome[]
// golfHole
FUNC BOOL IS_ANY_GOLF_FOURSOME_PLAYING_HOLE(GOLF_FOURSOME &thisFoursome[], INT golfhole)
int playerIndex
REPEAT COUNT_OF(thisFoursome) playerIndex
IF GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome[playerIndex]) = golfhole
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Returns the index of the golfer closest to the pin
/// PARAMS:
/// playerCore0 -
/// playerCore1 -
/// RETURNS:
///
FUNC INT GET_GOLF_PLAYER_WHOSE_BALL_IS_FARTHER_FROM_PIN(GOLF_FOURSOME &thisFoursome, INT playerIndex0, INT playerIndex1)
IF GET_GOLF_PLAYER_DISTANCE_TO_HOLE(thisFoursome.playerCore[playerIndex0]) > GET_GOLF_PLAYER_DISTANCE_TO_HOLE(thisFoursome.playerCore[playerIndex1])
RETURN playerIndex0
ENDIF
RETURN playerIndex1
ENDFUNC
PROC RESET_FOURSOME_NEXT_GOLFER_WEIGTHS(GOLF_FOURSOME &thisFoursome)
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
thisFoursome.playerCore[playerIndex].iNextGolferWeight = 0
ENDREPEAT
ENDPROC
PROC GOLF_SWAP_POSITIONS(INT &i, INT &j)
INT temp = i
i=j
j=temp
ENDPROC
/// PURPOSE:
/// Uses a bubble sort to figure who goes next based on scores of previous holes. Finally tiebreaks on player index.
/// PARAMS:
/// thisFoursome -
/// allPlayers -
/// iLastHole -
PROC SET_FOURSOME_NEXT_GOLFER_WEIGHT_BASED_ON_WHO_WON_HOLE(GOLF_FOURSOME &thisFoursome, GOLF_PLAYER &allPlayers[], INT iLastHole)
INT placeIndex
#IF NOT GOLF_IS_MP
INT placeAtHole[4]
#ENDIF
#IF GOLF_IS_MP
INT placeAtHole[MP_GOLF_MAX_PLAYERS]
#ENDIF
INT i
INT repeats = 0 // failsafe to ensure we don't loop forever.
INT maxRepeats = 100
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) placeIndex
placeAtHole[placeIndex] = placeIndex
ENDREPEAT
BOOL bSwapped = TRUE
WHILE bSwapped AND repeats < maxRepeats
bSwapped = FALSE
repeats++
i = 1
WHILE i < GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome)
// If thisHoleScore[i] is less than thisHoleScore[i-1] then we swap
IF GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, placeAtHole[i]) < GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, placeAtHole[i-1])
GOLF_SWAP_POSITIONS(placeAtHole[i], placeAtHole[i-1])
bSwapped = TRUE
// otherwise if thisHoleScore[i] equals thisHoleScore[i-1] we move onto the tiebreak
ELIF GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, placeAtHole[i]) = GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, placeAtHole[i-1])
// If the last hole was no the first hole we can tie break on the previous score
IF iLastHole > 0
// tiebreaking on the previous score, if prevHoleScore[i] < prevHoleScore[i-1] we swap
IF GET_GOLF_PLAYER_HOLE_SCORE(allPlayers[placeAtHole[i]], iLastHole-1) < GET_GOLF_PLAYER_HOLE_SCORE(allPlayers[placeAtHole[i-1]], iLastHole-1)
GOLF_SWAP_POSITIONS(placeAtHole[i], placeAtHole[i-1])
bSwapped = TRUE
// If the previous score is a tie then we tiebreak again on player index
ELIF GET_GOLF_PLAYER_HOLE_SCORE(allPlayers[placeAtHole[i]], iLastHole-1) = GET_GOLF_PLAYER_HOLE_SCORE(allPlayers[placeAtHole[i-1]], iLastHole-1)
IF placeAtHole[i] < placeAtHole[i-1]
GOLF_SWAP_POSITIONS(placeAtHole[i], placeAtHole[i-1])
bSwapped = TRUE
ENDIF
ENDIF
// if the last hole is 0 then we tiebreak on player index alone
ELSE
IF placeAtHole[i] < placeAtHole[i-1]
GOLF_SWAP_POSITIONS(placeAtHole[i], placeAtHole[i-1])
bSwapped = TRUE
ENDIF
ENDIF
ENDIF
i++
ENDWHILE
ENDWHILE
//placeAtHole now has the player index in order of who won the hole, adjust weights with the winner getting the biggest weight
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) placeIndex
thisFoursome.playerCore[placeAtHole[placeIndex]].iNextGolferWeight = (GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome)-1)-placeIndex
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Finds the next shooter in a foursome, the player who's ball is the farthest from the pin
/// PARAMS:
/// thisFoursome - Foursome to check
/// RETURNS:
/// Index of the player who's ball is farthest from the pin
FUNC INT FIND_NEXT_SHOOTER(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
FLOAT fFarthestShot = 0.0
INT iFarthestPlayer = -1
INT iCurrentPlayer
FLOAT fCurrentAdjustedDistance
IF GET_GOLF_FOURSOME_CURRENT_PLAYER_DISTANCE_TO_HOLE(thisFoursome) < (DIST_FOR_GIMMIE*DIST_FOR_GIMMIE) AND GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_GREEN
AND GET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome) != GPS_DONE_WITH_HOLE AND ARE_ALL_PLAYERS_ON_THE_GREEN(thisFoursome, thisCourse)
#IF NOT GOLF_IS_AI_ONLY
CDEBUG1LN(DEBUG_GOLF,"Golfer goes again for gimmie shot")
#ENDIF
RETURN GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)
ENDIF
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, iCurrentPlayer) != CONTROL_NONE
IF GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, iCurrentPlayer) != GPS_DONE_WITH_HOLE
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, iCurrentPlayer, GOLF_PLAYER_REMOVED)
VECTOR vStartPos, vEndPos
vStartPos = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, iCurrentPlayer)
vEndPos = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
vStartPos.z = 0
vEndPos.z = 0 //only 2d distance
fCurrentAdjustedDistance = VDIST(vStartPos, vEndPos)
fCurrentAdjustedDistance *= PICK_FLOAT(GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[iCurrentPlayer]) = LIE_GREEN, 1, 99999)
fCurrentAdjustedDistance *= PICK_FLOAT(GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[iCurrentPlayer]) = LIE_TEE, 100, 1)
fCurrentAdjustedDistance *= (thisFoursome.playerCore[iCurrentPlayer].iNextGolferWeight+1)
//fCurrentAdjustedDistance *= PICK_FLOAT(GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, iCurrentPlayer) != 0, 1, 100)
IF fCurrentAdjustedDistance > fFarthestShot
iFarthestPlayer = iCurrentPlayer
fFarthestShot = fCurrentAdjustedDistance
ENDIF
ENDIF
ENDIF
ENDREPEAT
IF iFarthestPlayer = -1
iFarthestPlayer = 0
ENDIF
IF bDebugSpew CDEBUG1LN(DEBUG_GOLF,"Next player is ", iFarthestPlayer) ENDIF
RETURN iFarthestPlayer
ENDFUNC
PROC MANAGE_CURRENT_ESTIMATE_BLIP(GOLF_HELPERS &thisHelpers, VECTOR vBlipLocation, INT iColour, BLIP_SPRITE blipSprtie = RADAR_TRACE_INVALID)
IF IS_VECTOR_ZERO(vBlipLocation)
EXIT
ENDIF
IF NOT DOES_BLIP_EXIST(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers))
SET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers, CREATE_BLIP_FOR_COORD(vBlipLocation))
ENDIF
IF DOES_BLIP_EXIST(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers))
SET_BLIP_COLOUR( GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), iColour)
IF NOT ARE_VECTORS_EQUAL(GET_BLIP_COORDS(GET_GOLF_HELPER_ESTIMATE_BLIP( thisHelpers)), vBlipLocation)
SET_BLIP_COORDS( GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), vBlipLocation)
ENDIF
SET_BLIP_PRIORITY(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), BLIPPRIORITY_HIGHEST)
SHOW_HEIGHT_ON_BLIP(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), FALSE)
IF blipSprtie != RADAR_TRACE_INVALID
IF GET_BLIP_SPRITE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers)) != blipSprtie
CDEBUG1LN(DEBUG_GOLF,"Setting estimate blip sprite to ", blipSprtie)
CDEBUG1LN(DEBUG_GOLF,"Current sprite ", GET_BLIP_SPRITE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers)))
SET_BLIP_SPRITE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), blipSprtie)
SET_BLIP_NAME_FROM_TEXT_FILE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), "SHOT_EST")
ENDIF
ELSE
SET_BLIP_SCALE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers), GOLF_BALL_BLIP_SCALE)
ENDIF
// CDEBUG1LN(DEBUG_GOLF,"Blip sprite ", GET_BLIP_SPRITE(GET_GOLF_HELPER_ESTIMATE_BLIP(thisHelpers)))
ENDIF
ENDPROC
FUNC BOOL HAS_ANY_GOLFER_TAKEN_A_SHOT_THIS_HOLE(GOLF_FOURSOME &thisFoursome)
INT iPlayerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
IF GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, iPlayerIndex) > 0
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL FIND_SAFE_SPOT_FOR_CART(VECTOR vOrigin, VECTOR vDestination, VECTOR &vNearby, FLOAT &fNearbyHeading, VECTOR vShotDir, VECTOR vFrontCheckOrigin, BOOL inFrontCheck = FALSE)
BOOL bFoundSpot
INT iSpotIndex = 1
INT iReturnLanes
VECTOR locationToNewSpot = <<0,0,0>>
WHILE NOT bFoundSpot
AND iSpotIndex < 10
IF NOT GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING( vOrigin, iSpotIndex, vNearby, fNearbyHeading, iReturnLanes)
RETURN FALSE
ELSE
IF VDIST2(vOrigin, vNearby) > 100
AND NOT IS_ANY_VEHICLE_NEAR_POINT(vNearby, 5.0)
#IF NOT GOLF_IS_MP
AND NOT IS_GOLF_COORD_OUTSIDE_BOUNDARY_PLANES(vNearby)
#ENDIF
locationToNewSpot= NORMALISE_VECTOR(<<vNearby.x, vNearby.y, 0>> - <<vFrontCheckOrigin.x, vFrontCheckOrigin.y, 0>>)
//CDEBUG1LN(DEBUG_GOLF,vNearby, " ", vDestination)
//CDEBUG1LN(DEBUG_GOLF,vShotDir, " ",locationToNewSpot , " ", DOT_PRODUCT_XY(vShotDir, locationToNewSpot))
IF NOT inFrontCheck OR DOT_PRODUCT_XY(vShotDir, locationToNewSpot) < 0.75
bFoundSpot = TRUE
ENDIF
ENDIF
ENDIF
iSpotIndex++
ENDWHILE
// Lets make sure the heading is actually pointing toward the hole, otherwise turn 180
IF ABSF(GET_HEADING_FROM_VECTOR_2D (vDestination.x - vOrigin.x, vDestination.y - vOrigin.y) - fNearbyHeading) > 90
fNearbyHeading += 180
ENDIF
GOLF_FIND_GROUND_Z(vNearby, 5.0, 0.5)
RETURN TRUE
ENDFUNC
FUNC BOOL FIND_SAFE_SPOT_FOR_CART_FAST(VECTOR vOrigin, VECTOR vDestination, VECTOR &vNearby, FLOAT &fNearbyHeading)
IF NOT GET_CLOSEST_VEHICLE_NODE_WITH_HEADING( vOrigin, vNearby, fNearbyHeading)
RETURN FALSE
ENDIF
// Lets make sure the heading is actually pointing toward the hole, otherwise turn 180
IF ABSF(GET_HEADING_FROM_VECTOR_2D (vDestination.x - vOrigin.x, vDestination.y - vOrigin.y) - fNearbyHeading) > 90
fNearbyHeading += 180
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL IS_CART_FAR_FROM_BALL(GOLF_FOURSOME &thisFoursome, VEHICLE_INDEX vehIndex)
IF NOT DOES_ENTITY_EXIST(vehIndex)
RETURN FALSE
ENDIF
IF IS_ENTITY_DEAD(vehIndex)
RETURN FALSE
ENDIF
RETURN VDIST2(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome), GET_ENTITY_COORDS(vehIndex)) > (40.0 * 40.0)
ENDFUNC
FUNC BOOL IS_CART_BLOCKING_PLAYERS_SHOT(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, VEHICLE_INDEX thisVehicle)
IF NOT DOES_ENTITY_EXIST(thisVehicle)
RETURN FALSE
ENDIF
VECTOR vHolePosition = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
VECTOR ballPos = GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)
VECTOR vShotDir = NORMALISE_VECTOR(<<vHolePosition.x, vHolePosition.y,0>> - <<ballPos.x, ballPos.y,0>>)
VECTOR vVehCoords = GET_ENTITY_COORDS(thisVehicle, FALSE)
IF DOT_PRODUCT_XY(vShotDir, NORMALISE_VECTOR(vVehCoords - ballPos)) < 0.75 AND VDIST2(ballPos, vVehCoords) > 5.0*5.0
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
PROC MOVE_GOLF_PLAYER_CART_TO_SAFE_LOCATION(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, VECTOR vDestination, VEHICLE_INDEX thisVehicle, INT cartIndex)
IF NOT DOES_ENTITY_EXIST(thisVehicle)
EXIT
ENDIF
IF IS_ENTITY_DEAD(thisVehicle)
EXIT
ENDIF
cartIndex = cartIndex
VECTOR newCartPosition
FLOAT newCartHeading
VECTOR vHolePosition = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
VECTOR ballPos = GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)
VECTOR shotDirection = NORMALISE_VECTOR(<<vHolePosition.x, vHolePosition.y,0>> - <<ballPos.x, ballPos.y,0>>)
//find safe spot for cart behind the ball
IF FIND_SAFE_SPOT_FOR_CART(ballPos, vDestination, newCartPosition, newCartHeading, shotDirection, ballPos, TRUE)
SET_ENTITY_HEADING(thisVehicle, newCartHeading)
IF NOT GOLF_FIND_GROUND_Z(newCartPosition)
EXIT //can't find good spot just get out
ENDIF
SET_ENTITY_COORDS(thisVehicle, newCartPosition)
//we put it somewhere that blocked its door.
IF NOT IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), thisVehicle, VS_DRIVER)
CDEBUG1LN(DEBUG_GOLF,"Can't get in cart, move it a little bit")
VECTOR vMoveDirection = GET_ENTITY_FORWARD_VECTOR(thisVehicle)
vMoveDirection.z = 0
vMoveDirection = NORMALISE_VECTOR(vMoveDirection)
vMoveDirection = ROTATE_VECTOR_ABOUT_Z_ORTHO(vMoveDirection, ROTSTEP_NEG_90)
newCartPosition += vMoveDirection *0.5
IF NOT GOLF_FIND_GROUND_Z(newCartPosition)
EXIT //can't find good spot just get out
ENDIF
SET_ENTITY_COORDS(thisVehicle, newCartPosition)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Creates a golf ball and sets up its physics properties
/// PARAMS:
/// vPosition - Location to create the ball
/// fHeading - Heading to create the ball with
/// RETURNS:
/// OBJECT_INDEX for the new ball
FUNC OBJECT_INDEX CREATE_GOLF_BALL(VECTOR vPosition, FLOAT fHeading)
IF ARE_VECTORS_ALMOST_EQUAL(vPosition, <<0,0,0>>)
SCRIPT_ASSERT("Trying to create a golf ball at 0,0,0.")
RETURN NULL
ENDIF
OBJECT_INDEX newBall
#IF NOT GOLF_IS_MP
newBall = CREATE_OBJECT(PROP_GOLF_BALL, vPosition)
#ENDIF
#IF GOLF_IS_MP
NETWORK_INDEX newNetBall
CREATE_NET_OBJ(newNetBall, PROP_GOLF_BALL, vPosition, TRUE)
newBall = GET_OBJECT_INDEX_FROM_ENTITY_INDEX( NETWORK_GET_ENTITY_FROM_NETWORK_ID(newNetBall ))
SET_NETWORK_ID_CAN_MIGRATE(newNetBall,FALSE)
// SET_NETWORK_ID_CAN_BE_REASSIGNED(newNetBall,FALSE)
SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(newNetBall, TRUE)
NETWORK_USE_HIGH_PRECISION_BLENDING(newNetBall, TRUE)
NETWORK_SET_OBJECT_CAN_BLEND_WHEN_FIXED(NET_TO_OBJ(newNetBall), TRUE)
#ENDIF
SET_OBJECT_IS_SPECIAL_GOLFBALL(newBall)
SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(newBall, FALSE)
SET_ENTITY_HEADING( newBall, fHeading)
IF bDebugSpew DEBUG_MESSAGE("CREATE BALL") ENDIF
RETURN newBall
ENDFUNC
FUNC OBJECT_INDEX CREATE_GOLF_BALL_MARKER(GOLF_FOURSOME &thisFoursome, INT playerIndex)
OBJECT_INDEX newMarker
VECTOR markerPos = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, playerIndex)
GET_GROUND_Z_FOR_3D_COORD(markerPos, markerPos.z)
newMarker = CREATE_OBJECT(PROP_GOLF_MARKER_01, markerPos, FALSE)
IF DOES_ENTITY_EXIST(newMarker)
SET_ENTITY_COLLISION(newMarker, FALSE)
ENDIF
RETURN newMarker
ENDFUNC
PROC CREATE_TEE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
VECTOR vTeePos = GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) - <<0.0, 0.0, 0.017>>
// CDEBUG1LN(DEBUG_GOLF, "Set Tee Pos to ", vTeePos)
IF NOT DOES_ENTITY_EXIST(thisFoursome.objTee)
thisFoursome.objTee = CREATE_OBJECT(PROP_GOLF_TEE, vTeePos, FALSE)
SET_ENTITY_COLLISION(thisFoursome.objTee, FALSE)
FREEZE_ENTITY_POSITION(thisFoursome.objTee, TRUE)
ELSE
SET_ENTITY_COLLISION(thisFoursome.objTee, FALSE)
FREEZE_ENTITY_POSITION(thisFoursome.objTee, FALSE)
SET_ENTITY_COORDS(thisFoursome.objTee, vTeePos + <<0.0, 0.0, 0.035>>)
FREEZE_ENTITY_POSITION(thisFoursome.objTee, TRUE)
ENDIF
ENDPROC
PROC DELETE_TEE(GOLF_FOURSOME &thisFoursome)
IF DOES_ENTITY_EXIST(thisFoursome.objTee)
DELETE_OBJECT(thisFoursome.objTee)
ENDIF
ENDPROC
FUNC BOOL IS_PLAYER_READY_TO_ADDRESS(GOLF_FOURSOME &thisFoursome)
IF IS_PLAYER_ON_PUTTING_GREEN()
OR IS_GOLF_FOURSOME_CURRENT_PLAYER_PUTTING(thisFoursome)
IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), SCRIPT_TASK_PERFORM_SEQUENCE) = PERFORMING_TASK
IF GET_SEQUENCE_PROGRESS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) = 2
RETURN TRUE
ENDIF
ENDIF
ELSE
IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), SCRIPT_TASK_PERFORM_SEQUENCE) != PERFORMING_TASK
AND GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), SCRIPT_TASK_PERFORM_SEQUENCE) != WAITING_TO_START_TASK
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Places a given player at his next shot and aiming in a direction. Creates a new club if necessary
/// PARAMS:
/// thisPlayerCore -
/// golfBag -
/// fHeading -
/// bSnapToBall -
PROC PLACE_PLAYER_AT_BALL_WITH_HEADING(GOLF_PLAYER_CORE &thisPlayerCore, GOLF_BAG &golfBag, FLOAT fHeading, BOOL bClearTask, BOOL bUseNetWarp, BOOL bSnapToBall = TRUE, BOOL bRecreateClub = FALSE, BOOL startIdleNow = FALSE)
IF GET_GOLF_PLAYER_CONTROL(thisPlayerCore) = COMPUTER
TASK_STAND_STILL(GET_GOLF_PLAYER_PED(thisPlayerCore), -1)
ELSE
//only AI gets tasked to walk to ball
bSnapToBall = TRUE
ENDIF
eCLUB_TYPE clubType = GET_GOLF_CLUB_TYPE(golfBag, GET_GOLF_PLAYER_CURRENT_CLUB(thisPlayerCore))
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_PLAYER_REPOSITIONED)
SET_GOLF_PLAYER_AIM(thisPlayerCore, fHeading)
#IF NOT GOLF_IS_AI_ONLY
CDEBUG1LN(DEBUG_GOLF,"PLACE_PLAYER_AT_BALL_WITH_HEADING: The clubType = ", clubType, ". placement offset = ", GET_STRING_FROM_VECTOR(GET_GOLF_CLUB_PLACEMENT_OFFSET(clubType)))
DEBUG_PRINTCALLSTACK()
#ENDIF
VECTOR newPlayerPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(GET_GOLF_PLAYER_BALL_POSITION(thisPlayerCore), GET_GOLF_PLAYER_AIM(thisPlayerCore), GET_GOLF_CLUB_PLACEMENT_OFFSET(clubType))
VECTOR vCurrentPlayerHeight = GET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisPlayerCore))
FLOAT fHeight
IF bClearTask
CLEAR_PED_TASKS_IMMEDIATELY(GET_GOLF_PLAYER_PED(thisPlayerCore))
ENDIF
IF bSnapToBall OR IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_FAR_AWAY)
IF GET_GOLF_PLAYER_CONTROL(thisPlayerCore) != COMPUTER
GOLF_FIND_GROUND_Z(vCurrentPlayerHeight, 100.0, 0.0)
ENDIF
IF GET_GROUND_Z_FOR_3D_COORD(newPlayerPos+<<0,0,1>>, fHeight)
IF ABSF(fHeight- vCurrentPlayerHeight.z) < 0.35 //don't allow a dramtic change in height
OR fHeight < newPlayerPos.z OR startIdleNow
newPlayerPos.z = fHeight
ENDIF
ENDIF
IF bUseNetWarp AND IS_GOLF_FOURSOME_MP()
NET_WARP_TO_COORD(newPlayerPos, GET_GOLF_PLAYER_AIM(thisPlayerCore), FALSE, FALSE)
ELSE
BOOL bControlEntity = TRUE
#IF GOLF_IS_MP
bControlEntity = NETWORK_HAS_CONTROL_OF_ENTITY(GET_GOLF_PLAYER_PED(thisPlayerCore))
#ENDIF
IF bControlEntity
SET_ENTITY_HEADING(GET_GOLF_PLAYER_PED(thisPlayerCore), GET_GOLF_PLAYER_AIM(thisPlayerCore))
SET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisPlayerCore), newPlayerPos, FALSE, TRUE, TRUE)
#IF NOT GOLF_IS_AI_ONLY
SET_PED_CAN_ARM_IK(GET_GOLF_PLAYER_PED(thisPlayerCore), FALSE)
CDEBUG1LN(DEBUG_GOLF,"Setting player pos to ", newPlayerPos, " Setting heading to ", GET_GOLF_PLAYER_AIM(thisPlayerCore))
#ENDIF
ELSE
CDEBUG1LN(DEBUG_GOLF, "Golf place player mp. Player ped ", NATIVE_TO_INT(PLAYER_PED_ID()), " golfer ped ", NATIVE_TO_INT(GET_GOLF_PLAYER_PED(thisPlayerCore)))
CASSERTLN(DEBUG_GOLF, "PLACE_PLAYER_AT_BALL_WITH_HEADING - Called when you don't own the current player ped.")
ENDIF
ENDIF
ELSE
CLEAR_PED_TASKS(GET_GOLF_PLAYER_PED(thisPlayerCore))
// CDEBUG1LN(DEBUG_GOLF, "PLACE_PLAYER_AT_BALL_WITH_HEADING: Should be approaching ball right now")
OPEN_SEQUENCE_TASK(thisPlayerCore.seq_swing_and_outro)
//TASK_STAND_STILL(NULL, 3000)
IF IS_PLAYER_ON_PUTTING_GREEN() OR IS_GOLF_PLAYER_PUTTING(thisPlayerCore)
TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, newPlayerPos, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_STOP_EXACTLY, fHeading)
TASK_PLAY_ANIM(NULL, "mini@golfai", "putt_approach_no_ball", REALLY_SLOW_BLEND_IN, SLOW_BLEND_OUT, -1)
TASK_PLAY_ANIM(NULL, "mini@golfai", "putt_approach_no_ball", SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_HOLD_LAST_FRAME, 0.999)
ELSE
TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, newPlayerPos, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_STOP_EXACTLY, fHeading)
ENDIF
CLOSE_SEQUENCE_TASK(thisPlayerCore.seq_swing_and_outro)
TASK_PERFORM_SEQUENCE(GET_GOLF_PLAYER_PED(thisPlayerCore), thisPlayerCore.seq_swing_and_outro)
CLEAR_SEQUENCE_TASK(thisPlayerCore.seq_swing_and_outro)
ENDIF
#IF NOT GOLF_IS_AI_ONLY
thisPlayerCore.vAddressBallPos = newPlayerPos
#ENDIF
IF startIdleNow
CDEBUG1LN(DEBUG_GOLF,"startIdleNow")
// IF IS_GOLF_FOURSOME_MP()
// CLEAR_PED_TASKS_IMMEDIATELY(GET_GOLF_PLAYER_PED(thisPlayerCore))
// ENDIF
GOLF_FORCE_IDLE_ANIMATION(thisPlayerCore, golfBag)
ENDIF
IF bRecreateClub AND NOT IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_FAR_AWAY)
GOLF_ATTACH_CLUB_TO_PLAYER(thisPlayerCore, golfBag)
ENDIF
ENDPROC
/// PURPOSE:
/// Places a given player at his next shot and aiming toward the pin
/// PARAMS:
/// thisCourse -
/// thisFoursome -
/// golfBag -
/// bSnapToBall -
PROC PLACE_PLAYER_AT_BALL(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, GOLF_BAG &golfBag, BOOL bUseNetWarp, BOOL bSnapToBall = TRUE, BOOL bIsTeeShot = FALSE, BOOL bRecreateClub = FALSE, BOOL startIdleNow = FALSE)
VECTOR aimSpot
IF bIsTeeShot
aimSpot = GET_GOLF_HOLE_FAIRWAY_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
ELSE
aimSpot= GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
ENDIF
FLOAT aim = GET_HEADING_BETWEEN_VECTORS(aimSpot, GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome))+90
PLACE_PLAYER_AT_BALL_WITH_HEADING(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], golfBag, aim, FALSE, bUseNetWarp, bSnapToBall, bRecreateClub, startIdleNow)
ENDPROC
/// PURPOSE:
/// Resets a golf ball (ie destroys and recreates) a golf ball once it is in the hole. Does all of the scoring elements also
/// PARAMS:
/// thisCourse -
/// thisPlayer -
/// thisFoursome -
PROC GOLF_RESET_BALL_IN_HOLE(GOLF_GAME &thisGame, GOLF_PLAYER &thisPlayer, GOLF_FOURSOME &thisFoursome, GOLF_HELPERS &thisHelpers)
UNUSED_PARAMETER(thisGame)
INCREMENT_GOLF_PLAYER_CURRENT_SCORE(thisPlayer, GET_GOLF_PLAYER_HOLE_SCORE(thisPlayer, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)))
CLEANUP_GOLF_HELPER_HOLE_BLIP(thisHelpers)
ENDPROC
/// PURPOSE:
/// Checks global wind and sets it up for golf
/// PARAMS:
/// thisGame -
PROC GRAB_WIND_FOR_HOLE(GOLF_GAME &thisGame, GOLF_FOURSOME &thisFoursome, INT iWeather)// #IF NOT GOLF_IS_AI_ONLY , GOLF_HELPERS &thisHelpers #ENDIF)
#IF IS_DEBUG_BUILD
#IF NOT GOLF_IS_AI_ONLY
IF bUseDebugWind
EXIT
ENDIF
#ENDIF
#ENDIF
#IF GOLF_IS_AI_ONLY
thisGame.fWindStrength = 0
EXIT
#ENDIF
// FLOAT fWeatherEffect = 1.0
FLOAT fRainMax = 10.0
FLOAT fRainMin = 5.0
FLOAT fClearMax = 6.0
FLOAT fClearMin = 1.0
FLOAT fNewValue
//EXTRASUNNY, CLEAR, CLOUDS, SMOG, CLOUDY, OVERCAST, RAIN, THUNDER, CLEARING, NEUTRAL, SNOW, MULTIPLAYER
IF IS_PREV_WEATHER_TYPE("RAIN")
OR IS_PREV_WEATHER_TYPE("THUNDER")
OR IS_PREV_WEATHER_TYPE("OVERCAST")
// fWeatherEffect = 1.2
iWeather = ciGOLF_OPTION_RAINING
CDEBUG1LN(DEBUG_GOLF, "Using rain wind modifier")
ENDIF
IF thisGame.fWindStrength = 0 //init wind strength
IF iWeather = ciGOLF_OPTION_RAINING
thisGame.fWindStrength = GET_RANDOM_FLOAT_IN_RANGE(fRainMin, fRainMax-2.0)
ELSE
thisGame.fWindStrength = GET_RANDOM_FLOAT_IN_RANGE(fClearMin, fClearMax-2.0)
ENDIF
CDEBUG1LN(DEBUG_GOLF, "Init wind strength to ", thisGame.fWindStrength)
ELSE
fNewValue = GET_RANDOM_FLOAT_IN_RANGE(-1.0, 1.0)
fNewValue = PICK_FLOAT(ABSF(fNewValue) < 0.1, 1.0, fNewValue) //10% chance of big increase
fNewValue /= GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome)
thisGame.fWindStrength += fNewValue
CDEBUG1LN(DEBUG_GOLF, "Inc wind strength by ", fNewValue)
ENDIF
IF iWeather = ciGOLF_OPTION_RAINING
IF thisGame.fWindStrength < fRainMin
thisGame.fWindStrength = fRainMin
ELIF thisGame.fWindStrength > fRainMax
thisGame.fWindStrength = fRainMax
ENDIF
ELSE
IF thisGame.fWindStrength < fClearMin
thisGame.fWindStrength = fClearMin
ELIF thisGame.fWindStrength > fClearMax
thisGame.fWindStrength = fClearMax
ENDIF
ENDIF
IF thisGame.vWindDirection.z = 0 //wind not intialized
thisGame.vWindDirection = GET_WIND_DIRECTION()
thisGame.vWindDirection = NORMALISE_VECTOR(thisGame.vWindDirection)
thisGame.vWindDirection.z = 1
ELSE
thisGame.vWindDirection.z = 0
thisGame.vWindDirection.x += GET_RANDOM_FLOAT_IN_RANGE(-0.3, 0.3)
thisGame.vWindDirection.y += GET_RANDOM_FLOAT_IN_RANGE(-0.3, 0.3)
thisGame.vWindDirection = NORMALISE_VECTOR(thisGame.vWindDirection)
thisGame.vWindDirection.z = 1
ENDIF
CDEBUG1LN(DEBUG_GOLF, "Wind Speed ", thisGame.fWindStrength)
CDEBUG1LN(DEBUG_GOLF, "Wind Direction ", thisGame.vWindDirection)
ENDPROC
FUNC BOOL IS_NEXT_GOLF_HOLE_AVAILABLE(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, GOLF_FOURSOME &allAIFoursomes[], INT holeOffset = 1)
INT foursomeIndex
INT nextHole = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)+holeOffset
IF nextHole >= GET_GOLF_COURSE_NUM_HOLES(thisCourse)
nextHole = 0
ENDIF
REPEAT COUNT_OF(allAIFoursomes) foursomeIndex
IF GET_GOLF_FOURSOME_CURRENT_HOLE(allAIFoursomes[foursomeIndex]) = nextHole
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(allAIFoursomes[foursomeIndex], 0, GOLF_WAITING_FOR_HOLE)
RETURN FALSE
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
FUNC BOOL ARE_ALL_PLAYERS_REMOVED_FROM_GOLF_GAME(GOLF_FOURSOME &thisFoursome)
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_PLAYER_REMOVED)
RETURN FALSE
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
PROC GOLF_REMOVE_AI_PED(GOLF_FOURSOME &thisFoursome, INT playerIndex)
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex))
AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex))
IF NOT HAS_ENTITY_CLEAR_LOS_TO_ENTITY(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), PLAYER_PED_ID())
DELETE_PED(thisFoursome.playerCore[ playerIndex].pedGolfPlayer)
EXIT
ELIF NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_PLAYER_REMOVED)
TASK_SMART_FLEE_PED(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), PLAYER_PED_ID(), FAR_AWAY_THRESHOLD, -1)
ENDIF
IF IS_PED_IN_MELEE_COMBAT(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex))
CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex))
TASK_SMART_FLEE_PED(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), PLAYER_PED_ID(), FAR_AWAY_THRESHOLD, -1)
ENDIF
ENDIF
SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, playerIndex, GOLF_PLAYER_REMOVED)
ENDPROC
PROC GOLF_REMOVE_AI_FOURSOME(GOLF_FOURSOME &thisFoursome)
INT playerCount
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerCount
CLEANUP_GOLF_FOURSOME_INDEXED_GOLF_BALL(thisFoursome, playerCount)
CLEANUP_GOLF_CLUB(thisFoursome.playerCore[playerCount])
CLEANUP_GOLF_GOLFBAG(thisFoursome.playerCore[playerCount])
IF DOES_ENTITY_EXIST(thisFoursome.playerCore[playerCount].pedGolfPlayer) AND NOT IS_ENTITY_DEAD(thisFoursome.playerCore[playerCount].pedGolfPlayer)
CLEAR_PED_TASKS(thisFoursome.playerCore[playerCount].pedGolfPlayer)
ENDIF
GOLF_REMOVE_AI_PED(thisFoursome, playerCount)
ENDREPEAT
SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, -2)
ENDPROC
FUNC BOOL ARE_ALL_GOLFERS_IN_CART(GOLF_FOURSOME &thisFoursome, INT startIndex = 0)
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF playerIndex >= startIndex
IF NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)) AND NOT IS_ENTITY_DEAD( GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex))
IF NOT IS_PED_IN_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex))
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_PLAYER_REMOVED)
AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_STOP_USING_CART)
RETURN FALSE
ENDIF
ENDIF
ENDIF
ENDREPEAT
RETURN TRUE
ENDFUNC
PROC TELEPORT_GOLFER_TO_COORD(GOLF_FOURSOME &thisFoursome, INT playerIndex, VECTOR coord, GOLF_COURSE &thisCourse, BOOL snapToGround, BOOL teleportCart = TRUE)
//do not teleport the golfer in mid air
FLOAT fHeight
IF snapToGround
IF GET_GROUND_Z_FOR_3D_COORD (coord + <<0,0,50.0>>, fHeight)
coord.z = fHeight
ENDIF
ENDIF
SET_ENTITY_COORDS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), coord, FALSE)
INT cartIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, playerIndex)
//move cart
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex)) AND teleportCart
VECTOR cartSpawnPos = << 0,0,0 >>
VECTOR cartOffset = <<0,0,0>>
FLOAT cartHeading = 0
BOOL foundSafeSpot
IF cartIndex > 0
cartOffset = <<5,5,0>>
ENDIF
IF NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex))
IF IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_FAR_AWAY)
foundSafeSpot = FIND_SAFE_SPOT_FOR_CART_FAST(coord+ cartOffset, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), cartSpawnPos, cartHeading)
ELSE
foundSafeSpot =FIND_SAFE_SPOT_FOR_CART(coord+ cartOffset, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), cartSpawnPos, cartHeading, <<0,0,0>>, <<0,0,0>>)
ENDIF
IF foundSafeSpot AND NOT IS_SPHERE_VISIBLE(cartSpawnPos, 5.0)
SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex), cartSpawnPos)
SET_ENTITY_HEADING(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex), cartHeading)
ENDIF
ENDIF
ENDIF
ENDPROC
//Teleports a golfer and his cart to his ball
PROC TELEPORT_GOLFER_TO_BALL(GOLF_FOURSOME &thisFoursome, INT playerIndex, GOLF_COURSE &thisCourse, BOOL snapToGround, BOOL teleportCart = TRUE)
TELEPORT_GOLFER_TO_COORD(thisFoursome, playerIndex, GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, playerIndex), thisCourse, snapToGround, teleportCart)
ENDPROC
PROC TELEPORT_FOURSOME_TO_TEE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, BOOL teleportCart = TRUE)
INT playerIndex
INT holeIndex = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)
//move players
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
SET_GOLF_PLAYER_STATE(thisFoursome.playerCore[playerIndex], GPS_PLACE_BALL)
SET_GOLF_FOURSOME_INDEXED_PLAYER_LIE(thisFoursome, playerIndex, <<0,0,0>>, LIE_TEE)
IF DOES_ENTITY_EXIST(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex]))
IF NOT IS_ENTITY_DEAD(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex]))
SET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex]), GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, holeIndex, playerIndex))
ENDIF
ENDIF
ENDREPEAT
IF teleportCart
VECTOR cartSpawnPos = << 0,0,0 >>
VECTOR cartOffset = <<5,5,0>>
FLOAT cartHeading = 0
INT cartIndex
//move cart
IF FIND_SAFE_SPOT_FOR_CART(GET_GOLF_HOLE_TEE_POSITION(thisCourse, holeIndex), GET_GOLF_HOLE_PIN_POSITION(thisCourse, holeIndex), cartSpawnPos, cartHeading, <<0,0,0>>, <<0,0,0>>)
REPEAT 2 cartIndex
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex))
IF NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex))
AND NOT IS_SPHERE_VISIBLE(cartSpawnPos+ TO_FLOAT(cartIndex)*cartOffset, 5.0)
SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex), cartSpawnPos + TO_FLOAT(cartIndex)*cartOffset)
SET_ENTITY_HEADING(GET_GOLF_FOURSOME_CART(thisFoursome, cartIndex), cartHeading)
ENDIF
ENDIF
ENDREPEAT
ENDIF
ENDIF
ENDPROC
FUNC STRING GET_GOLF_RANDOM_POSITIVE_ANIM_NAME()
INT randomNumber = GET_RANDOM_INT_IN_RANGE(0, 100)
IF randomNumber < 50
RETURN "average"
ENDIF
IF randomNumber < 75
RETURN "average_b"
ENDIF
IF randomNumber < 90
RETURN "celeb_a"
ENDIF
RETURN "celeb_c"
ENDFUNC
//Moves all other golfers off the course to the cart path so the player has a clear shot
PROC MOVE_GOLFERS_OFF_COURSE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
IF GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_TEE OR GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_GREEN
EXIT
ENDIF
#IF GOLF_IS_MP
EXIT
#ENDIF
INT currentPlayer = GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)
INT playerIndex
FLOAT returnHeading, fHeight
VECTOR pinPos = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
VECTOR originPos, returnPos
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
VEHICLE_INDEX playersCart = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)
PED_INDEX playersPed = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)
IF playerIndex != currentPlayer AND GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex) = COMPUTER
AND DOES_ENTITY_EXIST(playersPed) AND NOT IS_ENTITY_DEAD(playersPed)
IF NOT IS_PED_IN_ANY_VEHICLE(playersPed, TRUE)
originPos = GET_ENTITY_COORDS(playersPed)
CLEAR_PED_TASKS(playersPed)
IF FIND_SAFE_SPOT_FOR_CART(originPos, pinPos, returnPos, returnHeading, <<0,0,0>>, <<0,0,0>>)
IF GET_GROUND_Z_FOR_3D_COORD(returnPos+<<0,0,2>>, fHeight)
returnPos.z = fHeight
ENDIF
SET_ENTITY_COORDS(playersPed, returnPos)
SET_ENTITY_HEADING(playersPed, GET_HEADING_BETWEEN_VECTORS(returnPos,pinPos))
ENDIF
ELSE
IF DOES_ENTITY_EXIST(playersCart) AND NOT IS_ENTITY_DEAD(playersCart)
SET_PED_INTO_VEHICLE(playersPed, playersCart, GET_GOLF_FOURSOME_INDEXED_PLAYER_SEAT(playerIndex))
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC CLEAR_NEARBY_GOLF_BALLS(GOLF_FOURSOME &thisFoursome)
INT idx
INT idxExclude = GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) idx
IF idx != idxExclude
IF DOES_ENTITY_EXIST(thisFoursome.playerCore[idx].objBall)
IF VDIST2(GET_ENTITY_COORDS(thisFoursome.playerCore[idx].objBall), thisFoursome.playerCore[idxExclude].vBallPosition) <= 1.0
CDEBUG1LN(DEBUG_GOLF,"CLEAR_NEARBY_GOLF_BALLS: Deleting the golf ball of player: ", idx)
DELETE_OBJECT(thisFoursome.playerCore[idx].objBall)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC CLEAR_AREA_AROUND_BALL(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome)
IF IS_GOLF_FOURSOME_MP()
EXIT //not needed in mp
ENDIF
CLEAR_AREA_OF_PEDS(GET_GOLF_COURSE_CENTER(thisCourse), 400)
CLEAR_AREA_OF_PEDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome), 5.0)
CLEAR_AREA_OF_OBJECTS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome), 5.0)
CLEAR_AREA_OF_VEHICLES(GET_GOLF_COURSE_CENTER(thisCourse), 400)
ENDPROC
//The spectating players rotation from the player
FUNC FLOAT GET_GOLFERS_PLACEMENT_ROTATION_FROM_INDEX(INT iPlayerIndex)
IF iPlayerIndex = 0
RETURN 15.0
ELIF iPlayerIndex = 1
RETURN -15.0
ELIF iPlayerIndex = 2
RETURN 30.0
ELIF iPlayerIndex = 3
RETURN -30.0
ENDIF
RETURN 0.0
ENDFUNC
FUNC BOOL TELEPORT_SPECTATOR_TO_POSITION_IN_GOLF(GOLF_FOURSOME &thisFoursome, GOLF_HELPERS &thisHelpers, GOLF_COURSE &thisCourse, INT iSpectatorIndex)
PED_INDEX pedPlayer = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iSpectatorIndex)
FLOAT fTeleportHeading, fHeight, fDegree
INT iCurrentHole = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)
VECTOR vTeleportPosition, vCurrentShootersPos
BOOL bSafe = TRUE
GOLF_LIE_TYPE teleportPosLie
vCurrentShootersPos = GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)
CDEBUG1LN(DEBUG_GOLF,"Teleporting player")
VECTOR vHolePosition = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
VECTOR vShotDir = NORMALISE_VECTOR(<<vHolePosition.x, vHolePosition.y,0>> - <<vCurrentShootersPos.x, vCurrentShootersPos.y,0>>)
IF IS_TEE_SHOT(thisCourse, thisFoursome)
CDEBUG1LN(DEBUG_GOLF,"Teleporting to tee spectate")
vTeleportPosition = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse,iCurrentHole, iSpectatorIndex)
ELIF GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_GREEN
OR SHOULD_USE_GREEN_SPECATE_FOR_COORD(vCurrentShootersPos, iCurrentHole)
CDEBUG1LN(DEBUG_GOLF,"Teleporting to green spectate")
vTeleportPosition = GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse,iCurrentHole, iSpectatorIndex)
IF VDIST2(vTeleportPosition, vCurrentShootersPos) < 3.5*3.5 //teleport spot is really close to player
OR (DOT_PRODUCT_XY(vShotDir, NORMALISE_VECTOR(vTeleportPosition - vCurrentShootersPos)) > 0.5 //the player is within 6 meters and in the line of sight of the shooter
AND VDIST2(vTeleportPosition, vCurrentShootersPos) < 6.0*6.0)
CDEBUG1LN(DEBUG_GOLF,"Use extra green spectate for player ", iSpectatorIndex)
vTeleportPosition = GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, iCurrentHole, 6)
ENDIF
ELIF GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_BUNKER
IF IS_GOLF_COORD_NEAR_BUNKER(vCurrentShootersPos, iCurrentHole, vTeleportPosition, iSpectatorIndex)
CDEBUG1LN(DEBUG_GOLF,"Current player is in bunker, use pre defined specate spot ", vTeleportPosition)
ELSE
CDEBUG1LN(DEBUG_GOLF,"Current player is in bunker, but didn't find safe specate spot on hole ", iCurrentHole)
ENDIF
ELIF IS_GOLF_COORD_NEAR_LAKE(vCurrentShootersPos, iCurrentHole, vTeleportPosition, iSpectatorIndex)
CDEBUG1LN(DEBUG_GOLF,"Current player is near lake, use pre defined specate spot ", vTeleportPosition)
ELSE
CDEBUG1LN(DEBUG_GOLF,"Teleporting not tee or green shot")
FLOAT fMoveDist = PICK_FLOAT(IS_GOLF_FOURSOME_MP(), 5.5, 4.5)
vTeleportPosition = vCurrentShootersPos - fMoveDist*vShotDir
fDegree = GET_GOLFERS_PLACEMENT_ROTATION_FROM_INDEX(iSpectatorIndex)
vTeleportPosition = ROTATE_VECTOR_ABOUT_Z(vTeleportPosition - vCurrentShootersPos, fDegree)
vTeleportPosition += vCurrentShootersPos
IF NOT GET_GROUND_Z_FOR_3D_COORD(vTeleportPosition + <<0, 0, 2.0>>, fHeight)
bSafe = FALSE
ELSE
vTeleportPosition.z = fHeight
ENDIF
IF IS_GOLF_COORD_OUTSIDE_BOUNDARY_PLANES(vTeleportPosition)
bSafe = FALSE
ENDIF
IF (DOT_PRODUCT_XY(vShotDir, NORMALISE_VECTOR(vTeleportPosition - vCurrentShootersPos)) > 0.5
AND VDIST2(vCurrentShootersPos, vTeleportPosition) < 25.0*25.0) //if you are more then 25 yards away, its ok to be in players los
OR VDIST2(vTeleportPosition, vCurrentShootersPos) < 3.5*3.5 //teleport spot is really close to player
CDEBUG1LN(DEBUG_GOLF, "Teleport spot obstructing golfer.")
CDEBUG1LN(DEBUG_GOLF, "Dist ", VDIST2(vTeleportPosition, vCurrentShootersPos), " DOT ", DOT_PRODUCT_XY(vShotDir, NORMALISE_VECTOR(vTeleportPosition - vCurrentShootersPos)))
bSafe = FALSE
ENDIF
IF bSafe //the spot is safe so far, lets see what lie it's on
GET_GOLF_LIE_FROM_WORLD_POSITION(vTeleportPosition + <<0,0,0.1>>, teleportPosLie, LIE_UNKNOWN, PLAYER_PED_ID())
IF NOT IS_GOLF_LIE_SAFE_FOR_TELEPORT(teleportPosLie)
CDEBUG1LN(DEBUG_GOLF,"Going to teleport player to bad lie ", teleportPosLie)
bSafe = FALSE
ENDIF
ENDIF
ENDIF
IF bSafe
fTeleportHeading = GET_HEADING_BETWEEN_VECTORS(vTeleportPosition, vCurrentShootersPos)
CDEBUG1LN(DEBUG_GOLF,"Teleporting to ",vTeleportPosition, " with heading ", fTeleportHeading)
CLEAR_PED_TASKS_IMMEDIATELY(pedPlayer)
SET_ENTITY_COORDS(pedPlayer, vTeleportPosition, FALSE, TRUE)
SET_ENTITY_HEADING(pedPlayer, fTeleportHeading)
thisHelpers.bAllowPlayerViewCam = TRUE
RETURN TRUE
ELSE
CDEBUG1LN(DEBUG_GOLF,"Don't teleport to unsafe location")
#IF GOLF_IS_MP
//to close to player, move far away
IF VDIST(GET_ENTITY_COORDS(pedPlayer), vCurrentShootersPos) < 3.0
vTeleportPosition = <<-1378.6844, 55.8883, 52.6896>>
SET_ENTITY_COORDS(pedPlayer, vTeleportPosition, FALSE, TRUE)
FREEZE_ENTITY_POSITION(pedPlayer, TRUE)
thisHelpers.bAllowPlayerViewCam = FALSE
ELIF VDIST(GET_ENTITY_COORDS(pedPlayer), vCurrentShootersPos) < 50.0
//current position is close enough to count as good pos
fTeleportHeading = GET_HEADING_BETWEEN_VECTORS(vTeleportPosition, vCurrentShootersPos)
SET_ENTITY_HEADING(pedPlayer, fTeleportHeading)
thisHelpers.bAllowPlayerViewCam = TRUE
ELSE
thisHelpers.bAllowPlayerViewCam = FALSE
ENDIF
#ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//Moves any golfers in the way of the players shot
PROC MOVE_ENTITIES_AROUND_CURRENT_PLAYER(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
#IF GOLF_IS_MP //dont use this function in mp golf
EXIT
#ENDIF
INT playerIndex
VECTOR currentPlayerPos = GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), FALSE)
// VEHICLE_INDEX vehIndex
//PED_INDEX randomPed
// INT vehSearchFlag = ( VEHICLE_SEARCH_FLAG_RETURN_LAW_ENFORCER_VEHICLES | VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES | VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_CONTAINING_GROUP_MEMBERS | VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_CONTAINING_A_PLAYER | VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_CONTAINING_A_DEAD_OR_DYING_PED | VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_WITH_PEDS_ENTERING_OR_EXITING | VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK )
//
// INT iSafe = 0
// //remove random vehicles
// WHILE IS_ANY_VEHICLE_NEAR_POINT(currentPlayerPos, 5.0) AND iSafe < 10
// CDEBUG1LN(DEBUG_GOLF,"Vehicle not owned by script near player shot")
// vehIndex = GET_CLOSEST_VEHICLE(currentPlayerPos, 5.0, DUMMY_MODEL_FOR_SCRIPT, vehSearchFlag)
// DELETE_VEHICLE(vehIndex)
// iSafe++
// ENDWHILE
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF playerIndex != GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)
PED_INDEX indexedPlayerPed = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)
IF DOES_ENTITY_EXIST(indexedPlayerPed) AND NOT IS_ENTITY_DEAD(indexedPlayerPed)
REMOVE_GOLF_CLUB_WEAPON(indexedPlayerPed, TRUE)
//within 3 metters just teleport them away
IF VDIST2(GET_ENTITY_COORDS(indexedPlayerPed), currentPlayerPos) < 9.0
CDEBUG1LN(DEBUG_GOLF,"Ped Moved")
VECTOR newCoord = currentPlayerPos - 5.0*GET_ENTITY_FORWARD_VECTOR(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome))
//the ped is going to be moved out of bounds, rotate coord 90 deg
IF IS_GOLF_COORD_OUTSIDE_BOUNDARY_PLANES(newCoord)
newCoord = ROTATE_VECTOR_ABOUT_Z_ORTHO(newCoord - currentPlayerPos, ROTSTEP_90)
newCoord+=currentPlayerPos
ENDIF
VECTOR vHolePosition = GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))
VECTOR ballPos = GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)
VECTOR vShotDir = NORMALISE_VECTOR(<<vHolePosition.x, vHolePosition.y,0>> - <<ballPos.x, ballPos.y,0>>)
VECTOR vToNewPos = NORMALISE_VECTOR(<<newCoord.x, newCoord.y,0>> - <<ballPos.x, ballPos.y,0>>)
//ped is now in front of golfer, rotate
IF DOT_PRODUCT_XY(vShotDir, vToNewPos) > 0.75
newCoord = ROTATE_VECTOR_ABOUT_Z_ORTHO(newCoord - currentPlayerPos, ROTSTEP_180)
newCoord += currentPlayerPos
ENDIF
CLEAR_PED_TASKS(indexedPlayerPed)
GET_GROUND_Z_FOR_3D_COORD(newCoord+<<0,0,50>>, newCoord.z)
SET_ENTITY_COORDS(indexedPlayerPed, newCoord)
SET_ENTITY_HEADING(indexedPlayerPed, GET_HEADING_BETWEEN_VECTORS(newCoord, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))))
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC TELEPORT_GOLFERS_TO_SPECTATE(GOLF_FOURSOME &thisFoursome, GOLF_HELPERS &thisHelpers, GOLF_COURSE &thisCourse,INT iExcludeIndex)
#IF GOLF_IS_MP
EXIT
#ENDIF
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF iExcludeIndex != playerIndex
//only teleport the local player if the current player is putting
AND (IS_GOLF_FOURSOME_CURRENT_PLAYER_PUTTING(thisFoursome) OR playerIndex != GET_GOLF_FOURSOME_LOCAL_PLAYER(thisFoursome))
PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)
VEHICLE_INDEX vehIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)
IF DOES_ENTITY_EXIST(pedIndex) AND NOT IS_ENTITY_DEAD(pedIndex)
IF NOT IS_PED_IN_ANY_VEHICLE(pedIndex, TRUE)
CLEAR_PED_TASKS(pedIndex)
TELEPORT_SPECTATOR_TO_POSITION_IN_GOLF(thisFoursome, thisHelpers, thisCourse, playerIndex)
ELIF DOES_ENTITY_EXIST(vehIndex) AND NOT IS_ENTITY_DEAD(vehIndex)
SET_PED_INTO_VEHICLE(pedIndex, vehIndex, GET_GOLF_FOURSOME_INDEXED_PLAYER_SEAT(playerIndex))
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC TELEPORT_GOLF_FOURSOME_TO_TEE_SPECTATE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse,INT iExcludeIndex)
#IF GOLF_IS_MP
EXIT
#ENDIF
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF iExcludeIndex != playerIndex
PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)
//VEHICLE_INDEX vehIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)
VECTOR spectatePos = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex)
IF DOES_ENTITY_EXIST(pedIndex) AND NOT IS_ENTITY_DEAD(pedIndex) AND GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex) != HUMAN_NETWORK
CLEAR_PED_TASKS(pedIndex)
SET_ENTITY_COORDS(pedIndex, spectatePos)
SET_ENTITY_HEADING(pedIndex, GET_HEADING_BETWEEN_VECTORS(spectatePos, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))))
ENDIF
ENDIF
ENDREPEAT
ENDPROC
//Clears flags when the ball is at rest after a hit
PROC CLEAR_CONTROL_FLAGS_BALL_AT_REST(GOLF_FOURSOME &thisFoursome, GOLF_GAME &thisGame, GOLF_HELPERS &thisHelpers)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_BALL_IS_OOB)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_BALL_IN_FOCUS)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_HIT_FLAG)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_FORCE_UPDATE)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_CART_ARRIVED)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_SHOT_IS_GIMMIE)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_USE_HARD_AI)
CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playercore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_PLAYER_TIME_OUT)
CLEAR_GOLF_UI_FLAG(thisHelpers, GUC_USE_FILL_QUALITY)
CLEAR_GOLF_UI_FLAG(thisHelpers, GUC_STYLE_HELP_DISPLAYED)
CLEAR_GOLF_CONTROL_FLAG(thisGame, GCF_BALL_JUST_LAND)
CLEAR_GOLF_CONTROL_FLAG(thisGame, GCF_WAS_PERFECT_HIT)
CLEAR_GOLF_CONTROL_FLAG(thisGame, GCF_BALL_POP_SOUND)
CLEAR_GOLF_CONTROL_FLAG(thisGame, GCF_BALL_IN_CUP_SOUND)
CLEAR_GOLF_DIALOGUE_FLAG(thisHelpers, GDF_PARTNER_SAID_AIM_WARNING)
CLEAR_GOLF_STREAMING_FLAG(thisHelpers, GSF_SET_HELPER_BLIP_ADDRESS_NAME)
CLEAR_GOLF_STREAMING_FLAG(thisHelpers, GSF_SET_HELPER_BLIP_IN_FLIGHT_NAME)
CLEAR_GOLF_STREAMING_FLAG(thisHelpers, GSF_SKIP_AI_PRESSED)
thisHelpers.vLastGoodAddressCamPos = <<0,0,0>>
STOP_AUDIO_SCENE("GOLF_FLY_CAM")
ENDPROC
PROC SET_GOLF_MARKER_FLUSH_WITH_GROUND(OBJECT_INDEX objMarker)
FLOAT fHeight
VECTOR vMarkerPos, vGroundNormal, vMarkerRot
FLOAT h, h2
IF DOES_ENTITY_EXIST(objMarker)
vMarkerPos = GET_ENTITY_COORDS(objMarker)
IF GET_GROUND_Z_AND_NORMAL_FOR_3D_COORD(vMarkerPos + <<0,0,1>>, fHeight, vGroundNormal)
vMarkerPos.z = fHeight + 0.005
SET_ENTITY_COORDS(objMarker, vMarkerPos)
h = SQRT(vGroundNormal.x*vGroundNormal.x + vGroundNormal.z*vGroundNormal.z)
h2 = SQRT(vGroundNormal.y*vGroundNormal.y + vGroundNormal.z*vGroundNormal.z)
vMarkerRot.x = 90 - ASIN(vGroundNormal.z/h)
vMarkerRot.y = 90 - ASIN(vGroundNormal.z/h2)
SET_ENTITY_ROTATION(objMarker, vMarkerRot)
ENDIF
ENDIF
ENDPROC
PROC GOLF_REPLACE_BALL_WITH_MARKER(GOLF_FOURSOME &thisFoursome)
INT playerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex
IF playerIndex != GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome) AND GET_GOLF_FOURSOME_INDEXED_PLAYER_MARKER(thisFoursome, playerIndex) = NULL
AND GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) != GPS_DONE_WITH_HOLE
OBJECT_INDEX newMarker = CREATE_GOLF_BALL_MARKER(thisFoursome, playerIndex)
CLEANUP_GOLF_BALL(thisFoursome.playerCore[playerIndex])
SET_GOLF_FOURSOME_INDEXED_PLAYER_MARKER(thisFoursome, newMarker, playerIndex)
SET_GOLF_MARKER_FLUSH_WITH_GROUND(newMarker)
ENDIF
ENDREPEAT
ENDPROC
PROC GOLF_MANAGE_CART_OWNER(GOLF_FOURSOME &thisFoursome)
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
//player got into the wrong vehicle
IF GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) != GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, 0)
CDEBUG1LN(DEBUG_GOLF,"Switch carts")
SET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 0, ABSI(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 0) - 1))
SET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 2, ABSI(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 0) - 1))
SET_GOLF_FOURSOME_CART_DRIVER(thisFoursome, 0, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 0))
SET_GOLF_FOURSOME_CART_DRIVER(thisFoursome, 2, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, 2))
//if ped was entering cart when you stole it, have him stop trying to get in
PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 2)
VEHICLE_INDEX vehIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, 2)
IF DOES_ENTITY_EXIST(vehIndex) AND DOES_ENTITY_EXIST(pedIndex)
IF NOT IS_ENTITY_DEAD(vehIndex) AND NOT IS_ENTITY_DEAD(pedIndex)
IF GET_SCRIPT_TASK_STATUS(pedIndex, SCRIPT_TASK_ENTER_VEHICLE) = PERFORMING_TASK
CDEBUG1LN(DEBUG_GOLF,"Ped stops moveing to cart")
CLEAR_PED_TASKS_IMMEDIATELY(pedIndex)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL IS_GOLF_CURRENT_PLAYER_HARD_AI(GOLF_FOURSOME &thisFoursome)
RETURN (GET_GOLF_FOURSOME_CURRENT_PLAYER_AI_DIFFICULTY(thisFoursome) = GOLF_AI_HARD OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_USE_HARD_AI))
AND GET_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL(thisFoursome) = COMPUTER //important, do not remove
ENDFUNC
PROC GOLF_MANAGE_END_OF_HOLE_TIMER(GOLF_FOURSOME &thisFoursome, INT iTime)
UNUSED_PARAMETER(thisFoursome)
IF iTime < 0
iTime = 0
ENDIF
IF GET_GOLF_FOURSOME_STATE(thisFoursome) = GGS_SCORECARD_END_GAME
DRAW_GENERIC_TIMER(iTime*1000, "GOLF_END_TIMER")
ELSE
DRAW_GENERIC_TIMER(iTime*1000, "GOLF_NEXT_HOLE")
ENDIF
ENDPROC
FUNC FLOAT GET_GOLF_SCALER_FROM_COORD(VECTOR vPos)
FLOAT fPedRange = GET_DISTANCE_BETWEEN_COORDS(GET_CAM_COORD(GET_RENDERING_CAM()), vPos)
FLOAT DefaultFov = 50.0
FLOAT DefaultRange = 4.5
FLOAT fScalerX = (GET_CAM_FOV(GET_RENDERING_CAM()) * fPedRange) / (DefaultFov*DefaultRange)
IF fScalerX > 1
RETURN fScalerX
ELSE
RETURN 1.0
ENDIF
ENDFUNC
PROC DRAW_GOLF_ARROW(VECTOR vDrawPos, FLOAT fAimHeading, VECTOR vHolePos, VECTOR vBallPos, BOOL bUseStaticSize)
fAimHeading = fAimHeading%360
// //Sprite Placement details
// SPRITE_PLACEMENT drawSprite
// //Set up the sprite
// drawSprite.x = 0
// drawSprite.y = 0
// drawSprite.w = 0.03
// drawSprite.h = 0.075
// drawSprite.r = 255
// drawSprite.g = 255
// drawSprite.b = 255
// drawSprite.a = 200
//
// FLOAT fScreenX, fScreenY, Scaler
// //FLOAT XShiftStat = -0.015
IF VDIST2(vDrawPos, vHolePos) < (0.15*0.15)
vDrawPos.z = vHolePos.z + 0.08
ENDIF
FLOAT fMaxDist = 20.0 * 20.0
FLOAT fDistance = VDIST2(<<vBallPos.x, vBallPos.y, 0>> , <<vDrawPos.x, vDrawPos.y, 0>>)
FLOAT fSize = 0.3
IF NOT bUseStaticSize
IF fDistance < (0.5 *0.5)
fSize = 0.25
ELSE
fSize = 0.25 + (fDistance/fMaxDist)*0.2
ENDIF
ENDIF
// CDEBUG1LN(DEBUG_GOLF,"Size, ", fSize)
// CDEBUG1LN(DEBUG_GOLF,"fAimHeading ", fAimHeading)
DRAW_MARKER(MARKER_ARROW_FLAT, vDrawPos + <<0, 0, 0.152>>, <<0,0,0>>, <<90.0 - fAimHeading, 90.0, 0>>, <<fSize, fSize, fSize>>, 255, 255, 255, 200, FALSE, FALSE, EULER_YXZ, FALSE, GET_GOLF_TEXTURE_DICTIONARY_NAME(), "PuttingMarker")
//
// IF HAS_STREAMED_TEXTURE_DICT_LOADED(GET_GOLF_TEXTURE_DICTIONARY_NAME())
// IF GET_SCREEN_COORD_FROM_WORLD_COORD(vDrawPos, fScreenX, fScreenY)
// fScreenX = drawSprite.x
// fScreenY = drawSprite.y
// Scaler = GET_GOLF_SCALER_FROM_COORD(vDrawPos)
//
// IF Scaler > 1
// //Adjust the xpos
// //XShiftStat /= Scaler
// //Set the scale of the icon
// drawSprite.w = drawSprite.w / Scaler
// drawSprite.h = drawSprite.h / Scaler
// ENDIF
// //set up the sprite
// //fScreenX += XShiftStat
// //Make it so the icon is drawn in the center.
// drawSprite.x = fScreenX// + (aSprite.w/2)
// drawSprite.y = fScreenY - (drawSprite.h/2)
// SET_DRAW_ORIGIN(vDrawPos)
//
// SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_BEFORE_HUD)
// DRAW_2D_SPRITE(GET_GOLF_TEXTURE_DICTIONARY_NAME(), "PuttingMarker", drawSprite, TRUE, HIGHLIGHT_OPTION_NORMAL)
// SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_HUD)
// CLEAR_DRAW_ORIGIN()
// ENDIF
// ENDIF
ENDPROC
PROC DRAW_GOLF_TERRAIN_GRID(VECTOR vBallPos, INT iHole)
VECTOR vGridPos, vGridDir, vGridSize
FLOAT fGridRes
FLOAT fColourMuti = 20.0
FLOAT fChangeInHeight = 0.08
SWITCH iHole
CASE 0
vGridPos = <<-1120.569, 222.185, 64.814>>
vGridDir = <<-0.712, 0.700, 0.0>>
vGridSize = <<14.920, 24.480, -0.63>>
fGridRes = 42.000
BREAK
CASE 1
vGridPos = <<-1326.193, 162.310, 56.974>>
vGridDir = <<-0.771, 0.636, 0.003>>
vGridSize = <<19.480, 24.340, -0.63>>
fGridRes = 42.000
BREAK
CASE 2
vGridPos = <<-1238.702, 106.882, 56.462>>
vGridDir = <<0.177, 0.982, 0.060>>
vGridSize = << 15.720, 27.980, 0.100>>
fGridRes = 42.000
BREAK
CASE 3
vGridPos = <<-1099.278, 10.541, 50.810>>
vGridDir = <<-0.993, 0.110, -0.046>>
vGridSize = <<33.050, 36.350, -0.63>>
fGridRes = 65.000
BREAK
CASE 4
vGridPos = <<-965.273, -82.437, 41.041>>
vGridDir = <<0.549, -0.835, -0.031>>
vGridSize = <<20.470, 42.540, -0.63>>
fGridRes = 42.000
BREAK
CASE 5
vGridPos = <<-1102.084, -116.732, 40.891>>
vGridDir = <<-0.485, -0.875, -0.006>>
vGridSize = <<18.560, 20.000, -0.63>>
fGridRes = 42.000
BREAK
CASE 6
vGridPos = <<-1284.205, 4.114, 49.654>>
vGridDir = <<-0.997, -0.018, 0.076>>
vGridSize = <<19.010, 20.000, 0.700>>
fGridRes = 42.000
BREAK
CASE 7
vGridPos = <<-1041.863, -84.943, 43.140>>
vGridDir = <<0.799, 0.600, 0.033>>
vGridSize = <<18.690, 24.090, 0.68>>
fGridRes = 42.000
BREAK
CASE 8
vGridPos = <<-1289.969, 83.574, 54.183>>
vGridDir = <<-1.000, 0.004, 0.005>>
vGridSize = <<19.010, 20.000, -0.63>>
fGridRes = 42.000
BREAK
ENDSWITCH
vGridPos.z = vBallPos.z +0.5
TERRAINGRID_ACTIVATE(TRUE)
TERRAINGRID_SET_PARAMS(vGridPos, vGridDir, vGridSize.x, vGridSize.y, vGridSize.z, fGridRes, fColourMuti, vBallPos.z, fChangeInHeight)
TERRAINGRID_SET_COLOURS(255, 0, 0, 64, 255, 255, 255, 5, 255, 255, 0, 64)
// FLOAT fGridRes, fGridWidth, fGridHeight
// VECTOR vCenterPos, vForward
//
// GET_TERRAIN_GRID_DATA(iHole, vCenterPos, vForward, fGridRes, fGridWidth, fGridHeight)
// TERRAINGRID_SET_PARAMS(vCenterPos, vForward, fGridWidth, fGridHeight, 2.0, fGridRes, fColourMuti, vBallPos.z, 0.25 )
ENDPROC
PROC DRAW_GOLF_ESTIMATE_RING(VECTOR vEstimatePos, VECTOR vHolePos)
IF VDIST2(vEstimatePos, vHolePos) < (0.15*0.15)
vEstimatePos.z = vHolePos.z + 0.12
ENDIF
//DRAW_MARKER(MARKER_CYLINDER, vEstimatePos, <<0,0,0>>, <<0,0,0>>, <<0.31, 0.31, 0.05>>, 255, 255, 0, 200)
DRAW_MARKER(MARKER_RING, vEstimatePos + <<0,0,0.01>>, <<0,0,0>>, <<-90,0,0>>, <<0.25, 0.25, 0.05>>, 255, 255, 0, 255)
ENDPROC
//PROC DRAW_GOLF_ESTIMATE_RING(VECTOR vEstimatePos, VECTOR vHolePos)
//
// IF VDIST2(vEstimatePos, vHolePos) < (0.15*0.15)
// vEstimatePos.z = vHolePos.z + 0.12
// ENDIF
//
// FLOAT fHieght
// VECTOR vNormal = <<0, 0, -1>>
// VECTOR vDirX = <<1, 0, 0>>
// VECTOR vDirY = <<0, 1, 0>>
// VECTOR vDirZ = <<0, 0, 1>>
//
// GET_GROUND_Z_AND_NORMAL_FOR_3D_COORD(vEstimatePos + <<0, 0, 1>>, fHieght, vNormal)
// VECTOR vRot
//
// //vRot = <<ACOS(vNormal.y), ACOS(vNormal.x), ACOS(vNormal.z)>>
//
// vRot.x = ACOS(vNormal.y/SQRT(vNormal.y*vNormal.y + vNormal.z*vNormal.z))
// vRot.z = ACOS(vNormal.x/SQRT(vNormal.y*vNormal.y + vNormal.x*vNormal.x))
//
// // + +, - Cos y
// //- +, 180 + Sin x
// //+ -, 180 + Sin x
// //- -, - Sin y
// IF bDebugSpew
// CDEBUG1LN(DEBUG_GOLF,"Normal ", vNormal, " vRot( ", vRot)
//
// CDEBUG1LN(DEBUG_GOLF,"Cos x ", ACOS(vNormal.x/SQRT(vNormal.y*vNormal.y + vNormal.x*vNormal.x)))
// CDEBUG1LN(DEBUG_GOLF,"Cos y ", ACOS(vNormal.y/SQRT(vNormal.y*vNormal.y + vNormal.x*vNormal.x)))
// CDEBUG1LN(DEBUG_GOLF,"Sin x ", ASIN(vNormal.x/SQRT(vNormal.y*vNormal.y + vNormal.x*vNormal.x)))
// CDEBUG1LN(DEBUG_GOLF,"Sin y ", ASIN(vNormal.y/SQRT(vNormal.y*vNormal.y + vNormal.x*vNormal.x)))
// ENDIF
//
// vEstimatePos += <<0,0,0.01>>
//
//
//
// //89.59, 81.66, 8.5
// DRAW_DEBUG_LINE(vEstimatePos, vEstimatePos +vDirX, 255, 0 ,0 )
// DRAW_DEBUG_LINE(vEstimatePos, vEstimatePos +vDirY, 0, 255 ,0 )
// DRAW_DEBUG_LINE(vEstimatePos, vEstimatePos +vDirZ, 0, 0 ,255 )
// DRAW_DEBUG_LINE(vEstimatePos, vEstimatePos+vNormal, 255, 255 ,255 )
//
//
// //DRAW_MARKER(MARKER_CYLINDER, vEstimatePos, <<0,0,0>>, <<0,0,0>>, <<0.31, 0.31, 0.05>>, 255, 255, 0, 200)
//
// DRAW_MARKER(MARKER_RING, vEstimatePos, <<0, 0, 0>>, <<vRingScale.x,vRingScale.y,vRingScale.z>>, <<0.25, 0.25, 0.05>>, 255, 255, 0, 255)
//ENDPROC
PROC GOLF_MANAGE_BALL_COLLISION(GOLF_FOURSOME &thisFoursome)
#IF GOLF_IS_MP
EXIT //no need to do it in mp golf, this is handled elsewhere
#ENDIF
INT iPlayerIndex, iPlayerIndex2
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
OBJECT_INDEX playerBall = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL(thisFoursome, iPlayerIndex)
IF DOES_ENTITY_EXIST(playerBall)
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex2
OBJECT_INDEX playerBall2 = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL(thisFoursome, iPlayerIndex2)
IF iPlayerIndex2 != iPlayerIndex AND DOES_ENTITY_EXIST(playerBall2)
IF IS_ENTITY_TOUCHING_ENTITY(playerBall, playerBall2)
CDEBUG1LN(DEBUG_GOLF,"Ball collision unfreeze balls")
SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, iPlayerIndex, GOLF_BALL_NEEDS_SNAP)
SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, iPlayerIndex2, GOLF_BALL_NEEDS_SNAP)
FREEZE_GOLF_BALL(playerBall, FALSE)
FREEZE_GOLF_BALL(playerBall2, FALSE)
ENDIF
ENDIF
ENDREPEAT
ENDIF
ENDREPEAT
ENDPROC
PROC GOLF_KNOCK_OVER_PED(PED_INDEX golferPed, OBJECT_INDEX playerBall)
IF IS_PED_INJURED(golferPed)
EXIT
ENDIF
IF IS_PED_RAGDOLL(golferPed)
EXIT
ENDIf
VECTOR vForce
FLOAT fMaxForce = 10.0
IF DOES_ENTITY_EXIST(playerBall)
vForce = GET_ENTITY_VELOCITY(playerBall) //* 0.1
ELSE
vForce = <<0,0,1>>
ENDIF
IF VMAG2(vForce) > (fMaxForce * fMaxForce)
vForce = NORMALISE_VECTOR(vForce)*fMaxForce
ENDIF
PRINTLN("Knock ped over")
FREEZE_ENTITY_POSITION(golferPed, FALSE)
#IF NOT GOLF_IS_MP
SET_PED_TO_RAGDOLL(golferPed, 3000, 5000, TASK_NM_BALANCE, FALSE )
APPLY_FORCE_TO_ENTITY(golferPed, APPLY_TYPE_IMPULSE, vForce, <<0,0,0>>, 0, FALSE, FALSE, TRUE)
#ENDIF
#IF GOLF_IS_MP
TASK_PLAY_ANIM(golferPed, "reaction@shove", "shoved_front")
#ENDIF
ENDPROC
PROC GOLF_MANAGE_BALL_PLAYER_COLLISION(GOLF_FOURSOME &thisFoursome)
#IF GOLF_IS_MP
EXIT //no need to do it in mp golf, this is handled elsewhere
#ENDIF
INT iPlayerIndex
OBJECT_INDEX playerBall = GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)
IF NOT DOES_ENTITY_EXIST(playerBall)
EXIT
ENDIF
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
PED_INDEX golferPed = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iPlayerIndex)
IF NOT IS_PED_INJURED(golferPed)
IF IS_ENTITY_TOUCHING_ENTITY(playerBall, golferPed)
CDEBUG1LN(DEBUG_GOLF,"Ball is touching a golfer")
GOLF_KNOCK_OVER_PED(golferPed, playerBall)
GOLF_DETACH_CLUB(thisFoursome, iPlayerIndex)
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC GOLF_FREEZE_ALL_BALL_POSITIONS(GOLF_FOURSOME &thisFoursome)
#IF GOLF_IS_MP
EXIT //no need to do it in mp golf, this is handled elsewhere
#ENDIF
INT iPlayerIndex
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex
OBJECT_INDEX playerBall = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL(thisFoursome, iPlayerIndex)
IF DOES_ENTITY_EXIST(playerBall)
FREEZE_GOLF_BALL(playerBall, TRUE)
ENDIF
ENDREPEAT
ENDPROC
FUNC TEXT_LABEL_23 GET_GOLF_SPLASH_TEXT_FROM_ENUM(GOLF_SPLASH_TEXT_ENUM eSplashText, TEXT_LABEL_23 &sRetStrapLine)
TEXT_LABEL_23 txtReturnSplashName
sRetStrapLine = ""
SWITCH eSplashText
CASE GOLF_SPLASH_NONE
txtReturnSplashName = ""
BREAK
CASE GOLF_SPLASH_HOLE_IN_ONE
txtReturnSplashName = "SCORE_HOLEINONE"
BREAK
CASE GOLF_SPLASH_EAGLE2
txtReturnSplashName = "SCORE_EAGLE2"
BREAK
CASE GOLF_SPLASH_EAGLE
txtReturnSplashName = "SCORE_EAGLE"
BREAK
CASE GOLF_SPLASH_BIRDIE
txtReturnSplashName = "SCORE_BIRDIE"
BREAK
CASE GOLF_SPLASH_PAR
txtReturnSplashName = "SCORE_PAR"
BREAK
CASE GOLF_SPLASH_BOGEY
txtReturnSplashName = "SCORE_BOGEY"
BREAK
CASE GOLF_SPLASH_BOGEY2
txtReturnSplashName = "SCORE_BOGEY2"
BREAK
CASE GOLF_SPLASH_BOGEY3
txtReturnSplashName = "SCORE_BOGEY3"
BREAK
CASE GOLF_SPLASH_BOGEY4
txtReturnSplashName = "SCORE_BOGEY4"
BREAK
CASE GOLF_SPLASH_BOGEY5
txtReturnSplashName = "SCORE_BOGEY5"
BREAK
CASE GOLF_SPLASH_FIR
txtReturnSplashName = "FIR"
sRetStrapLine = "GOLF_F_REGULATION"
BREAK
CASE GOLF_SPLASH_GIR
txtReturnSplashName = "GIR"
sRetStrapLine = "GOLF_G_REGULATION"
BREAK
CASE GOLF_SPLASH_LONGEST_DIVE
txtReturnSplashName = "GOLF_NEW_RECORD"
sRetStrapLine = "DRIVE_LONG"
IF GOLF_SHOULD_USE_FOREIGN_DISTANCE()
sRetStrapLine = "DRIVE_LONG_M"
ENDIF
BREAK
CASE GOLF_SPLASH_LONGEST_HOLE
txtReturnSplashName = "GOLF_NEW_RECORD"
txtReturnSplashName = "DRIVE_HOLE"
IF GOLF_SHOULD_USE_FOREIGN_DISTANCE()
sRetStrapLine = "DRIVE_HOLE_M"
ENDIF
BREAK
CASE GOLF_SPLASH_CLOSEST_TO_PIN
txtReturnSplashName = "GOLF_NEW_RECORD"
sRetStrapLine = GET_DRIVE_PIN_TEXT_LABEL(0)
BREAK
CASE GOLF_SPLASH_OOB
txtReturnSplashName = "LIE_UNKNOWN"
BREAK
CASE GOLF_SPLASH_WATER
txtReturnSplashName = "LIE_WATER"
BREAK
CASE GOLF_SPLASH_SCORE_LIMIT
txtReturnSplashName = "SCORE_LIMIT"
BREAK
CASE GOLF_SPLASH_UNPLAYABLE
txtReturnSplashName = "LIE_UNPLAYABLE"
BREAK
CASE GOLF_SPLASH_OBSTRUCTED
txtReturnSplashName = "LIE_UNPLAYABLE"
sRetStrapLine = "LIE_OBSTRUCT"
BREAK
DEFAULT
CDEBUG1LN(DEBUG_GOLF,"Invalid Splash text enum ", eSplashText)
SCRIPT_ASSERT("Invalid Splash text enum")
BREAK
ENDSWITCH
RETURN txtReturnSplashName
ENDFUNC
PROC RESET_FRIEND_FOR_CLEANUP(PED_INDEX pedFriend)
IF NOT IS_PED_INJURED(pedFriend)
RESET_PED_WEAPON_MOVEMENT_CLIPSET(pedFriend)
SET_PED_CAN_PLAY_AMBIENT_ANIMS(pedFriend, TRUE)
SET_PED_CONFIG_FLAG(pedFriend, PCF_IgnoreLegIkRestrictions, FALSE)
ENDIF
ENDPROC
PROC RESET_FRIEND_FOR_GOLF_OUTRO(GOLF_FOURSOME &thisFoursome, PED_VARIATION_STRUCT &sResetVariation, INT iFriendIndex, VECTOR vEndPos, FLOAT fEndHeading)
PED_INDEX pedFriend = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iFriendIndex)
IF NOT IS_PED_INJURED(pedFriend)
REMOVE_PED_FROM_GROUP(pedFriend)
SET_ENTITY_COORDS(pedFriend, vEndPos)
SET_ENTITY_HEADING(pedFriend, fEndHeading)
REMOVE_GOLF_CLUB_WEAPON(pedFriend, TRUE)
SET_PED_VARIATIONS(pedFriend, sResetVariation)
CLEAR_PED_TASKS(pedFriend)
RESET_FRIEND_FOR_CLEANUP(pedFriend)
ENDIF
ENDPROC
PROC CREATE_GOLF_PLAYER_GOLF_CARTS(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse)
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome, 0))
VEHICLE_INDEX veh = GET_GOLF_FOURSOME_CART(thisFoursome, 0)
DELETE_VEHICLE(veh)
ENDIF
SET_GOLF_FOURSOME_CART(thisFoursome, CREATE_VEHICLE(CADDY, GET_GOLF_COURSE_CART_POSITION(thisCourse, 0)), 0)
SET_VEHICLE_EXTRA(GET_GOLF_FOURSOME_CART(thisFoursome, 0), 5, TRUE)
SET_VEHICLE_HAS_STRONG_AXLES(GET_GOLF_FOURSOME_CART(thisFoursome, 0), TRUE)
SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(GET_GOLF_FOURSOME_CART(thisFoursome, 0), TRUE)
DEBUG_MESSAGE("CREATE CART")
IF GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) > 2
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome, 1))
VEHICLE_INDEX veh = GET_GOLF_FOURSOME_CART(thisFoursome, 1)
DELETE_VEHICLE(veh)
ENDIF
SET_GOLF_FOURSOME_CART(thisFoursome, CREATE_VEHICLE(CADDY, GET_GOLF_COURSE_CART_POSITION(thisCourse, 1)), 1)
SET_VEHICLE_EXTRA(GET_GOLF_FOURSOME_CART(thisFoursome, 1), 5, TRUE)
SET_VEHICLE_HAS_STRONG_AXLES(GET_GOLF_FOURSOME_CART(thisFoursome, 1), TRUE)
SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(GET_GOLF_FOURSOME_CART(thisFoursome, 1), TRUE)
DEBUG_MESSAGE("CREATE CART 2")
ENDIF
INT iCurrentPlayer
REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer
IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iCurrentPlayer))
OBJECT_INDEX obj = GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iCurrentPlayer)
DELETE_OBJECT(obj)
ENDIF
SET_GOLF_PLAYER_GOLFBAG(thisFoursome.playerCore[iCurrentPlayer], CREATE_OBJECT_NO_OFFSET(PROP_GOLF_BAG_01B, GET_GOLF_COURSE_START_POSITION(thisCourse, iCurrentPlayer)))
ATTACH_ENTITY_TO_ENTITY( GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iCurrentPlayer), GET_GOLF_FOURSOME_CART(thisFoursome, PICK_INT(iCurrentPlayer < 2, 0, 1)), 0, <<-0.225 - (-0.444 * ((iCurrentPlayer+1)%2)),-1.111, 0.570>>, <<0,0,-87.000 + (180.0 * ((iCurrentPlayer+1)%2)) >>)
ENDREPEAT
ENDPROC
PROC GOLF_TOGGLE_LOADING_SPINNER(BOOL bOn)
IF bOn
BEGIN_TEXT_COMMAND_BUSYSPINNER_ON("MP_SPINLOADING")
END_TEXT_COMMAND_BUSYSPINNER_ON(5)
ELSE
IF BUSYSPINNER_IS_ON()
BUSYSPINNER_OFF()
PRELOAD_BUSYSPINNER()
ENDIF
ENDIF
ENDPROC