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(<> - <>) //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(<> - <>) 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(<> - <>) //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(<> - <>) 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(<> - <>) VECTOR vToNewPos = NORMALISE_VECTOR(<> - <>) //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(<> , <>) 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>>, <>, 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 = <> // // 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>>, <>, <<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