USING "minigames_helpers.sch" USING "golf.sch" USING "golf_helpers.sch" USING "golf_foursome.sch" USING "golf_clubs_lib.sch" USING "golf_anims_lib.sch" USING "golf_physics_lib.sch" USING "oddjob_aggro.sch" FUNC FLOAT GET_DISTANCE_BETWEEN_ENTITIES_SQUARED(ENTITY_INDEX entityA, ENTITY_INDEX entityB, BOOL bCheck3D = TRUE) VECTOR vEntityAPos VECTOR vEntityBPos IF NOT IS_ENTITY_DEAD(entityA) vEntityAPos = GET_ENTITY_COORDS(entityA) ELSE vEntityAPos = GET_ENTITY_COORDS(entityA, FALSE) ENDIF IF NOT IS_ENTITY_DEAD(entityB) vEntityBPos = GET_ENTITY_COORDS(entityB) ELSE vEntityBPos = GET_ENTITY_COORDS(entityB, FALSE) ENDIF IF bCheck3D RETURN VDIST2(vEntityAPos, vEntityBPos) ELSE RETURN POW(vEntityAPos.x - vEntityBPos.x, 2.0) + POW(vEntityAPos.y - vEntityBPos.y, 2.0) ENDIF ENDFUNC /// PURPOSE: /// Updates a specific AI golfer status to see if it is far away from a given ped (the player, generally) or not /// PARAMS: /// thisPlayerCore - /// pedReference - /// newBallPos - There is a good chance that the balls Z cord will be way off when the player gets close to a golfer who used to be far away. /// Pass the golf balls position vector in to correct this. It will only change if the golfer changes its far away flag. PROC UPDATE_AI_FAR_AWAY(GOLF_PLAYER_CORE &thisPlayerCore, PED_INDEX pedReference, GOLF_FOURSOME &thisFoursome, INT playerIndex, GOLF_COURSE &thisCourse) IF NOT DOES_ENTITY_EXIST(GET_GOLF_PLAYER_PED(thisPlayerCore)) EXIT ENDIF IF IS_ENTITY_DEAD(GET_GOLF_PLAYER_PED(thisPlayerCore)) OR IS_PED_INJURED(GET_GOLF_PLAYER_PED(thisPlayerCore)) EXIT ENDIF IF NOT DOES_ENTITY_EXIST(pedReference) EXIT ENDIF IF GET_SCRIPT_TASK_STATUS(GET_GOLF_PLAYER_PED(thisPlayerCore), SCRIPT_TASK_ENTER_VEHICLE) = PERFORMING_TASK //walking to cart, he might walk out of the acceptable range. Don't teleport until he is in the cart EXIT ENDIF VECTOR golfBallPos = GET_GOLF_PLAYER_BALL_POSITION(thisPlayerCore) VECTOR playerPos = GET_ENTITY_COORDS(pedReference) VECTOR golferPos = GET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisPlayerCore)) FLOAT fHeight IF VDIST2(golferPos, playerPos) > (FAR_AWAY_THRESHOLD*FAR_AWAY_THRESHOLD) AND VDIST2(golfBallPos, playerPos) > (FAR_AWAY_THRESHOLD*FAR_AWAY_THRESHOLD) //Golfers will sometimes fall to there deaths in the far away state IF NOT IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_FAR_AWAY) SET_PED_GRAVITY(thisPlayerCore.pedGolfPlayer, FALSE) SET_PED_CAN_RAGDOLL(thisPlayerCore.pedGolfPlayer, FALSE) ENDIF SET_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_FAR_AWAY) ELSE IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_FAR_AWAY) SET_PED_GRAVITY(thisPlayerCore.pedGolfPlayer, TRUE) SET_PED_CAN_RAGDOLL(thisPlayerCore.pedGolfPlayer, TRUE) ENDIF CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_FAR_AWAY) ENDIF //golf ball far away IF VDIST2(golfBallPos, playerPos) > (FAR_AWAY_THRESHOLD*FAR_AWAY_THRESHOLD) SET_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_BALL_FAR_AWAY) IF golfBallPos.z > 100.0 IF DOES_ENTITY_EXIST(thisPlayerCore.objBall) IF NOT IS_ENTITY_DEAD(thisPlayerCore.objBall) SET_ENTITY_COORDS(thisPlayerCore.objBall, <>) ENDIF ENDIF ENDIF ELSE IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_BALL_FAR_AWAY) //move ball to correct spot IF DOES_ENTITY_EXIST(thisPlayerCore.objBall) IF NOT IS_ENTITY_DEAD(thisPlayerCore.objBall) VECTOR tempPos = thisPlayerCore.vBallPosition + <<0,0, 50.0>> IF GET_GROUND_Z_FOR_3D_COORD (tempPos, fHeight) thisPlayerCore.vBallPosition.z = fHeight SET_ENTITY_COORDS(thisPlayerCore.objBall, thisPlayerCore.vBallPosition) ENDIF ENDIF ENDIF IF GET_GOLF_PLAYER_STATE(thisPlayerCore) = GPS_BALL_IN_FLIGHT //if ball was flying put it at rest SET_GOLF_PLAYER_STATE(thisPlayerCore, GPS_BALL_AT_REST) ENDIF CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_BALL_FAR_AWAY) ENDIF IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_AI_FAR_AWAY) AND ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) //ball is close to player but golfer isn't FLOAT distanceToBall = VDIST(golferPos, golfBallPos) VECTOR directionToBall = NORMALISE_VECTOR(golfBallPos - golferPos) VECTOR teleportLoc = golferPos + directionToBall*distanceToBall*0.5 TELEPORT_GOLFER_TO_COORD(thisFoursome, playerIndex, teleportLoc, thisCourse, TRUE) IF GET_SCRIPT_TASK_STATUS(GET_GOLF_PLAYER_PED(thisPlayerCore), SCRIPT_TASK_ANY) = PERFORMING_TASK CLEAR_PED_TASKS(GET_GOLF_PLAYER_PED(thisPlayerCore)) ENDIF ENDIF ENDIF //ai far away IF VDIST2(golferPos, playerPos) > (FAR_AWAY_THRESHOLD*FAR_AWAY_THRESHOLD) SET_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_AI_FAR_AWAY) //golf ball is far away, set up the golfer for the far away logic IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_BALL_FAR_AWAY) AND playerIndex = GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome) IF GET_SCRIPT_TASK_STATUS(thisPlayerCore.pedGolfPlayer, SCRIPT_TASK_ANY) = PERFORMING_TASK CLEAR_PED_TASKS(thisPlayerCore.pedGolfPlayer) ENDIF SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF ELSE //aproaching golfer who was in the far away state, teleport him to his ball if the ball is far away IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_AI_FAR_AWAY) IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisPlayerCore, GOLF_BALL_FAR_AWAY) AND ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) TELEPORT_GOLFER_TO_BALL(thisFoursome, playerIndex, thisCourse, TRUE) IF GET_SCRIPT_TASK_STATUS(thisPlayerCore.pedGolfPlayer, SCRIPT_TASK_ANY) = PERFORMING_TASK CLEAR_PED_TASKS(thisPlayerCore.pedGolfPlayer) ENDIF SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_GET_IN_CART) IF IS_TEE_SHOT(thisCourse, thisFoursome) SET_GOLF_PLAYER_STATE(thisPlayerCore, GPS_PLACE_BALL) ELSE SET_GOLF_PLAYER_STATE(thisPlayerCore, GPS_APPROACH_BALL) ENDIF ELSE ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) IF GET_GROUND_Z_FOR_3D_COORD (golferPos, fHeight) golferPos.z = fHeight SET_ENTITY_COORDS(thisPlayerCore.pedGolfPlayer, golferPos) ENDIF ENDIF CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisPlayerCore, GOLF_AI_FAR_AWAY) ENDIF ENDIF ENDPROC /// PURPOSE: /// Does AI navigation to its next shot /// PARAMS: /// thisPlayerCore - /// golfCart - /// bOverridePlayer - /// bInitialHole - PROC DO_NAVIGATION_TO_NEXT_SHOT(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, INT playerIndex)//, BOOL bPlayerTimeout = TRUE) IF GET_GOLF_PLAYER_CONTROL(thisFoursome.playerCore[playerIndex]) != COMPUTER EXIT ENDIF IF NOT DOES_ENTITY_EXIST(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex])) EXIT ENDIF IF IS_ENTITY_DEAD(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex])) EXIT ENDIF IF GET_GOLF_PLAYER_CONTROL(thisFoursome.playerCore[playerIndex]) = HUMAN_NETWORK EXIT ENDIF VECTOR newBallLoc = GET_GOLF_PLAYER_BALL_POSITION(thisFoursome.playerCore[playerIndex]) PED_INDEX pedGolfPlayer = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex) IF IS_TEE_SHOT(thisCourse, thisFoursome) newBallLoc = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex) ENDIF IF IS_PED_IN_GROUP(pedGolfPlayer) OR VMAG2(newBallLoc) = 0 EXIT ENDIF IF IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_FAR_AWAY) // Probably need to check ball position also! IF bDebugSpew DEBUG_MESSAGE("We are trying to task the user to go to the ball, but we are far away, so lets teleport instead") ENDIF IF NOT IS_SPHERE_VISIBLE(newBallLoc, 5.0) SET_ENTITY_COORDS(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex]), newBallLoc, FALSE) ENDIF VECTOR cartSpawnPos = << 0,0,0 >> FLOAT cartHeading = 0 //move cart IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome)) IF NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CART(thisFoursome)) IF FIND_SAFE_SPOT_FOR_CART(GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome,0), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), cartSpawnPos, cartHeading, <<0,0,0>>, <<0,0,0>>) IF NOT IS_SPHERE_VISIBLE(cartSpawnPos, 5.0) SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CART(thisFoursome), cartSpawnPos) SET_ENTITY_HEADING(GET_GOLF_FOURSOME_CART(thisFoursome), cartHeading) ENDIF ENDIF ENDIF ENDIF ELIF GET_SCRIPT_TASK_STATUS( pedGolfPlayer, SCRIPT_TASK_PERFORM_SEQUENCE) != PERFORMING_TASK AND GET_SCRIPT_TASK_STATUS( pedGolfPlayer, SCRIPT_TASK_PERFORM_SEQUENCE) != WAITING_TO_START_TASK IF IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome,playerIndex, GOLF_PUTTING_GREEN_AI) AND DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) newBallLoc = GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) ELIF GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) = GPS_DONE_WITH_HOLE // We are approaching a hit ball OR GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) = GPS_BALL_IN_HOLE_CELEBRATION OR GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[playerIndex]) = LIE_GREEN IF GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[playerIndex]) = LIE_GREEN OR GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) = GPS_DONE_WITH_HOLE //don't go to the spectate location if you are the current golfer, unless you are finished with the hole OR GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) = GPS_BALL_IN_HOLE_CELEBRATION OR GET_GOLF_PLAYER_LIE(thisFoursome.playerCore[playerIndex]) = LIE_CUP AND FIND_NEXT_SHOOTER(thisFoursome, thisCourse) != playerIndex // PRINTLN("We are on the green, done with hole, or the lie is a cup - walk to green spectate") newBallLoc = GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome),playerIndex) SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, playerIndex, GOLF_STOP_USING_CART) ELSE // PRINTLN("We are not on the green, and done with hole, and the lie is not a cup - walk to ball") newBallLoc = GET_GOLF_PLAYER_BALL_POSITION(thisFoursome.playerCore[playerIndex]) ENDIF ENDIF // Task the player to go to the ball offset position then turn right 90 degrees IF VDIST2(newBallLoc, GET_ENTITY_COORDS(pedGolfPlayer)) > 1.5 CLEAR_PED_TASKS(pedGolfPlayer) OPEN_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, newBallLoc, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_DEFAULT | ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED, GET_HEADING_BETWEEN_VECTORS_2D(newBallLoc, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)))) //TASK_TURN_PED_TO_FACE_COORD(NULL, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(pedGolfPlayer, thisFoursome.playerCore[playerIndex].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) ENDIF IF GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex) != COMPUTER SET_GOLF_FOURSOME_LOCAL_PLAYER_CONTROL_FLAG(thisFoursome, GOLF_PLAYER_TASKED) ENDIF ENDIF ENDPROC PROC GOLF_AI_WALK_TO_CART(GOLF_FOURSOME &thisFoursome, INT playerIndex, BOOL bForceTaskEnterCart = FALSE) IF GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex) != COMPUTER EXIT ENDIF PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex) VEHICLE_INDEX vehIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex) VEHICLE_SEAT seat IF playerIndex = 0 OR playerIndex = 2 seat = VS_DRIVER ELSE seat = VS_FRONT_RIGHT ENDIF bForceTaskEnterCart = bForceTaskEnterCart IF DOES_ENTITY_EXIST(vehIndex) AND DOES_ENTITY_EXIST(pedIndex) IF NOT IS_ENTITY_DEAD(vehIndex) AND NOT IS_ENTITY_DEAD(pedIndex) IF NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_STOP_USING_CART) AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_CART_ARRIVED) AND NOT IS_PED_IN_GROUP(pedIndex) IF NOT IS_PED_IN_VEHICLE(pedIndex, vehIndex) AND IS_VEHICLE_SEAT_FREE(vehIndex, seat) AND NOT IS_PED_BEING_JACKED(pedIndex) AND NOT IS_PED_JACKING(pedIndex) AND IS_VEHICLE_ON_ALL_WHEELS(vehIndex) // IF VDIST2(GET_ENTITY_COORDS(vehIndex), GET_ENTITY_COORDS(pedIndex)) > (10.0 *10.0) // AND GET_SCRIPT_TASK_STATUS(pedIndex, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) != PERFORMING_TASK AND NOT bForceTaskEnterCart // TASK_FOLLOW_NAV_MESH_TO_COORD(pedIndex, GET_ENTITY_COORDS(vehIndex), PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, 5.0, ENAV_DEFAULT | ENAV_NEVER_ENTER_WATER | ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED) // ELIF GET_SCRIPT_TASK_STATUS(pedIndex, SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK // AND GET_SCRIPT_TASK_STATUS(pedIndex, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) != PERFORMING_TASK IF GET_SCRIPT_TASK_STATUS(pedIndex, SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK TASK_ENTER_VEHICLE(pedIndex, vehIndex, DEFAULT_TIME_NEVER_WARP, seat, PEDMOVE_WALK ) ENDIF ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Manages AI foursome navigation to next shot /// PARAMS: /// thisFoursome - /// bOverridePlayer - PROC GOLF_MANAGE_NAVIGATE_AI(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome) INT iCurrentPlayer REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer DO_NAVIGATION_TO_NEXT_SHOT(thisCourse, thisFoursome, iCurrentPlayer) ENDREPEAT ENDPROC /// PURPOSE: /// Manages startup AI (walking from clubhouse to golfcart) /// PARAMS: /// thisFoursome - /// allPlayers - PROC GOLF_MANAGE_NAVIGATE_STARTUP_AI(GOLF_FOURSOME &thisFoursome) INT iCurrentPlayer REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer IF iCurrentPlayer > 1 GOLF_AI_WALK_TO_CART(thisFoursome, iCurrentPlayer, TRUE) ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Stub for managing Address AI. Will eventually be flushed out with homing on a different/better shot /// PARAMS: /// thisGame - /// thisCourse - /// swingMeter - /// RETURNS: /// FUNC GOLF_PLAYER_STATE GOLF_MANAGE_ADDRESS_AI() RETURN GPS_SWING_METER ENDFUNC /// PURPOSE: /// Stub/shortcut for managing AI swings. Just a slight randomization on the decided shot. /// bUseRandomAim only matters if bSafety is set to TRUE PROC GOLF_MANAGE_SWING_AI(GOLF_FOURSOME &thisFoursome, GOLF_GAME &thisGame, SWING_METER &swingMeter, BOOL bSafety = FALSE, BOOL bUseRandomAim = FALSE) INT iBackswingModifier = 1000 IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_SHOT_IS_GIMMIE) iBackswingModifier = 450 ENDIF #IF NOT GOLF_IS_AI_ONLY PRINTLN("Backswingtime + 1000: ",swingMeter.iBackswingStartTime, " Game time: ", GET_GAME_TIMER()) PRINTLN("Swing state ", swingMeter.meterState) #ENDIF BOOL bPlayerTimeout = IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_PLAYER_TIME_OUT) FLOAT fAccuracyDistribution = 0 FLOAT fPowerReduction = PICK_FLOAT(bPlayerTimeout, 2.0, 1.0) IF swingMeter.iBackswingDelta > 0 swingMeter.iBackswingDelta += FLOOR(GET_FRAME_TIME()*1000) ENDIF IF swingMeter.iBackswingStartTime = 0 AND NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) OR GET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_ANIM(thisFoursome) = SAS_IDLE SET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_ANIM(thisFoursome, SAS_SWINGING_BACK) swingMeter.iBackswingStartTime = GET_GAME_TIMER() swingMeter.iBackswingDelta = swingMeter.iBackswingStartTime RESTART_TIMER_NOW(thisFoursome.physicsTimeout) GOLF_PLAY_BACKSWING_SOUND(thisFoursome) swingMeter.meterState = SWING_METER_RISING ELIF ((swingMeter.iBackswingStartTime + iBackswingModifier < swingMeter.iBackswingDelta OR swingMeter.iBackswingHoldTime != 0) AND swingMeter.meterState != SWING_METER_FINISHED AND swingMeter.meterState != SWING_METER_SHANK) OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) SET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_ANIM(thisFoursome, SAS_SWINGING_FORWARD) swingMeter.meterState = SWING_METER_FINISHED IF bSafety swingMeter.fCurrentAccurRel = GET_RANDOM_FLOAT_POLAR(0, PICK_FLOAT(bUseRandomAim, 5.0, 0.0)) swingMeter.fCurrentPowerRel = GET_GOLF_FOURSOME_CURRENT_PLAYER_METER_GOAL(thisFoursome) ELSE swingMeter.fCurrentAccurRel = GET_RANDOM_FLOAT_POLAR(0, fAccuracyDistribution) swingMeter.fCurrentPowerRel = GET_RANDOM_FLOAT_POLAR(GET_GOLF_FOURSOME_CURRENT_PLAYER_METER_GOAL(thisFoursome), 20) / fPowerReduction IF swingMeter.fCurrentPowerRel < 15 swingMeter.fCurrentPowerRel = 15 ENDIF ENDIF IF GET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_STYLE(thisFoursome) = SWING_STYLE_GREEN_SHORT OR GET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_STYLE(thisFoursome) = SWING_STYLE_GREEN_TAP OR GET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_STYLE(thisFoursome) = SWING_STYLE_GREEN_LONG OR GET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_STYLE(thisFoursome) = SWING_STYLE_GREEN //we arnt doing the magic on the swing meter any more ELSE GOLF_PLAY_SWING_SOUND(thisFoursome, thisGame, FALSE, 1.0) ENDIF IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) SET_GOLF_FOURSOME_CURRENT_PLAYER_METER_GOAL(thisFoursome, swingMeter.fCurrentPowerRel) INCREMENT_GOLF_FOURSOME_CURRENT_PLAYER_AIM(thisFoursome, swingMeter.fCurrentAccurRel) ENDIF ENDIF ENDPROC /// PURPOSE: /// Stub for managing golf shot flight AI. May not be needed. /// PARAMS: /// swingMeter - PROC GOLF_MANAGE_FLIGHT_AI(SWING_METER &swingMeter) UNUSED_PARAMETER(swingMeter) ENDPROC PROC GOLF_CREATE_AI_GOLFER(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, INT playerIndex) VECTOR spawnPos MODEL_NAMES pedModel PED_TYPE pedType = PEDTYPE_PLAYER_UNUSED SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex, COMPUTER) IF playerIndex = 0 spawnPos = GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) ELSE spawnPos = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex) ENDIF IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)) pedModel = GET_GOLF_PED_MODEL(pedType) SET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex, CREATE_PED( pedType, pedModel, spawnPos)) SET_ENTITY_HEADING(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), GET_HEADING_BETWEEN_VECTORS(spawnPos, GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)))) IF HAS_ANIM_SET_LOADED("move_m@golfer@") SET_PED_WEAPON_MOVEMENT_CLIPSET(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), "move_m@golfer@") ENDIF SET_TREAT_AS_AMBIENT_PED_FOR_DRIVER_LOCKON(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), TRUE) //SET_PED_CAN_RAGDOLL(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), FALSE) //SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), TRUE) /* IF playerIndex = 0 SET_PED_AS_GROUP_LEADER(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), GET_GOLF_FOURSOME_GROUP(thisFoursome)) ELSE SET_PED_AS_GROUP_MEMBER(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), GET_GOLF_FOURSOME_GROUP(thisFoursome)) ENDIF //*/ PRINTLN("Create AI Foursome PED!") ENDIF ENDPROC PROC GOLF_INIT_FOURSOME_DATA(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, INT holeToStart, INT iNumPlayers) SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, holeToStart) SET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome, iNumPlayers) SET_GOLF_FOURSOME_CART_DRIVER(thisFoursome, 0, 0) SET_GOLF_FOURSOME_CART_DRIVER(thisFoursome, 2, 1) SET_GOLF_FOURSOME_LOCAL_PLAYER(thisFoursome, 0)//ai foursomes don't use this variable for its intended purpose so I am hyjacking it for somthing else //SET_GOLF_FOURSOME_GROUP(thisFoursome, CREATE_GROUP(DEFAULT_TASK_ALLOCATOR_SIT_IN_LEADER_CAR)) GOLF_INIT_CURRENT_HOLE(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome,0) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDPROC PROC GOLF_CREATE_AI_CARTS(GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, INT holeToStart, INT iNumPlayers) VECTOR cartSpawnPos FLOAT cartHeading INT iPlayerIndex VECTOR cartOffset = <<0,0,0>> REPEAT (iNumPlayers+1)/2 iPlayerIndex IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CART(thisFoursome,iPlayerIndex)) IF iPlayerIndex = 1 cartOffset = 10.0*GET_ENTITY_FORWARD_VECTOR(GET_GOLF_FOURSOME_CART(thisFoursome, 0)) PRINTLN(cartOffset) ENDIF IF FIND_SAFE_SPOT_FOR_CART_FAST(GET_GOLF_HOLE_TEE_POSITION(thisCourse, holeToStart) + cartOffset, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), cartSpawnPos, cartHeading) SET_GOLF_FOURSOME_CART(thisFoursome, CREATE_VEHICLE(CADDY, cartSpawnPos, cartHeading), iPlayerIndex) SET_VEHICLE_EXTRA(GET_GOLF_FOURSOME_CART(thisFoursome, iPlayerIndex), 5, TRUE) SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(GET_GOLF_FOURSOME_CART(thisFoursome, iPlayerIndex), TRUE) PRINTLN("Create AI Foursome Cart!") ENDIF ENDIF ENDREPEAT /* we are streaming too manu models, no bags for ambient ai REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex IF iPlayerIndex < 2 SET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, iPlayerIndex, 0) IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex)) SET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex, CREATE_OBJECT_NO_OFFSET(PROP_GOLF_BAG_01, GET_ENTITY_COORDS( GET_GOLF_FOURSOME_CART(thisFoursome, 0)))) PRINTLN("Create AI Foursome Bag!") ENDIF ATTACH_ENTITY_TO_ENTITY( GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex), GET_GOLF_FOURSOME_CART(thisFoursome, 0), 0, <<0.2 - (0.4 * iPlayerIndex) ,-1.0,0.6>>, <<0,0,0>>) ELSE SET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, iPlayerIndex, 1) IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex)) SET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex, CREATE_OBJECT_NO_OFFSET(PROP_GOLF_BAG_01, GET_ENTITY_COORDS( GET_GOLF_FOURSOME_CART(thisFoursome, 1)))) PRINTLN("Create AI Foursome Bag!") ENDIF ATTACH_ENTITY_TO_ENTITY( GET_GOLF_FOURSOME_INDEXED_PLAYER_GOLFBAG(thisFoursome, iPlayerIndex), GET_GOLF_FOURSOME_CART(thisFoursome, 1), 0, <<0.2 - (0.4 * (iPlayerIndex%2)) ,-1.0,0.6>>, <<0,0,0>>) ENDIF ENDREPEAT //*/ ENDPROC /// PURPOSE: /// Creates an AI foursome, puts it on the proper hole, and prepares it to start playing golf. /// PARAMS: /// thisCourse - /// thisFoursome - /// iNumPlayers - /// holeToStart - PROC GOLF_CREATE_AI_FOURSOME (GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, INT iNumPlayers, INT holeToStart, BOOL bCreateCarts = FALSE) INT iPlayerIndex GOLF_INIT_FOURSOME_DATA(thisCourse, thisFoursome, holeToStart, iNumPlayers) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iPlayerIndex GOLF_CREATE_AI_GOLFER(thisCourse, thisFoursome, iPlayerIndex) ENDREPEAT IF bCreateCarts GOLF_CREATE_AI_CARTS(thisCourse, thisFoursome, holeToStart, iNumPlayers) ENDIF ENDPROC /// PURPOSE: /// State machine for an AI player taking a golf shot (from address to the ball being at rest) /// PARAMS: /// thisGame - /// thisCourse - /// thisFoursome - PROC GOLF_AI_PLAYER_TAKE_SHOT(GOLF_GAME &thisGame,GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome) // Need a better recovery mechanism here! IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) EXIT ENDIF IF IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) EXIT ENDIF //FLOAT cameraOffsetZ SWITCH GET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome) CASE GPS_PLACE_BALL DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_PLACE_BALL") VECTOR vBallTeePos vBallTeePos = GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) GOLF_FIND_GROUND_Z(vBallTeePos) IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) SET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome, CREATE_GOLF_BALL(vBallTeePos, GET_HEADING_BETWEEN_VECTORS(GET_GOLF_HOLE_FAIRWAY_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)))) ELIF NOT IS_PLAYER_ON_PUTTING_GREEN() SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome), vBallTeePos) ENDIF SET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome, GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome))) IF GET_GOLF_HOLE_PAR(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) = 1 SET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome, <<0,0,0>>, LIE_GREEN) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome, <<0,0,0>>, LIE_TEE) ENDIF SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_NORMAL(thisFoursome, <<0,0,-1>>) IF NOT bDrivingRangeMode PICK_IDEAL_CLUB_AND_SHOT(thisGame, thisCourse,thisFoursome) ENDIF PLACE_PLAYER_AT_BALL(thisCourse, thisFoursome, thisGame.golfBag, FALSE, FALSE, TRUE, TRUE) SET_ENTITY_RECORDS_COLLISIONS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome), FALSE) FREEZE_GOLF_BALL(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome), TRUE) SET_METER_MAX_DISTANCE(thisGame, thisCourse, thisFoursome) SET_METER_CURRENT_DISTANCE(thisFoursome.swingMeter, thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], thisGame) SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_ESTIMATE(thisFoursome, GOLF_FIND_SHOT_ESTIMATE(thisFoursome, thisGame.golfBag)) START_TIMER_NOW(thisFoursome.physicsTimeout) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_ADDRESS_BALL) BREAK CASE GPS_APPROACH_BALL // DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_APPROACH_BALL") IF NOT bDrivingRangeMode PICK_IDEAL_CLUB_AND_SHOT(thisGame, thisCourse,thisFoursome) ENDIF PLACE_PLAYER_AT_BALL(thisCourse, thisFoursome, thisGame.golfBag, FALSE, FALSE, FALSE, TRUE) IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) SET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome, CREATE_GOLF_BALL(GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) + <<0,0, 0.075>>, GET_HEADING_BETWEEN_VECTORS(GET_GOLF_HOLE_FAIRWAY_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)))) ENDIF // SET_ENTITY_HEADING( GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome), GET_HEADING_BETWEEN_VECTORS(GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome))+90) SET_METER_MAX_DISTANCE(thisGame, thisCourse, thisFoursome) SET_METER_CURRENT_DISTANCE(thisFoursome.swingMeter, thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], thisGame) IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_PUTTING(thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_ESTIMATE(thisFoursome, GOLF_FIND_SHOT_ESTIMATE(thisFoursome, thisGame.golfBag)) ENDIF START_TIMER_NOW(thisFoursome.physicsTimeout) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_ADDRESS_BALL) BREAK CASE GPS_ADDRESS_BALL IF IS_PLAYER_READY_TO_ADDRESS(thisFoursome) OR IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_FAR_AWAY) //When the golfer is in the address_ball state when he gets too far away from the player he will freeze IF IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], GOLF_FAR_AWAY) TELEPORT_GOLFER_TO_BALL(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome), thisCourse, FALSE) //DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: State transition to GOLF_MANAGE_ADDRESS_AI()") RESTART_TIMER_NOW(thisFoursome.physicsTimeout) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GOLF_MANAGE_ADDRESS_AI()) // The input manager here will change state - be careful! EXIT ENDIF //make sure they are near the ball IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) IF VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)) > 9 CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) //DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: State transition back to GPS_ADDRESS_BALL for being far") SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) EXIT ENDIF ENDIF RESTART_TIMER_NOW(thisFoursome.physicsTimeout) //DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: State transition to GOLF_MANAGE_ADDRESS_AI()") SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GOLF_MANAGE_ADDRESS_AI()) // The input manager here will change state - be careful! SET_GOLF_FOURSOME_CURRENT_PLAYER_SWING_ANIM(thisFoursome, SAS_SWINGING_BACK) GOLF_MANAGE_SWING_ANIMS(thisGame, thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], thisFoursome.swingMeter) IF IS_BALL_ON_GREEN(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_ESTIMATE(thisFoursome, GOLF_FIND_SHOT_ESTIMATE(thisFoursome, thisGame.golfBag)) ENDIF ELIF GET_ENTITY_SPEED(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) = 0 AND TIMER_DO_ONCE_WHEN_READY( thisFoursome.physicsTimeout, 15) //PRINTLN("Ped is performing sequence but not moving") START_TIMER_NOW(thisFoursome.physicsTimeout) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) IF NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) ENDIF ENDIF BREAK CASE GPS_SWING_METER IF GET_DISTANCE_BETWEEN_ENTITIES_SQUARED(PLAYER_PED_ID(), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].pedGolfPlayer, FALSE) < CLOSE_PED_DIST2 CPRINTLN(DEBUG_GOLF, "GOLF_MANAGE_AI_FOURSOME_PUTTING: Close to ped.") IF IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].pedGolfPlayer) CLEAR_PED_TASKS_IMMEDIATELY(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].pedGolfPlayer) //DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME_PUTTING: Ped has ragdolled. EXITING SWING_METER") PLACE_PLAYER_AT_BALL(thisCourse, thisFoursome, thisGame.golfBag, FALSE, FALSE, FALSE, TRUE) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_NAVIGATE_TO_SHOT) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) CANCEL_TIMER(thisFoursome.physicsTimeout) EXIT ENDIF ENDIF // // DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_SWING_METER") IF bDebugSpew PRINTLN("Player ",GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome), " hitting ball") ENDIF GOLF_MANAGE_SWING_AI(thisFoursome, thisGame, thisFoursome.swingMeter) IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) GOLF_MANAGE_SWING_ANIMS(thisGame, thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], thisFoursome.swingMeter) ENDIF IF NOT IS_GOLF_CONTROL_FLAG_SET(thisGame, GCF_AI_HIT_BALL_THIS_FRAME) IF (thisFoursome.swingMeter.meterState = SWING_METER_FINISHED OR thisFoursome.swingMeter.meterState = SWING_METER_SHANK OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY)) AND DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) IF (HAS_SWING_ANIM_REACHED_BALL(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OR TIMER_DO_ONCE_WHEN_READY( thisFoursome.physicsTimeout, 2.5) OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY)) AND DOES_ENTITY_HAVE_PHYSICS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) IF bDebugSpew DEBUG_MESSAGE("Player hitting ball with no anim - we are far away") ENDIF thisFoursome.swingMeter.meterState = SWING_METER_FINISHED ENDIF IF GOLF_HIT_BALL(thisGame, thisCourse, thisFoursome) thisFoursome.swingMeter.meterState = SWING_METER_INACTIVE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_BALL_IN_FLIGHT) ELSE // We didnt hit the ball (force <<0,0,0>>) so lets false start instead thisFoursome.swingMeter.meterState = SWING_METER_INACTIVE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_ADDRESS_BALL) ENDIF SET_GOLF_CONTROL_FLAG( thisGame, GCF_AI_HIT_BALL_THIS_FRAME) ENDIF ELIF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) thisFoursome.swingMeter.meterState = SWING_METER_INACTIVE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) ENDIF ENDIF BREAK CASE GPS_BALL_IN_FLIGHT // DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_BALL_IN_FLIGHT") IF HAS_SWING_ANIM_REACHED_TIME(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), 1.0) GOLF_MANAGE_AI_POST_SHOT_ANIMATIONS(thisGame, thisFoursome, TRUE) ENDIF IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) SET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome, CREATE_GOLF_BALL(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome), GET_HEADING_BETWEEN_VECTORS(GET_GOLF_HOLE_FAIRWAY_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)))) ENDIF IF NOT IS_BALL_ON_GREEN(thisCourse, thisFoursome) GOLF_MANAGE_BALL_IN_FLIGHT(thisGame, thisCourse, thisFoursome) GOLF_MANAGE_FLIGHT_AI(thisFoursome.swingMeter) IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET( thisFoursome, GOLF_BALL_AT_REST) GOLF_CLEAR_SWING_METER(thisFoursome.swingMeter) ENDIF ELSE GOLF_MANAGE_BALL_ON_GREEN(thisGame, thisCourse, thisFoursome) IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET( thisFoursome, GOLF_BALL_AT_REST) GOLF_CLEAR_SWING_METER(thisFoursome.swingMeter) ENDIF ENDIF BREAK CASE GPS_BALL_AT_REST // DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_BALL_AT_REST") GOLF_MANAGE_AI_POST_SHOT_ANIMATIONS(thisGame, thisFoursome, TRUE) IF IS_BALL_IN_WATER_HAZARD(thisFoursome) OR IS_BALL_LIE_UNKOWN(thisFoursome) OR IS_GOLF_COORD_OUTSIDE_BOUNDARY_PLANES(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome))) GOLF_RESET_BALL_AT_REST_HAZARD(thisFoursome) ELSE GOLF_RESET_BALL_AT_REST(thisCourse, thisFoursome) ENDIF SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_POST_SHOT_REACTION) INCREMENT_GOLF_FOURSOME_CURRENT_PLAYER_SHOTS_ON_HOLE(thisFoursome) //If the ai is 4 over par, just end the hole IF GET_GOLF_FOURSOME_CURRENT_PLAYER_SHOTS_ON_HOLE(thisFoursome) > (GET_GOLF_HOLE_PAR(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisfoursome)) + 3) //PRINTLN("4 over par - finish hole.") SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_POST_SHOT_REACTION) SET_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG(thisFoursome, GOLF_STROKE_LIMIT) ENDIF BREAK CASE GPS_BALL_IN_HOLE_CELEBRATION GOLF_MANAGE_AI_POST_SHOT_ANIMATIONS(thisGame, thisFoursome, TRUE) // DEBUG_MESSAGE("GOLF_AI_PLAYER_TAKE_SHOT: GPS_BALL_IN_HOLE_CELEBRATION") SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_POST_SHOT_REACTION) INCREMENT_GOLF_FOURSOME_CURRENT_PLAYER_SHOTS_ON_HOLE(thisFoursome) CLEANUP_GOLF_FOURSOME_CURRENT_GOLF_BALL(thisFoursome) CLEAR_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG(thisFoursome, GOLF_STOP_USING_CART) IF NOT ARE_ALL_PLAYERS_DONE_WITH_HOLE(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)) AND NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OPEN_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_GO_TO_COORD_ANY_MEANS( NULL, GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)), PEDMOVE_WALK, NULL) TASK_TURN_PED_TO_FACE_COORD( NULL, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) ENDIF BREAK CASE GPS_POST_SHOT_REACTION IF NOT GOLF_MANAGE_AI_POST_SHOT_ANIMATIONS(thisGame, thisFoursome, FALSE) // If players are around the green or tee, move them to a spectating spot rather than have them walk around a bunch IF WAS_TEE_SHOT(thisCourse, thisFoursome) // We are finished with the tee shot AND NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)) IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) IF bDebugSpew DEBUG_MESSAGE("Moving player to tee spectate") ENDIF CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OPEN_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_FOLLOW_NAV_MESH_TO_COORD( NULL, GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)), PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP) TASK_TURN_PED_TO_FACE_COORD( NULL, GET_GOLF_HOLE_TEE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) ELSE SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome))) ENDIF ELIF IS_GOLF_FOURSOME_CURRENT_PLAYER_PUTTING(thisFoursome) OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_STOP_USING_CART) IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) IF NOT ARE_ALL_PLAYERS_DONE_WITH_HOLE(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)) IF bDebugSpew DEBUG_MESSAGE("Moving player to green spectate") ENDIF CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OPEN_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_FOLLOW_NAV_MESH_TO_COORD( NULL, GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)), PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP) TASK_TURN_PED_TO_FACE_COORD( NULL, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) ENDIF ELIF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_PUTTING_GREEN_AI) SET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome))) ENDIF ELSE //golfer just hit from fairway IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) IF NOT ARE_ALL_PLAYERS_DONE_WITH_HOLE(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)) AND DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome)) IF NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome)) //TASK_FOLLOW_NAV_MESH_TO_COORD(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome)), PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OPEN_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_ENTER_VEHICLE(NULL, GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome), DEFAULT_TIME_NEVER_WARP, GET_GOLF_FOURSOME_CURRENT_PLAYER_SEAT(thisFoursome), PEDMOVE_WALK) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)].seq_swing_and_outro) ENDIF ENDIF ENDIF ENDIF IF GET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome) = LIE_CUP OR IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_STROKE_LIMIT) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_DONE_WITH_HOLE) CLEAR_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG(thisFoursome, GOLF_STROKE_LIMIT) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_DONE_WITH_SHOT) ENDIF ENDIF BREAK ENDSWITCH ENDPROC TYPEDEF FUNC VECTOR GET_GOLF_SPECTATE_LOCATION_CALLBACK(GOLF_COURSE &golfCourse, INT holeIndex, INT spectateIndex) TYPEDEF FUNC VECTOR GET_GOLF_LOOK_AT_CALLBACK(GOLF_COURSE &golfCourse, INT holeIndex) PROC AI_GOLFERS_LEAVE_CART_AND_MOVE_TO_SPECTATE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, INT cartIndex, BOOL stopUsingCart, GET_GOLF_SPECTATE_LOCATION_CALLBACK moveToCB, GET_GOLF_LOOK_AT_CALLBACK faceToCB) INT playerIndex REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex IF ((cartIndex = 0 AND (playerIndex = 0 OR playerIndex = 1)) OR (cartIndex = 1 AND (playerIndex = 2 OR playerIndex = 3))) AND GET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL(thisFoursome, playerIndex) = COMPUTER OPEN_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) TASK_LEAVE_ANY_VEHICLE(NULL) TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, CALL moveToCB(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex), PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP) TASK_TURN_PED_TO_FACE_COORD( NULL, CALL faceToCB(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) CLOSE_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) TASK_PERFORM_SEQUENCE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome,playerIndex), thisFoursome.playerCore[playerIndex].seq_swing_and_outro) CLEAR_SEQUENCE_TASK(thisFoursome.playerCore[playerIndex].seq_swing_and_outro) IF stopUsingCart AND GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex) != GPS_DONE_WITH_HOLE SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, playerIndex, GOLF_STOP_USING_CART) ENDIF ENDIF ENDREPEAT ENDPROC FUNC BOOL DOES_GOLF_AI_FOURSOME_USE_CART(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse) INT magicDistanceFromBall = 150 INT magicDistanceFromGreen = 1600 IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) RETURN FALSE ENDIF //too close to green, don't use cart IF VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) < magicDistanceFromGreen //the cart is not near the green, drive to it IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CART(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER_CART_INDEX(thisFoursome))) IF VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_CART(thisFoursome)), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) > magicDistanceFromGreen RETURN TRUE ENDIF //the cart and golfer are near green have everyone get out and walk to their ball AI_GOLFERS_LEAVE_CART_AND_MOVE_TO_SPECTATE(thisFoursome, thisCourse, GET_GOLF_FOURSOME_CURRENT_PLAYER_CART_INDEX(thisFoursome) ,TRUE, &GET_GOLF_HOLE_GREEN_SPECTATE_POSITION, &GET_GOLF_HOLE_PIN_POSITION) ENDIF RETURN FALSE ENDIF //too close to ball don't bother going to cart first IF VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)), GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome)) < magicDistanceFromBall RETURN FALSE ENDIF RETURN TRUE ENDFUNC PROC AI_DRIVE_CART(GOLF_FOURSOME &thisFoursome, INT playerIndex, GOLF_COURSE &thisCourse, BOOL getOutOfCart, BOOL bPlayersFoursome = FALSE) //im not using thisFoursome.playerCore[playerIndex].vShotEstimate right now so im going to borrow it to keep track of where the cart is driving FLOAT cartHeading, stoppingDistance PED_INDEX cartDriver = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_DRIVER(thisFoursome,playerIndex)) INT tempIndex VECTOR ballPos = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, playerIndex) VECTOR cartOffset = <<0,0,0>> IF IS_ENTITY_DEAD(cartDriver) EXIT ENDIF IF IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)) #IF GOLF_IS_AI_ONLY SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) #ENDIF EXIT ENDIF stoppingDistance = 144 BOOL bNearBall = VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CART(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, playerIndex))), thisFoursome.playerCore[playerIndex].vShotEstimate) < stoppingDistance IF NOT IS_PED_IN_VEHICLE(cartDriver, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)) AND NOT bNearBall IF GET_SCRIPT_TASK_STATUS(cartDriver, SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK TASK_ENTER_VEHICLE(cartDriver, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex), DEFAULT_TIME_NEVER_WARP, VS_DRIVER, PEDMOVE_WALK) ENDIF EXIT //you must be in cart to drive ENDIF DRIVINGMODE cartDrivingMode = DRIVINGMODE_STOPFORCARS IF bPlayersFoursome cartDrivingMode = DF_StopForCars | DF_SteerAroundPeds ENDIF IF DOES_ENTITY_EXIST(cartDriver) AND NOT IS_ENTITY_DEAD(cartDriver) AND (GET_SCRIPT_TASK_STATUS(cartDriver, SCRIPT_TASK_VEHICLE_DRIVE_TO_COORD) != PERFORMING_TASK ) AND NOT IS_GOLF_PLAYER_CONTROL_FLAG_SET(thisFoursome.playerCore[playerIndex], GOLF_CART_ARRIVED) //add an offset to the second cart when driving to the tee, this way the two carts wont try and park in the same spot IF GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, playerIndex) = 1 AND NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) IF IS_TEE_SHOT(thisCourse, thisFoursome) AND GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) = 0 cartOffset = <<-3,-3,0>> ELSE cartOffset = <<3,3,0>> ENDIF ENDIF //drive cart to the vehicle node near the ball FIND_SAFE_SPOT_FOR_CART( ballPos + cartOffset, GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)),thisFoursome.playerCore[playerIndex].vShotEstimate, cartHeading, <<0,0,0>>, <<0,0,0>>) TASK_VEHICLE_DRIVE_TO_COORD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_DRIVER(thisFoursome, playerIndex)), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex), thisFoursome.playerCore[playerIndex].vShotEstimate, 4.0, DRIVINGSTYLE_NORMAL, DUMMY_MODEL_FOR_SCRIPT, cartDrivingMode , 4, -1) ENDIF //you are getting close to the ball stop and let the current player out IF bNearBall CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_DRIVER(thisFoursome, playerIndex))) SET_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playerCore[playerIndex], GOLF_CART_ARRIVED) //tee shot IF NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) //move to the tee make everyone leave the vehicle TASK_EVERYONE_LEAVE_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)) BOOL everyoneOutOfCart = TRUE //tell golfers to move to tee spectate once they get out of cart AI_GOLFERS_LEAVE_CART_AND_MOVE_TO_SPECTATE(thisFoursome, thisCourse, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, playerIndex), FALSE, &GET_GOLF_HOLE_TEE_SPECTATE_POSITION, &GET_GOLF_HOLE_TEE_POSITION) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) tempIndex IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, tempIndex)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, tempIndex)) IF IS_PED_IN_ANY_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, tempIndex)) everyoneOutOfCart = FALSE ENDIF ENDIF ENDREPEAT IF everyoneOutOfCart AND getOutOfCart SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF //green ELIF VDIST2(GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, playerIndex), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) < 1600 AND VDIST2(GET_ENTITY_COORDS(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) < 1600 AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_STOP_USING_CART) //the cart and ball are near green have everyone get out and walk to their ball AI_GOLFERS_LEAVE_CART_AND_MOVE_TO_SPECTATE(thisFoursome, thisCourse, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome, playerIndex), TRUE, &GET_GOLF_HOLE_GREEN_SPECTATE_POSITION, &GET_GOLF_HOLE_PIN_POSITION) IF getOutOfCart SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF ELIF IS_PED_IN_ANY_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)) // driving cart when player reached destination TASK_VEHICLE_PARK(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_DRIVER(thisFoursome, playerIndex)), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex), GET_ENTITY_COORDS(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, playerIndex)), 0, PARK_TYPE_PULL_OVER,360) IF getOutOfCart TASK_LEAVE_ANY_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) SET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex, GPS_APPROACH_BALL) ENDIF ELSE //player reached destination while not in a cart, probably because he recently was in the far away state IF getOutofCart SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) SET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, playerIndex, GPS_APPROACH_BALL) ENDIF ENDIF ENDIF ENDPROC PROC MOVE_GOLF_AI_FOURSOME_TO_HOLE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, INT iHole) PRINTLN("Move Foursome to Hole ", iHole) GOLF_CLEANUP_CURRENT_HOLE(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome,0) SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, iHole) GOLF_INIT_CURRENT_HOLE(thisCourse, thisFoursome) TELEPORT_FOURSOME_TO_TEE(thisFoursome, thisCourse) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDPROC PROC MOVE_GOLF_FOURSOME_TO_NEXT_AVAILABLE_HOLE(GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse, GOLF_FOURSOME &allAIFoursomes[]) INT holeIndex REPEAT GET_GOLF_COURSE_NUM_HOLES(thisCourse) holeIndex IF NOT IS_ANY_GOLF_FOURSOME_PLAYING_HOLE(allAIFoursomes, holeIndex) //no other foursome is playing at the hole we might move to // Player is playing on this hole, move group to next available hole MOVE_GOLF_AI_FOURSOME_TO_HOLE(thisFoursome, thisCourse, holeIndex) EXIT// break out of loop ENDIF ENDREPEAT ENDPROC FUNC INT GET_HOLE_FOURSOME_SHOULD_BE_AT_WHEN_PLAYER_IS_AT_HOLE(INT iPlayersHole) SWITCH iPlayersHole CASE 0 RETURN 2 BREAK CASE 1 RETURN 0 BREAK CASE 2 RETURN 1 BREAK CASE 3 RETURN 2 BREAK CASE 4 RETURN 3 BREAK CASE 5 RETURN 4 BREAK CASE 6 RETURN 5 BREAK CASE 7 RETURN 2 BREAK CASE 8 RETURN 2 BREAK ENDSWITCH RETURN 2 ENDFUNC /// PURPOSE: /// Manages an AI foursome - navigating to shots, taking shots, finishing hole, etc /// PARAMS: /// thisGame - /// thisCourse - /// thisFoursome - PROC GOLF_MANAGE_AI_FOURSOME(GOLF_GAME &thisGame,GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome, GOLF_FOURSOME &allAIFoursomes[], INT iFoursomeIndex) // PRINTSTRING("GOLF_MANAGE_AI_FOURSOME working on golfer ")PRINTINT(GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome))PRINTNL() INT playerIndex IF ARE_ALL_PLAYERS_REMOVED_FROM_GOLF_GAME(thisFoursome) //The peds only get deleted if they are far from the player, check to see if peds removed from the golf game need to be deleted REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex GOLF_REMOVE_AI_PED(thisFoursome, playerIndex) ENDREPEAT EXIT ENDIF //local player is never used in ai foursomes, I am using it to round robin this expensive function UPDATE_AI_FAR_AWAY(thisFoursome.playerCore[thisFoursome.iLocalPlayerIndex], PLAYER_PED_ID(), thisFoursome, thisFoursome.iLocalPlayerIndex , thisCourse) thisFoursome.iLocalPlayerIndex++ IF thisFoursome.iLocalPlayerIndex >= GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) thisFoursome.iLocalPlayerIndex = 0 ENDIF BOOL bWanted = GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 AGGRO_ARGS aggroArguments EAGGRO aggroReason aggroArguments.iShotIRange = 25 REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex //Has a golfer been killed IF DOES_ENTITY_EXIST(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex])) IF IS_ENTITY_DEAD(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex])) AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, playerIndex, GOLF_PLAYER_REMOVED ) PRINTSTRING("Some one died, stop golfing.\n") GOLF_REMOVE_AI_FOURSOME(thisFoursome) EXIT ENDIF IF bWanted AND GET_PLAYER_DISTANCE_FROM_ENTITY(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex])) < 100 PRINTLN("player nearby is wanted, stop golfing") GOLF_REMOVE_AI_FOURSOME(thisFoursome) EXIT ENDIF IF DO_AGGRO_CHECK(GET_GOLF_PLAYER_PED(thisFoursome.playerCore[playerIndex]), GET_GOLF_FOURSOME_CART(thisFoursome,0), aggroArguments, aggroReason, TRUE) PRINTLN("DO_AGGRO_CHECK, stop golfing") GOLF_REMOVE_AI_FOURSOME(thisFoursome) EXIT ENDIF ENDIF ENDREPEAT //The player stole your cart, don't try and use it anymore IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) = GET_GOLF_FOURSOME_CART(thisFoursome,0) PRINTLN("Disowning ai cart") SET_ENTITY_AS_MISSION_ENTITY(GET_GOLF_FOURSOME_CART(thisFoursome,0), FALSE) SET_VEHICLE_AS_NO_LONGER_NEEDED(thisFoursome.vehCart[0]) SET_GOLF_FOURSOME_CART(thisFoursome, NULL, 0) IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 0)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 0)) IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 0), SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 0)) TASK_TURN_PED_TO_FACE_ENTITY(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 0), PLAYER_PED_ID(), -1) ENDIF ENDIF IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 1)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 1)) IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 1), SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 1)) TASK_TURN_PED_TO_FACE_ENTITY(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, 1), PLAYER_PED_ID(), -1) ENDIF ENDIF ENDIF IF GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) = GET_GOLF_FOURSOME_CART(thisFoursome,1) SET_ENTITY_AS_MISSION_ENTITY(GET_GOLF_FOURSOME_CART(thisFoursome,1), FALSE) SET_VEHICLE_AS_NO_LONGER_NEEDED(thisFoursome.vehCart[1]) SET_GOLF_FOURSOME_CART(thisFoursome, NULL, 1) ENDIF ENDIF //moves group if the player starts the game and there is a group on that hole IF g_sGolfGlobals.CurrrentPlayerHole = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) MOVE_GOLF_FOURSOME_TO_NEXT_AVAILABLE_HOLE(thisFoursome, thisCourse, allAIFoursomes) ENDIF //Make sure foursome is in an appropiate hole when the player is on the course IF iFoursomeIndex = 0 AND IS_GLOBAL_GOLF_CONTROL_FLAG_SET(GGCF_PLAYER_ADDRESSING_BALL) INT iMoveToHole = GET_HOLE_FOURSOME_SHOULD_BE_AT_WHEN_PLAYER_IS_AT_HOLE(g_sGolfGlobals.CurrrentPlayerHole) IF GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) != iMoveToHole AND NOT IS_ANY_GOLF_FOURSOME_PLAYING_HOLE(allAIFoursomes, iMoveToHole) MOVE_GOLF_AI_FOURSOME_TO_HOLE(thisFoursome, thisCourse, iMoveToHole) ENDIF ENDIF IF IS_GOLF_CONTROL_FLAG_SET(thisGame, GCF_PLAYER_SKIP) OR IS_GLOBAL_GOLF_CONTROL_FLAG_SET(GGCF_PLAYER_SKIP) // Player has pressed skip - move all players to their next shot REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex 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_PLAYER_BALL_POSITION(thisFoursome.playerCore[playerIndex])) ENDIF ENDIF ENDREPEAT SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF IF IS_GOLF_CONTROL_FLAG_SET(thisGame, GCF_PLAYER_DONE_WITH_HOLE) OR IS_GLOBAL_GOLF_CONTROL_FLAG_SET(GGCF_PLAYER_DONE_WITH_HOLE) // Player has finished hole - move all players to their next tee INT iMoveToHole = GET_HOLE_FOURSOME_SHOULD_BE_AT_WHEN_PLAYER_IS_AT_HOLE(g_sGolfGlobals.CurrrentPlayerHole) MOVE_GOLF_AI_FOURSOME_TO_HOLE(thisFoursome, thisCourse, iMoveToHole) ENDIF INT iCurrentHole VECTOR moveTo SWITCH GET_GOLF_FOURSOME_STATE(thisFoursome) CASE GGS_GET_IN_CART IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) //task every golfer in the foursome to go to the cart // REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome,thisFoursome.iLocalPlayerIndex)) AND NOT IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome,thisFoursome.iLocalPlayerIndex)) AND DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex)) AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, thisFoursome.iLocalPlayerIndex, GOLF_PLAYER_REMOVED) AND GET_DISTANCE_BETWEEN_ENTITIES(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, thisFoursome.iLocalPlayerIndex), GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex)) < 25.0 IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex), SCRIPT_TASK_ENTER_VEHICLE) != PERFORMING_TASK AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, thisFoursome.iLocalPlayerIndex, GOLF_STOP_USING_CART) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex)) IF NOT IS_PED_IN_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome,thisFoursome.iLocalPlayerIndex)) IF thisFoursome.iLocalPlayerIndex = GET_GOLF_FOURSOME_CART_DRIVER(thisFoursome, GET_GOLF_FOURSOME_INDEXED_PLAYER_CART_INDEX(thisFoursome,thisFoursome.iLocalPlayerIndex)) IF NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex+1)) OR NOT IS_PED_GETTING_INTO_A_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex+1)) TASK_ENTER_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome,thisFoursome.iLocalPlayerIndex), DEFAULT_TIME_NEVER_WARP, VS_DRIVER, PEDMOVE_WALK) ENDIF ELSE TASK_ENTER_VEHICLE(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, thisFoursome.iLocalPlayerIndex), GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome,thisFoursome.iLocalPlayerIndex), DEFAULT_TIME_NEVER_WARP, VS_FRONT_RIGHT, PEDMOVE_WALK) ENDIF ENDIF ENDIF ELSE //the cart does not exist tell everyone to walk to ball SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex IF playerIndex != GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome) IF IS_INDEXED_BALL_IN_RANGE_OF_GREEN(thisCourse, thisFoursome, playerIndex) moveTo = GET_GOLF_HOLE_GREEN_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex) ELIF NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) moveTo = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), playerIndex) ELSE moveTo = GET_GOLF_FOURSOME_INDEXED_PLAYER_BALL_POSITION(thisFoursome, playerIndex) ENDIF 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)) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex)) TASK_FOLLOW_NAV_MESH_TO_COORD(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, playerIndex), moveTo, PEDMOVE_WALK,DEFAULT_TIME_NEVER_WARP) ENDIF ENDIF ENDREPEAT IF IS_TEE_SHOT(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) ENDIF ENDIF //ENDREPEAT IF ARE_ALL_GOLFERS_IN_CART(thisFoursome) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) playerIndex CLEAR_GOLF_PLAYER_CONTROL_FLAG(thisFoursome.playerCore[playerIndex], GOLF_CART_ARRIVED) ENDREPEAT SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_DRIVE_TO_SHOT) START_TIMER_NOW(thisFoursome.physicsTimer) ENDIF ELSE //the player is far away from this golfer SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) IF IS_TEE_SHOT(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) ENDIF ENDIF BREAK CASE GGS_DRIVE_TO_SHOT //wait a little bit before the cart starts driving, otherwise it looks to robotic IF TIMER_DO_WHEN_READY(thisFoursome.physicsTimer, 2.0) AI_DRIVE_CART(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome), thisCourse, TRUE) ENDIF //the first cart is driving the current golfer and there are more then two golfers IF GET_GOLF_FOURSOME_CURRENT_PLAYER_CART_INDEX(thisFoursome) = 0 AND GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) > 2 AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 2, GOLF_STOP_USING_CART) //have the second cart drive to a ball IF GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) = 3 AI_DRIVE_CART(thisFoursome, 2, thisCourse, FALSE) //the third ped is the only possible driver in this case ELSE AI_DRIVE_CART(thisFoursome, GET_GOLF_PLAYER_WHOSE_BALL_IS_FARTHER_FROM_PIN(thisFoursome, 2, 3), thisCourse, FALSE) ENDIF ELIF GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) > 2 //the second cart is driving the current gofler AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 0, GOLF_STOP_USING_CART) //have the first cart drive to a ball AI_DRIVE_CART(thisFoursome, GET_GOLF_PLAYER_WHOSE_BALL_IS_FARTHER_FROM_PIN(thisFoursome, 0, 1), thisCourse, FALSE) ENDIF BREAK /* CASE GGS_NAVIGATE_TO_SHOT // DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_NAVIGATE_TO_SHOT") GOLF_MANAGE_NAVIGATE_AI(thisCourse, thisFoursome) IF ARE_ALL_PLAYERS_ON_THE_GREEN(thisFoursome) // Delete the flag as everyone is on the green CLEANUP_GOLF_HOLE_FLAG(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome)) ENDIF IF GOLF_IS_ANY_PLAYER_APPROACHING_BALL(thisFoursome) IF bDebugSpew DEBUG_MESSAGE("GMS_NAVIGATE_TO_SHOT - player approaches shot") ENDIF SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF BREAK //*/ CASE GGS_TAKING_SHOT // DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_TAKING_SHOT") //If the 'wait for available hole' flag is not set IF NOT IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_WAITING_FOR_HOLE) //take shot GOLF_AI_PLAYER_TAKE_SHOT(thisGame, thisCourse, thisFoursome) ELSE //Check availablity again IF IS_NEXT_GOLF_HOLE_AVAILABLE(thisCourse, thisFoursome, allAIFoursomes, 0) //Clear wait control flag CLEAR_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG(thisFoursome, GOLF_WAITING_FOR_HOLE) ENDIF ENDIF IF NOT IS_PED_INJURED(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) SET_PED_RESET_FLAG(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), PRF_ExpandPedCapsuleFromSkeleton, TRUE) ENDIF // Next state logic is getting more complicated IF ARE_ALL_PLAYERS_DONE_WITH_HOLE(thisFoursome) GOLF_CLEANUP_CURRENT_HOLE(thisCourse, thisFoursome) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) thisFoursome.iCurrentPlayer SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) SET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome, <<0,0,0>>, LIE_TEE) SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_NORMAL(thisFoursome, <<0,0,-1>>) ENDREPEAT iCurrentHole = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) //Check to see if next hole is not empty IF NOT IS_NEXT_GOLF_HOLE_AVAILABLE(thisCourse, thisFoursome, allAIFoursomes) //Set control flag to wait SET_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG(thisFoursome, 0, GOLF_WAITING_FOR_HOLE) ENDIF GOLF_MOVE_TO_NEXT_HOLE(thisGame, thisCourse, thisFoursome, 8) SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome, 0) IF GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) != iCurrentHole GOLF_INIT_CURRENT_HOLE(thisCourse, thisFoursome) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_SCORECARD_END_HOLE) ENDIF IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_FAR_AWAY) //golfer is far away, teleport him to his next shot moveTo = GET_GOLF_HOLE_TEE_SPECTATE_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome), GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)) TELEPORT_GOLFER_TO_COORD(thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome), moveTo, thisCourse, FALSE) TASK_TURN_PED_TO_FACE_COORD(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), GET_GOLF_HOLE_PIN_POSITION(thisCourse, GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome))) ENDIF ELIF IS_PLAYER_DONE_WITH_SHOT(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)]) CLEANUP_GOLF_CLUB(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)]) SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome, FIND_NEXT_SHOOTER(thisFoursome, thisCourse)) IF NOT ARE_ALL_PLAYERS_DONE_WITH_TEE_SHOT(thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) ELSE IF DOES_GOLF_AI_FOURSOME_USE_CART(thisFoursome, thisCourse) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_GET_IN_CART) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) ELSE SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) //no cart ENDIF ENDIF ENDIF BREAK CASE GGS_SCORECARD_END_HOLE // DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_SCORECARD_END_HOLE") IF IS_GOLF_FOURSOME_CURRENT_PLAYER_CONTROL_FLAG_SET(thisFoursome, GOLF_AI_FAR_AWAY) TELEPORT_FOURSOME_TO_TEE(thisFoursome, thisCourse) ENDIF SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_GET_IN_CART) BREAK CASE GGS_SCORECARD_END_GAME // DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_SCORECARD_END_GAME") BREAK ENDSWITCH ENDPROC PROC TASK_GOLF_FOURSOME_FLEE(GOLF_FOURSOME &thisFoursome, GOLF_GAME &thisGame) INT iCurrentPlayer REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer) IF PLAYER_PED_ID() != pedIndex AND NOT IS_PED_INJURED(pedIndex) PRINTLN("Send golfer flee") IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_INDEXED_PLAYER_CLUB(thisFoursome, iCurrentPlayer)) DETACH_ENTITY(GET_GOLF_FOURSOME_INDEXED_PLAYER_CLUB(thisFoursome, iCurrentPlayer)) ENDIF //friends don't run IF NOT IS_GOLF_CONTROL_FLAG_SET(thisGame, GCF_IS_FRIEND_ACTIVITY) TASK_SMART_FLEE_PED(pedIndex, PLAYER_PED_ID(), FAR_AWAY_THRESHOLD, -1) SET_PED_KEEP_TASK(pedIndex, TRUE) ENDIF ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Manages an AI foursome - navigating to shots, taking shots, finishing hole, etc /// PARAMS: /// thisGame - /// thisCourse - /// thisFoursome - PROC GOLF_MANAGE_AI_FOURSOME_PUTTING(GOLF_GAME &thisGame,GOLF_COURSE &thisCourse, GOLF_FOURSOME &thisFoursome) // PRINTSTRING("GOLF_MANAGE_AI_FOURSOME working on golfer ")PRINTINT(GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome))PRINTNL() IF IS_ENTITY_DEAD(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OR IS_PED_INJURED(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OR NOT DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OR IS_PED_FLEEING(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) CLEANUP_GOLF_FOURSOME_CURRENT_GOLF_BALL(thisFoursome) ENDIF EXIT ELSE AGGRO_ARGS aggroArguments EAGGRO aggroReason IF DO_AGGRO_CHECK(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), NULL, aggroArguments, aggroReason) OR IS_PED_IN_MELEE_COMBAT(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) OR IS_PED_RESPONDING_TO_EVENT(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), EVENT_POTENTIAL_GET_RUN_OVER) CLEAR_PED_TASKS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome)) TASK_SMART_FLEE_PED(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), PLAYER_PED_ID(), FAR_AWAY_THRESHOLD, -1) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), TRUE) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_SCORECARD_END_GAME) EXIT ENDIF ENDIF UPDATE_AI_FAR_AWAY(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)], PLAYER_PED_ID(), thisFoursome, GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome), thisCourse) INT iCurrentHole SWITCH GET_GOLF_FOURSOME_STATE(thisFoursome) CASE GGS_NAVIGATE_TO_SHOT //DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_NAVIGATE_TO_SHOT") GOLF_ATTACH_CLUB_FOR_WALKING(thisFoursome, thisGame) GOLF_MANAGE_NAVIGATE_AI(thisCourse, thisFoursome) IF GOLF_IS_PLAYER_APPROACHING_BALL(thisFoursome.playerCore[0]) //DEBUG_MESSAGE("GMS_NAVIGATE_TO_SHOT - player approaches shot") SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_TAKING_SHOT) ENDIF BREAK CASE GGS_TAKING_SHOT //DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_TAKING_SHOT") GOLF_AI_PLAYER_TAKE_SHOT(thisGame, thisCourse, thisFoursome) SET_PED_RESET_FLAG(GET_GOLF_FOURSOME_CURRENT_PLAYER_PED(thisFoursome), PRF_ExpandPedCapsuleFromSkeleton, TRUE) IF GET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome) <= GPS_ADDRESS_BALL GOLF_ATTACH_CLUB_FOR_WALKING(thisFoursome, thisGame) ENDIF // Next state logic is getting more complicated IF ARE_ALL_PLAYERS_DONE_WITH_HOLE(thisFoursome) IF bDebugSpew DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: ARE_ALL_PLAYERS_DONE_WITH_HOLE") ENDIF GOLF_ATTACH_CLUB_FOR_WALKING(thisFoursome, thisGame) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) thisFoursome.iCurrentPlayer SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_PLACE_BALL) SET_GOLF_FOURSOME_CURRENT_PLAYER_LIE(thisFoursome, <<0,0,0>>, LIE_TEE) SET_GOLF_FOURSOME_CURRENT_PLAYER_SHOT_NORMAL(thisFoursome, <<0,0,-1>>) ENDREPEAT iCurrentHole = GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) IF iCurrentHole = 0 SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, 1) ELIF iCurrentHole = 1 SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, 0) ELIF iCurrentHole = 4 SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, 3) ELIF iCurrentHole = 3 SET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome, 4) ENDIF SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome, 0) IF GET_GOLF_FOURSOME_CURRENT_HOLE(thisFoursome) != iCurrentHole GOLF_INIT_CURRENT_HOLE(thisCourse, thisFoursome) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_SCORECARD_END_HOLE) ENDIF IF DOES_ENTITY_EXIST(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome)) SET_GOLF_FOURSOME_CURRENT_PLAYER_BALL_POSITION(thisFoursome, GET_ENTITY_COORDS(GET_GOLF_FOURSOME_CURRENT_PLAYER_BALL(thisFoursome))) ENDIF ELIF IS_PLAYER_DONE_WITH_SHOT(thisFoursome.playerCore[GET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome)]) SET_GOLF_FOURSOME_CURRENT_PLAYER_STATE(thisFoursome, GPS_APPROACH_BALL) GOLF_MANAGE_NAVIGATE_AI(thisCourse, thisFoursome) SET_GOLF_FOURSOME_CURRENT_PLAYER(thisFoursome, 0) GOLF_ATTACH_CLUB_FOR_WALKING(thisFoursome, thisGame) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_NAVIGATE_TO_SHOT) ENDIF BREAK CASE GGS_SCORECARD_END_HOLE //DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_SCORECARD_END_HOLE") GOLF_MANAGE_NAVIGATE_AI(thisCourse, thisFoursome) SET_GOLF_FOURSOME_STATE(thisFoursome, GGS_NAVIGATE_TO_SHOT) BREAK CASE GGS_SCORECARD_END_GAME //DEBUG_MESSAGE("GOLF_MANAGE_AI_FOURSOME: GMS_SCORECARD_END_GAME") BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Stub for cleaning up an AI foursome. /// PARAMS: /// thisFoursome - PROC GOLF_CLEANUP_AI_FOURSOME (GOLF_FOURSOME &thisFoursome) UNUSED_PARAMETER(thisFoursome) ENDPROC //Manage the second group of golfers in single player golf PROC GOLF_MANAGE_NAVIAGTE_AI_GROUP(GOLF_GAME thisGame, GOLF_FOURSOME &thisFoursome, GOLF_COURSE &thisCourse) #IF GOLF_IS_MP EXIT #ENDIF #IF NOT GOLF_IS_AI_ONLY IF IS_SYNCHRONIZED_SCENE_RUNNING(iGolfResetSceneID) EXIT //dont update ai while intro scene is running ENDIF #ENDIF INT iCurrentPlayer REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer IF iCurrentPlayer > 1 IF NOT (IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 2, GOLF_STOP_USING_CART) OR IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 3, GOLF_STOP_USING_CART)) IF ARE_ALL_GOLFERS_IN_CART(thisFoursome, 2) AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 3, GOLF_STOP_USING_CART) AI_DRIVE_CART(thisFoursome, 2, thisCourse, FALSE, TRUE) ELIF NOT (GET_GOLF_FOURSOME_INDEXED_PLAYER_LIE(thisFoursome, iCurrentPlayer) = LIE_GREEN AND GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, iCurrentPlayer) != 1) AND GET_GOLF_FOURSOME_INDEXED_PLAYER_STATE(thisFoursome, iCurrentPlayer) != GPS_DONE_WITH_HOLE AND NOT IS_GOLF_FOURSOME_INDEXED_PLAYER_CONTROL_FLAG_SET(thisFoursome, 2, GOLF_CART_ARRIVED) AND GET_DISTANCE_BETWEEN_ENTITIES(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, iCurrentPlayer), GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer)) < 40.0 GOLF_AI_WALK_TO_CART(thisFoursome, iCurrentPlayer) ELSE DO_NAVIGATION_TO_NEXT_SHOT(thisCourse, thisFoursome, iCurrentPlayer) ENDIF ELSE DO_NAVIGATION_TO_NEXT_SHOT(thisCourse, thisFoursome, iCurrentPlayer) ENDIF ELIF iCurrentPlayer = 1 IF (GET_GOLF_FOURSOME_INDEXED_PLAYER_LIE(thisFoursome, iCurrentPlayer) = LIE_GREEN AND GET_GOLF_FOURSOME_INDEXED_PLAYER_SHOTS_ON_HOLE(thisFoursome, iCurrentPlayer) != 1) OR IS_ENTITY_DEAD(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, 1)) OR IS_ENTITY_IN_WATER(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, 1)) OR GET_DISTANCE_BETWEEN_ENTITIES(GET_GOLF_FOURSOME_INDEXED_PLAYER_CART(thisFoursome, iCurrentPlayer), GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer)) > 40.0 DO_NAVIGATION_TO_NEXT_SHOT(thisCourse, thisFoursome, iCurrentPlayer) ELSE IF NOT IS_GOLF_CONTROL_FLAG_SET(thisGame, GCF_IS_FRIEND_ACTIVITY) //during friend activity, just let the friend follow you around GOLF_AI_WALK_TO_CART(thisFoursome, iCurrentPlayer) ELSE IF GET_SCRIPT_TASK_STATUS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer), SCRIPT_TASK_PLAY_ANIM) = PERFORMING_TASK CLEAR_PED_TASKS(GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer)) ENDIF ENDIF ENDIF ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Called every frame to manage golf buddies /// PARAMS: /// thisFoursome /// RETURNS: /// TRUE if a ped is dead, injured or non-exsistant FUNC BOOL UPDATE_GOLF_BUDDIES_AI(GOLF_FOURSOME &thisFoursome) INT iCurrentPlayer // AGGRO_ARGS aggroArguments // EAGGRO aggroReason // // SET_BITMASK_AS_ENUM(aggroArguments.iBitFieldDontCheck, EAggro_JackingCar) REPEAT GET_GOLF_FOURSOME_NUM_PLAYERS(thisFoursome) iCurrentPlayer PED_INDEX pedIndex = GET_GOLF_FOURSOME_INDEXED_PLAYER_PED(thisFoursome, iCurrentPlayer) IF iCurrentPlayer != 0 //Make sure the player isn't attacking a ped IF IS_PED_INJURED(pedIndex) RETURN TRUE ELSE IF iCurrentPlayer = 1 //buddy can't run SET_PED_MAX_MOVE_BLEND_RATIO(pedIndex, PEDMOVE_WALK) ENDIF SET_PED_CAN_PLAY_AMBIENT_ANIMS(pedIndex, FALSE) ENDIF ENDIF ENDREPEAT RETURN FALSE ENDFUNC