// SCRIPT NAME : chop.sc // AUTHOR : Kenneth Ross / Kev Edwards // DESCRIPTION : Spawns chop the dog in Franklins back garden, player can command Chop to perform various tricks depending on the skill level achieved in app //Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. USING "pickups_weapon.sch" USING "pickups_armour.sch" USING "pickups_health.sch" USING "pickups_letter.sch" USING "pickups_spaceship.sch" USING "pickups_query.sch" USING "rgeneral_include.sch" USING "RC_Helper_Functions.sch" USING "RC_Area_public.sch" USING "website_public.sch" ENUM CHOP_STAGE_ENUM STAGE_INIT = 0, STAGE_PROCESS ENDENUM CHOP_STAGE_ENUM eStage ENUM CHOP_TASK_ENUM CHOP_TASK_NONE = 0, CHOP_TASK_WAIT, CHOP_TASK_WALK, CHOP_TASK_RETURN, CHOP_TASK_WANDER, CHOP_TASK_SNIFF, CHOP_TASK_ATTACK, CHOP_TASK_BEG, CHOP_TASK_SIT, CHOP_TASK_PAW, CHOP_TASK_PET,//10 CHOP_TASK_SPAWNED_IN_KENNEL, CHOP_TASK_SIT_OUTSIDE_SHOP, CHOP_TASK_SHIT, CHOP_TASK_PISS, CHOP_TASK_FETCH, CHOP_TASK_CABLE_CAR, CHOP_TASK_WAIT_PLAY_ANIM, CHOP_TASK_GREET_FRANKLIN ENDENUM CHOP_TASK_ENUM eChopTask INT iChopStage CHOP_TASK_ENUM eNextChopTask = CHOP_TASK_NONE ENUM HELP_FLAG CHOP_HELP_INTERACT_WITH_CHOP = 0, CHOP_HELP_BARK_NEAR_PICKUPS, CHOP_HELP_VEHICLE_IS_SUITABLE, CHOP_HELP_VEHICLE_NOT_SUITABLE, CHOP_HELP_TOO_FAR_AWAY, CHOP_HELP_FOLLOW_ON_BIKE, CHOP_HELP_ATTACK_ENEMIES, CHOP_HELP_PLAY_FETCH, CHOP_HELP_WHISTLE, CHOP_HELP_KILLED_BY_PLAYER, CHOP_HELP_MISBEHAVE, CHOP_HELP_ATTACK_AIM, CHOP_HELP_KILLED_BY_SOMEONE_ELSE ENDENUM ENUM CHOP_INPUT_TYPE CHOP_INPUT_ENGAGE = 0, CHOP_INPUT_SEARCH, CHOP_INPUT_SIT, CHOP_INPUT_PAW, CHOP_INPUT_BEG, CHOP_INPUT_PET ENDENUM INT iRadioStationHowlTimer = -1 INT iDelayUntilNextHowl INT iBarkTimer INT iBarkInVehicleTimer // B*1801754 Prevent barking immediately after a vehicle shunt INT iDelayUntilNextBark INT iDelayUntilNextPickupScan INT iNextWantedWhimperTimer INT iDelayUntilNextWantedWhimper INT iChopBehaviourNotMovingTimer INT iChopFetchExcitedTimer INT iChopPtfxTimer INT iChopWarpToVehicleTimer INT iChopWarpToVehicleTimeLimit INT iChopReachedPickupTimer INT iChopVehicleInWaterTimer PED_INDEX chopID BLIP_INDEX blipChop REL_GROUP_HASH relGroupChop BOOL bRelGroupExists = FALSE BOOL bFranklinTaskedToLookAtChop BOOL bIsChopTargettable BOOL bPlayerChoseToWalkChop VECTOR vLastChopBehaviourPosition PTFX_ID ptfx_chop VEHICLE_INDEX vehChop // The vehicle that Chop is sat inside BOOL bPlayWaitStandAnim STRING sAnimDict[3] STRING sAnimPlaying = "null" INT iNavBlockerPool = -1 INT iNavBlockerJacuzzi = -1 CONST_INT NUM_CHOP_CABLE_CAR_POSITIONS 4 VECTOR vChopCableCarPos[NUM_CHOP_CABLE_CAR_POSITIONS] FLOAT fChopCableCarPos[NUM_CHOP_CABLE_CAR_POSITIONS] ENUM CHOP_VEHICLE_STATUS CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE = 0, CHOP_VEHICLE_STATUS_FRANKLIN_ENTERING_VEHICLE, CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR, CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR, CHOP_VEHICLE_STATUS_CHOP_ENTER_VEHICLE, CHOP_VEHICLE_STATUS_CHOP_ENTERING_VEHICLE, CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR, CHOP_VEHICLE_STATUS_FRANKLIN_CLOSING_DOOR, CHOP_VEHICLE_STATUS_CHOP_SAT_IN_CAR, CHOP_VEHICLE_STATUS_WAIT_UNTIL_PLAYER_EXITED, CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR_FOR_EXIT, CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR_FOR_EXIT, CHOP_VEHICLE_STATUS_CHOP_EXIT_VEHICLE, CHOP_VEHICLE_STATUS_CHOP_EXITING_VEHICLE, CHOP_VEHICLE_STATUS_CHOP_FOLLOWING_BIKE, CHOP_VEHICLE_STATUS_CLEANUP ENDENUM CHOP_VEHICLE_STATUS chopInVehicleStatus INT iSynchSceneChop TEXT_LABEL_31 tlChopHelp BOOL bPlayerEnteringRightSide SC_DOOR_LIST doorChop = SC_DOOR_FRONT_RIGHT SEQUENCE_INDEX taskSequence TEST_POLY g_polyPlayArea structPedsForConversation sConversation BOOL bPlayedVehicleDialogue ENUM CHOP_CURRENT_PICKUP_TYPE CHOP_CURRENT_PICKUP_TYPE_ARMOUR, CHOP_CURRENT_PICKUP_TYPE_HEALTH, CHOP_CURRENT_PICKUP_TYPE_WEAPON, CHOP_CURRENT_PICKUP_TYPE_LETTER, CHOP_CURRENT_PICKUP_TYPE_SPACESHIP, CHOP_CURRENT_PICKUP_TYPE_NONE ENDENUM CHOP_CURRENT_PICKUP_TYPE chopCurrentPickupType CHOP_CURRENT_PICKUP_TYPE chopCurrentValidityScan INT iClosestPickupTimer INT iClosestPickupOfType[5] FLOAT fDistanceToClosestPickupOfType[5] VECTOR vClosestPickupOfType[5] VECTOR vChopSitNearClosestPickupOfType[5] INT iClosestPickup VECTOR vClosestPickup VECTOR vChopSitNearClosestPickup FLOAT fMaxChopHuntDist = 200 // Maximum distance at which Chop will hunt for a pickup CONST_INT CHOP_REPEAT_EXCITED_DELAY 10000 CONST_FLOAT CHOP_ATTACK_RANGE 100.0 BOOL bDoingTimetableSwitchChopNotInVehicle BOOL bDoingTimetableSwitchChopIsInVehicle BOOL bPlayerUsedApp BOOL bOverrideHappiness = FALSE #IF IS_DEBUG_BUILD BOOL bOutputCameraToTTY = FALSE INT iOverrideChopEnterVehicleCamera = -1 #ENDIF STRUCT CHOP_DATA_STRUCT VECTOR vSpawnCoords FLOAT fSpawnHeading SAVEHOUSE_NAME_ENUM eSavehouse VECTOR vKennelCoords FLOAT fKennelHeading ENDSTRUCT CHOP_DATA_STRUCT sChopData INT iChopInKennelTimer INT iChopExitKennelTime BOOL bChopGreetedFranklinDone INT iNavmeshAttempts INT iGoToBallTasksGiven FLOAT fBallZHeight INT iWhistleTimer INT iUnhappyTimer = GET_GAME_TIMER() INT iUnhappyDelay = 10000 VECTOR vStartCoords OBJECT_INDEX oChopShit VECTOR vChopShit BOOL bChopDidShit OBJECT_INDEX oLamppost INT iChopPissDirection VECTOR vChopCurrentPositionAtLamppost VECTOR vLamppostOffset FLOAT fLamppostHeading VECTOR vChopLastShitPosition VECTOR vChopLastPissPosition BOOL bChopDoneShitDialogue BOOL bPlayedChopBusyDialogue CONST_INT NUM_CHOP_WANDER_POSITIONS 8 VECTOR vChopWanderPositions[NUM_CHOP_WANDER_POSITIONS] BOOL bChopWanderingBetweenPositions INT iCurrentChopCollar = -1 ENTITY_INDEX eBall VECTOR vBallPosition BOOL bChopRetrievedBall BOOL bPlayedFetchBallDialogue WEAPON_TYPE wThrownWeapon INT iChopFetchDelayTimer VEHICLE_LAYOUT_TYPE vehLayoutHash = LAYOUT_STANDARD STRING stringFranklinInVehicleAnim = "std_ds_open_door_for_chop" STRING stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@std_car" INT iDoingChopInVehicleCollisionAnim = 0 INT iFranklinVehicleDoorAnimTimer INT iChopSicBallsMeter CONST_INT CHOP_SIC_BALLS_CALL_COPS_LIMIT 3 CONST_INT CHOP_SIC_BALLS_COOLDOWN_TIMER 60000 INT iChopSicBallsTimer BOOL bChopAlreadyFacingFranklin BOOL bFranklinAlreadyFacingChop INT iBulletNearChopTimer INT iOldBallNearFranklinTimer = GET_GAME_TIMER() CAMERA_INDEX camChopEnterVehicle INT iNumTimesChopTakenForWalk INT iStockMarketTimer = GET_GAME_TIMER() INT i_DoorOpenTimer //B* 2336322: Make sure door is open when chop enters INT iPickupBallSound = GET_SOUND_ID() BOOL bPlayerHasBeenInCarWithChop = FALSE // B*1982159 Only latch the door for the player's last vehicle if the player got into a vehicle with Chop BOOL bHintCamAlreadyACtive = FALSE //B* 2002205: Don't kill hint cam if already active when thread starts /// PURPOSE: /// Debug widget functions. #IF IS_DEBUG_BUILD BOOL bSetCollar INT iCollarDraw, iCollarTex PROC SETUP_CHOP_WIDGETS() START_WIDGET_GROUP("Chop The Dog") ADD_WIDGET_BOOL("Unlock all tricks", g_bUnlockAllChopTricks) ADD_WIDGET_BOOL("Player has used app", bPlayerUsedApp) ADD_WIDGET_BOOL("Set debug collar", bSetCollar) ADD_WIDGET_INT_SLIDER("Collar drawable", iCollarDraw, 0, 10, 1) ADD_WIDGET_INT_SLIDER("Collar texture", iCollarTex, 0, 10, 1) ADD_WIDGET_FLOAT_READ_ONLY("Happiness from app (read only)", g_savedGlobals.sSocialData.sDogAppData.fHappiness) ADD_WIDGET_BOOL("Override happiness to 100", bOverrideHappiness) ADD_WIDGET_BOOL("Output cam pos and rot to tty", bOutputCameraToTTY) ADD_WIDGET_INT_SLIDER("Override Chop enter vehicle camera", iOverrideChopEnterVehicleCamera, -1, 3, 1) STOP_WIDGET_GROUP() ENDPROC PROC MAINTAIN_CHOP_WIDGETS() IF bSetCollar = TRUE IF NOT IS_PED_INJURED(chopID) SET_PED_COMPONENT_VARIATION(chopID, PED_COMP_TORSO, iCollarDraw, iCollarTex) ENDIF bSetCollar = FALSE ENDIF // Check for player using XML debug menu to unlock tricks (needs app) IF bPlayerUsedApp = FALSE // These variables will now get overridden with SPCID_UNLOCK_CHOP_TRICKS IF g_bDebugAppScreenOverride AND g_bDebugChopPlayedStatusOverride bPlayerUsedApp = TRUE ENDIF ENDIF ENDPROC #ENDIF /// PURPOSE: /// Returns the type of input to check for, depending on the current input mode FUNC CONTROL_TYPE GET_CHOP_INPUT_CONTROL() IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) RETURN PLAYER_CONTROL ELSE RETURN FRONTEND_CONTROL ENDIF ENDFUNC /// PURPOSE: /// Returns the input button to check for, for a given action FUNC CONTROL_ACTION GET_CHOP_INPUT_ACTION(CHOP_INPUT_TYPE eInputType) IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) SWITCH eInputType CASE CHOP_INPUT_ENGAGE RETURN INPUT_ATTACK CASE CHOP_INPUT_SEARCH RETURN INPUT_JUMP CASE CHOP_INPUT_SIT RETURN INPUT_COVER CASE CHOP_INPUT_PAW RETURN INPUT_RELOAD CASE CHOP_INPUT_BEG RETURN INPUT_CONTEXT CASE CHOP_INPUT_PET RETURN INPUT_ENTER ENDSWITCH CPRINTLN(DEBUG_AMBIENT, "GET_CHOP_INPUT_ACTION(): Unknown (keyboard+mouse) eInputType: ", eInputType) SCRIPT_ASSERT( "GET_CHOP_INPUT_ACTION(): Unknown (keyboard+mouse) eInputType") ELSE SWITCH eInputType CASE CHOP_INPUT_ENGAGE RETURN INPUT_SCRIPT_RB CASE CHOP_INPUT_SEARCH RETURN INPUT_SCRIPT_RT CASE CHOP_INPUT_SIT RETURN INPUT_SCRIPT_RLEFT CASE CHOP_INPUT_PAW RETURN INPUT_SCRIPT_RRIGHT CASE CHOP_INPUT_BEG RETURN INPUT_SCRIPT_RDOWN CASE CHOP_INPUT_PET RETURN INPUT_SCRIPT_RUP ENDSWITCH CPRINTLN(DEBUG_AMBIENT, "GET_CHOP_INPUT_ACTION(): Unknown (joypad) eInputType: ", eInputType) SCRIPT_ASSERT( "GET_CHOP_INPUT_ACTION(): Unknown (joypad) eInputType") ENDIF RETURN INPUT_NEXT_CAMERA // Error ENDFUNC /// PURPOSE: /// Handles Franklin looking at Chop when within 10m. PROC FRANKLIN_SHOULD_LOOK_AT_CHOP(BOOL b_franklin_should_look_at_chop) IF b_franklin_should_look_at_chop = TRUE //IF bFranklinTaskedToLookAtChop = FALSE // B*1501473 - Keep setting this on Franklin IF IS_ENTITY_ALIVE(chopID) TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), chopID, -1, SLF_WIDEST_YAW_LIMIT|SLF_WIDEST_PITCH_LIMIT) bFranklinTaskedToLookAtChop = TRUE //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Set Franklin to look at Chop") #ENDIF ENDIF ELSE IF bFranklinTaskedToLookAtChop = TRUE AND IS_ENTITY_ALIVE(PLAYER_PED_ID()) TASK_CLEAR_LOOK_AT(PLAYER_PED_ID()) bFranklinTaskedToLookAtChop = FALSE //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Stopped Franklin looking at Chop") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns true if Chop should be deleted when the script cleans up. FUNC BOOL SHOULD_CHOP_BE_DELETED() IF IS_PLAYER_SWITCH_IN_PROGRESS() AND IS_ENTITY_ALIVE(chopID) IF IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) OR IS_PED_IN_ANY_VEHICLE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player switch in progress and Chop is in a car, so delete Chop") #ENDIF RETURN TRUE ENDIF ENDIF IF g_bSafehouseTutorialIsActive = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bSafehouseTutorialIsActive is TRUE, so delete Chop") #ENDIF RETURN TRUE ENDIF IF g_bPlayerIsInCinema = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bPlayerIsInCinema is TRUE, so delete Chop") #ENDIF g_bPlayerIsInCinema = FALSE // Immediately reset the flag RETURN TRUE ENDIF IF IS_ENTITY_ALIVE(chopID) IF eChopTask = CHOP_TASK_SPAWNED_IN_KENNEL AND IS_ENTITY_OCCLUDED(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is still in his kennel and occluded, so delete Chop because he won't be able to navigate out using AI") #ENDIF // B*1469198 RETURN TRUE ENDIF IF IS_POINT_VISIBLE(GET_ENTITY_COORDS(chopID, FALSE), 1) // B*1021716 - Don't delete Chop if he's visible RETURN FALSE ENDIF ENDIF IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_STORY) // Don't delete if player isn't starting a mission RETURN FALSE ENDIF IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) // B*1133827 - Don't delete if phoning a friend OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP) RETURN FALSE ENDIF RETURN TRUE // B*1057917 - Delete Chop if a mission begins and he's not onscreen ENDFUNC /// PURPOSE: /// Release the ball projectile entity. PROC CLEANUP_BALL(BOOL b_delete) IF DOES_ENTITY_EXIST(eBall) VECTOR v_ball = GET_ENTITY_COORDS(eBall) IF IS_ENTITY_ATTACHED_TO_ANY_PED(eBall) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: eBall was attached to Chop so unattached it") #ENDIF DETACH_ENTITY(eBall) ENDIF SET_ENTITY_AS_NO_LONGER_NEEDED(eBall) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Released eBall") #ENDIF IF b_delete = TRUE AND wThrownWeapon = WEAPONTYPE_BALL CLEAR_AREA_OF_PROJECTILES(v_ball, 0.1) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Cleared area of projectiles at eBall coords") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// B*1088351 - Suppress other dog models because Chop can't fight them. PROC SUPPRESS_OTHER_CREATURES(BOOL b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_RETRIEVER, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_ROTTWEILER, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_BOAR, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_COYOTE, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_DEER, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_MTLION, b_suppress) SET_PED_MODEL_IS_SUPPRESSED(A_C_PIG, b_suppress) ENDPROC /// PURPOSE: /// Used in while loops to check the entities are ok, to continue in those while loops. FUNC BOOL ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(vehChop) AND IS_ENTITY_ALIVE(chopID) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Remove any help text that has been printed by the Cho script. PROC CLEANUP_CHOP_HELP_TEXT() IF IS_HELP_MESSAGE_BEING_DISPLAYED() // Don't just do a CLEAR_HELP in case we're cleaning up because a mission has been triggered which may have displayed its own help text IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_0") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_HOME") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_0") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_HUNT") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_NOVEH") //OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_RANGE") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_CAR") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_BIKE") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_ATTACK") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_BALL") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WHIS") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_NOAPP") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_BEHAVE") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_BEHAVA") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_AIM") CLEAR_HELP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop help text was onscreen when cleaning up so clearing help text") #ENDIF ENDIF ENDIF IF IS_PC_VERSION() IF IS_HELP_MESSAGE_BEING_DISPLAYED() // Don't just do a CLEAR_HELP in case we're cleaning up because a mission has been triggered which may have displayed its own help text IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_0_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_HOME_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_0_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_NOAPP_KM") CLEAR_HELP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop help text was onscreen when cleaning up so clearing help text (PC version)") #ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Latch Chop's door on the last player vehicle PROC SET_LATCH_DOOR_ON_LAST_PLAYER_VEHICLE() IF bPlayerHasBeenInCarWithChop = TRUE AND IS_ENTITY_ALIVE(GET_LAST_DRIVEN_VEHICLE()) AND GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(GET_LAST_DRIVEN_VEHICLE()) > 1 AND NOT IS_VEHICLE_DOOR_DAMAGED(GET_LAST_DRIVEN_VEHICLE(), doorChop) SET_VEHICLE_DOOR_LATCHED(GET_LAST_DRIVEN_VEHICLE(), doorChop, FALSE, TRUE, FALSE) // B*1955858 Ensure Chop's door won't be flapping around post-mission #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Latched GET_LAST_DRIVEN_VEHICLE() door") #ENDIF ENDIF ENDPROC /// PURPOSE: /// Clean up everything conceivably setup in this mission. PROC CLEANUP_SCRIPT() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Cleaning up script") #ENDIF IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_OF_THIS_SCRIPT_NAME()) > 1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Another Chop.sc thread is already running so not doing full cleanup") #ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: This is the only Chop.sc thread running so doing full cleanup") #ENDIF g_bPlayerInteractingWithChop = FALSE FRANKLIN_SHOULD_LOOK_AT_CHOP(FALSE) IF IS_GAMEPLAY_HINT_ACTIVE() AND NOT bHintCamAlreadyACtive //B* 2002205: Don't kill hint cam if already active STOP_GAMEPLAY_HINT() // Ensure gameplay hint has been stopped, see B*1431829 ENDIF // Remove Chop blip SAFE_REMOVE_BLIP(blipChop) // Chop has been unlocked IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_CHOP_THE_DOG_UNLOCKED) // Assert guard IF IS_PLAYER_PLAYING(PLAYER_ID()) // B*1406239 // Enable static blip based on unlocked safehouse IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FRANKLIN_MOVED_TO_HILLS_APARTMENT) // Restore static blip when outside Vinewood Hills Chop world point IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), <<19.30, 528.24, 169.63>>) > 50 SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_AMBIENT_CHOP_VH, TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying Chop blip STATIC_BLIP_AMBIENT_CHOP_VH") #ENDIF ENDIF ELSE // Restore static blip when outside South Central Chop world point IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), <<-11.15, -1425.56, 29.67>>) > 50 SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_AMBIENT_CHOP_SC, TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying Chop blip STATIC_BLIP_AMBIENT_CHOP_SC") #ENDIF ENDIF ENDIF ENDIF ENDIF CLEANUP_BALL(TRUE) SAFE_RELEASE_OBJECT(oChopShit) SAFE_RELEASE_OBJECT(oLamppost) IF DOES_PARTICLE_FX_LOOPED_EXIST(ptfx_chop) STOP_PARTICLE_FX_LOOPED(ptfx_chop) ENDIF REMOVE_PTFX_ASSET() IF HAS_PED_GOT_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_BALL) REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), WEAPONTYPE_BALL) ENDIF IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY) SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillFlyThroughWindscreen, TRUE) // B*1434346 ENDIF IF DOES_ENTITY_EXIST(chopID) IF SHOULD_CHOP_BE_DELETED() SAFE_DELETE_PED(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Deleted Chop") #ENDIF ELSE IF NOT IS_ENTITY_DEAD(chopID) AND IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF IF IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) OR IS_PED_IN_ANY_VEHICLE(chopID) // Chop is in a car, or doing a synched scene to get in/out, so we need to play anims to get him out IF IS_ENTITY_ALIVE(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is in car so need to make him get out") #ENDIF BOOL b_car_stopped = FALSE WHILE NOT b_car_stopped WAIT(0) IF NOT ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() // Need to check again due to while loop OR BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(vehChop) b_car_stopped = TRUE ENDIF ENDWHILE IF ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() // Need to check again due to while loop IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Opening doorChop so Chop can get out") #ENDIF SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) ENDIF REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) WHILE NOT HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) WAIT(0) ENDWHILE ENDIF IF ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() // Need to check again due to while loop iSynchSceneChop = CREATE_SYNCHRONIZED_SCENE(<<0,0,0>>,<<0,0,0>>) ATTACH_SYNCHRONIZED_SCENE_TO_ENTITY(iSynchSceneChop, vehChop, GET_ENTITY_BONE_INDEX_BY_NAME(vehChop, "seat_pside_f")) CLEAR_PED_TASKS_IMMEDIATELY(chopID) TASK_SYNCHRONIZED_SCENE(chopID, iSynchSceneChop, stringChopInVehicleAnimDict, "get_out", INSTANT_BLEND_IN, NORMAL_BLEND_OUT, SYNCED_SCENE_TAG_SYNC_OUT|SYNCED_SCENE_ON_ABORT_STOP_SCENE) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop was in car so making him get out") #ENDIF BOOL b_chop_now_out = FALSE WHILE NOT b_chop_now_out WAIT(0) IF NOT ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() // Need to check again due to while loop OR (IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) AND GET_SYNCHRONIZED_SCENE_PHASE(iSynchSceneChop) > 0.99) b_chop_now_out = TRUE ENDIF ENDWHILE WAIT(0) IF ARE_ENTITIES_OK_FOR_CHOP_VEHICLE_EXIT() // Need to check again due to while loop AND NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has got out so closing doorChop") #ENDIF SET_VEHICLE_DOOR_SHUT(vehChop, doorChop, FALSE) ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop now outside car") #ENDIF ENDIF ELIF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_FRANKLIN // B*1292832 - Don't warp Chop to player offset if he's switched to Trevor or Michael IF eChopTask = CHOP_TASK_WALK // B*1562427 - Somehow Chop warped beside Franklin. This is a failsafe to ensure this only occurs if Chop was on a walk or fetch task OR eChopTask = CHOP_TASK_FETCH #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop was in car but vehChop didn't exist so warping Chop out of whatever vehicle he's in") #ENDIF CLEAR_PED_TASKS_IMMEDIATELY(chopID) SAFE_TELEPORT_ENTITY(chopID, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(), <<1.75,0,0>>), GET_ENTITY_HEADING(chopID), TRUE) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop would have been warped beside Franklin but prevented this as his state wasn't walk or fetch") #ENDIF ENDIF ENDIF ENDIF IF IS_ENTITY_ALIVE(chopID) // Need to check again due to while loop SET_PED_KEEP_TASK(chopID, TRUE) TASK_SMART_FLEE_PED(chopID, PLAYER_PED_ID(), 100, -1) // If this Chop script is terminating we don't want Chop to still be walking around with the player unable to interact with Chop, so make Chop run away #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Made Chop flee player") #ENDIF ENDIF ENDIF SAFE_RELEASE_PED(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Released Chop") #ENDIF ENDIF ENDIF SET_LATCH_DOOR_ON_LAST_PLAYER_VEHICLE() SAFE_RELEASE_VEHICLE(vehChop) SUPPRESS_OTHER_CREATURES(FALSE) REMOVE_ANIM_DICT("creatures@rottweiler@move") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@enter") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@base") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@idle_a") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@exit") REMOVE_ANIM_DICT("creatures@rottweiler@in_vehicle@4x4") REMOVE_ANIM_DICT("creatures@rottweiler@in_vehicle@low_car") REMOVE_ANIM_DICT("creatures@rottweiler@in_vehicle@std_car") REMOVE_ANIM_DICT("creatures@rottweiler@in_vehicle@van") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_sitting@enter") REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_sitting@idle_a" ) REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_sitting@exit") REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") REMOVE_ANIM_DICT("creatures@rottweiler@amb@sleep_in_kennel@") REMOVE_ANIM_DICT("creatures@rottweiler@indication@") REMOVE_ANIM_DICT("misschop_vehicleenter_exit") REMOVE_ANIM_DICT("creatures@rottweiler@melee@streamed_taunts@") REMOVE_PED_FOR_DIALOGUE(sConversation, 1) REMOVE_PED_FOR_DIALOGUE(sConversation, 3) CLEANUP_CHOP_HELP_TEXT() DESTROY_ALL_CAMS() IF iNavBlockerPool > -1 REMOVE_NAVMESH_BLOCKING_OBJECT(iNavBlockerPool) ENDIF IF iNavBlockerJacuzzi > -1 REMOVE_NAVMESH_BLOCKING_OBJECT(iNavBlockerJacuzzi) ENDIF IF bRelGroupExists = TRUE REMOVE_RELATIONSHIP_GROUP(relGroupChop) ENDIF STOP_SOUND(iPickupBallSound) ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Script thread terminated") #ENDIF TERMINATE_THIS_THREAD() ENDPROC /// PURPOSE: /// Checks if the script should cleanup, if so returns true. FUNC BOOL SHOULD_SCRIPT_CLEANUP() IF eStage > STAGE_INIT IF DOES_ENTITY_EXIST(chopID) IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_STORY) AND g_bIsOnCableCar = FALSE // Don't terminate Chop script if the cable car script has been started #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is now on a story mission") #ENDIF RETURN TRUE ENDIF IF NOT IS_PED_THE_CURRENT_PLAYER_PED(CHAR_FRANKLIN) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is no longer Franklin") #ENDIF RETURN TRUE ENDIF IF g_bRandomEventActive = TRUE // B*1328660 Terminate ambient Chop if a random event begins in full #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bRandomEventActive is TRUE") #ENDIF RETURN TRUE ENDIF IF g_bScriptsSetSafeForCutscene = TRUE AND g_bIsOnCableCar = FALSE // Don't terminate Chop script if the cable car script has been started AND g_HasCellphoneRequestedSave = FALSE // B*1498810 Prevent script terminating when quick saving AND g_bCurrentlyUsingVendingMachine = FALSE // B*1567131 Prevent Chop running off when using a vending machine AND g_bCurrentlyUsingTelescope = FALSE // Prevent Chop running off when using a telescope AND g_bCurrentlyBuyingProperty = FALSE // B*1574904 Prevent Chop running off when buying a property AND g_bInATM = FALSE // Prevent Chop running off when using an ATM AND NOT Is_Player_Timetable_Scene_In_Progress() // B*1503527 Prevent script terminating if timetable scene sets g_bScriptsSetSafeForCutscene to true AND NOT IS_PLAYER_IN_ANY_SHOP() // B*1485031 Prevent script terminating when using a shop AND g_bShopCutsceneActive = FALSE // B*1557823 Prevent script terminating when showing a shop cutscene AND IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND NOT IS_PLAYER_CHANGING_CLOTHES() // B*1452680 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bScriptsSetSafeForCutscene is TRUE") #ENDIF RETURN TRUE ENDIF IF g_bPlayerLockedInToTrigger = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bPlayerLockedInToTrigger is TRUE") #ENDIF RETURN TRUE ENDIF IF IS_ENTITY_DEAD(chopID) IF IS_PLAYER_PLAYING(PLAYER_ID()) AND HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(chopID, PLAYER_PED_ID()) g_bPlayerHasKilledChop = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has been killed by the player") #ENDIF IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_KILLED_BY_PLAYER)) AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_KILLED_BY_PLAYER)) PRINT_HELP("CHOP_H_DEAD") // "Franklin killed Chop. Chop will soon return to Franklin's safehouse, but he's not happy." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_DEAD") #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has been killed by someone other than the player") #ENDIF IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_KILLED_BY_SOMEONE_ELSE)) AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_KILLED_BY_SOMEONE_ELSE)) PRINT_HELP("CHOP_H_DEAD2") // "Chop was killed. Chop will soon return to Franklin's safehouse." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_DEAD2") #ENDIF ENDIF ENDIF RETURN TRUE ELSE IF IS_PLAYER_SWITCH_IN_PROGRESS() //RETURN TRUE // B*1395743 Don't cleanup Chop if switching to Franklin who is positioned near a Chop worldbrain position CLEANUP_CHOP_HELP_TEXT() // But make sure any help text is removed as soon as the switch starts ELSE // B*1514491 Don't check for distance if a switch scene is in progress FLOAT f_cleanup_distance IF eChopTask = CHOP_TASK_WALK OR eChopTask = CHOP_TASK_SNIFF OR eChopTask = CHOP_TASK_FETCH f_cleanup_distance = 200.0 ELSE f_cleanup_distance = 100.0 ENDIF IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), chopID) > f_cleanup_distance #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has been abandoned, distance = ", f_cleanup_distance) #ENDIF IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_TOO_FAR_AWAY)) AND IS_PLAYER_PLAYING(PLAYER_ID()) // B*940495 Don't display if player isn't in control AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() // Don't display if player is switching to/from Franklin IF eChopTask = CHOP_TASK_WAIT OR eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_SPAWNED_IN_KENNEL OR eChopTask = CHOP_TASK_WANDER // B*1280794 Don't display if player has dismissed Chop OR eChopTask = CHOP_TASK_RETURN // B*1280794 Don't display if player has dismissed Chop OR eChopTask = CHOP_TASK_SHIT // B*1306595 Don't display if Chop is taking a dump while mooching near his kennel // Don't display any help message ELSE // B*940630 Only display if player is interacting with Chop SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_TOO_FAR_AWAY)) PRINT_HELP("CHOP_H_RANGE") // "Chop will stop following if you go too far away." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_RANGE") #ENDIF ENDIF ENDIF RETURN TRUE ENDIF ENDIF IF NOT IS_PED_IN_ANY_VEHICLE(chopID) AND GET_ENTITY_HEALTH(chopID) > 0 IF IS_ENTITY_IN_WATER(chopID) VECTOR v_chop = GET_ENTITY_COORDS(chopID) FLOAT f_water_height IF GET_WATER_HEIGHT(v_chop, f_water_height) IF f_water_height-v_chop.z > 0.1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is in deep water so killing him, water depth is ", f_water_height-v_chop.z) #ENDIF SET_ENTITY_HEALTH(chopID, 0) // B*1413242 Ensure Chop is killed if in water ENDIF ENDIF ENDIF IF IS_ENTITY_ON_FIRE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is on fire so killing him") #ENDIF SET_ENTITY_HEALTH(chopID, 0) // B*1563377 Ensure Chop is killed if on fire ENDIF ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop doesn't exist") #ENDIF RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Creates Chop's bone blip. PROC CREATE_CHOP_BLIP() IF NOT DOES_BLIP_EXIST(blipChop) AND IS_ENTITY_ALIVE(chopID) AND NOT IS_PED_IN_ANY_VEHICLE(chopID, TRUE) // Turn off relevant static blip as Chop's blip will be handled by this script whilst it is active IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FRANKLIN_MOVED_TO_HILLS_APARTMENT) SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_AMBIENT_CHOP_VH, FALSE) ELSE SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_AMBIENT_CHOP_SC, FALSE) ENDIF // Create dynamic Chop blip blipChop = CREATE_BLIP_FOR_PED(chopID, FALSE) SET_BLIP_SPRITE(blipChop, RADAR_TRACE_CHOP) ENDIF ENDPROC /// PURPOSE: /// Puts Chop in the player's group. PROC PUT_CHOP_IN_PLAYER_GROUP() IF NOT IS_PED_IN_GROUP(chopID) SET_PED_AS_GROUP_MEMBER(chopID, GET_PED_GROUP_INDEX(PLAYER_PED_ID())) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Put Chop in player's group") #ENDIF ENDIF IF IS_PED_IN_GROUP(chopID) SET_PED_NEVER_LEAVES_GROUP(chopID, TRUE) SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 1.0, 0.9, 3.0) SET_PED_CAN_TELEPORT_TO_GROUP_LEADER(chopID, GET_PED_GROUP_INDEX(PLAYER_PED_ID()), TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Setup Chop in player's group") #ENDIF ENDIF ENDPROC /// PURPOSE: /// Sets the anim dict for Chop based on the player vehicle. PROC SET_LAYOUT_HASH_FOR_CHOP_VEHICLE() IF IS_ENTITY_ALIVE(vehChop) vehLayoutHash = INT_TO_ENUM(VEHICLE_LAYOUT_TYPE, GET_VEHICLE_LAYOUT_HASH(vehChop)) SWITCH vehLayoutHash CASE LAYOUT_VAN CASE LAYOUT_VAN_BODHI CASE LAYOUT_VAN_BOXVILLE CASE LAYOUT_VAN_CADDY CASE LAYOUT_VAN_JOURNEY CASE LAYOUT_VAN_MULE CASE LAYOUT_VAN_POLICE CASE LAYOUT_VAN_TRASH CASE LAYOUT_4X4_DUBSTA // B*1844650 - Hipster DLC vehicle CASE LAYOUT_VAN_ROOSEVELT // B*1844650 - Hipster DLC vehicle stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@van" stringFranklinInVehicleAnim = "van_ds_open_door_for_chop" BREAK CASE LAYOUT_LOW //CASE LAYOUT_LOW_BFINJECTION // B*1834123 use Chop's normal enter/exit anims for the BF Injection vehicle CASE LAYOUT_LOW_DUNE CASE LAYOUT_LOW_INFERNUS CASE LAYOUT_LOW_RESTRICTED CASE LAYOUT_LOW_SENTINEL2 CASE LAYOUT_LOW_CHEETAH CASE LAYOUT_LOW_BLADE // B*1844650 - Hipster DLC vehicle CASE LAYOUT_LOW_TURISMOR // B*1844650 - Hipster DLC vehicle CASE LAYOUT_LOW_FURORE // B*1993428 - DLC vehicle CASE LAYOUT_LOW_OSIRIS // Luxe DLC vehicle stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@low_car" stringFranklinInVehicleAnim = "low_ds_open_door_for_chop" BREAK CASE LAYOUT_4X4 CASE LAYOUT_BISON CASE LAYOUT_RANGER CASE LAYOUT_RANGER_SWAT stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@4x4" stringFranklinInVehicleAnim = "std_ds_open_door_for_chop" BREAK DEFAULT stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@std_car" stringFranklinInVehicleAnim = "std_ds_open_door_for_chop" BREAK ENDSWITCH IF GET_ENTITY_MODEL(vehChop) = BRAWLER stringChopInVehicleAnimDict = "creatures@rottweiler@in_vehicle@4x4" stringFranklinInVehicleAnim = "std_ds_open_door_for_chop" ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Set vehLayoutHash to ", stringChopInVehicleAnimDict) #ENDIF ENDIF ENDPROC /// PURPOSE: /// Sets which door should open/close for Chop based on the player vehicle. PROC SET_CHOPS_DOOR_FOR_CHOP_VEHICLE() IF IS_ENTITY_ALIVE(vehChop) MODEL_NAMES model_player_car = GET_ENTITY_MODEL(vehChop) IF model_player_car = COACH doorChop = SC_DOOR_FRONT_LEFT #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Set doorChop to SC_DOOR_FRONT_LEFT") #ENDIF ELSE doorChop = SC_DOOR_FRONT_RIGHT #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Set doorChop to SC_DOOR_FRONT_RIGHT") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Updates Chop's collar if the player has selected a different one in the app. PROC UPDATE_CHOP_COLLAR() IF iCurrentChopCollar <> GET_CHOP_COLLAR_FROM_APP() AND IS_ENTITY_ALIVE(chopID) IF HAS_PLAYER_USED_CHOP_APP() iCurrentChopCollar = GET_CHOP_COLLAR_FROM_APP() SET_PED_COMPONENT_VARIATION(chopID, PED_COMP_TORSO, 0, iCurrentChopCollar) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Changed Chop's collar to ", iCurrentChopCollar) #ENDIF ELIF iCurrentChopCollar <> 4 // Prevents this constantly being set iCurrentChopCollar = 4 // B*1168557 Set to Ballas collar by default SET_PED_COMPONENT_VARIATION(chopID, PED_COMP_TORSO, 0, iCurrentChopCollar) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player hasn't used app so set his collar to Ballas (colour 4)") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Grab Chop initially using g_pScene_buddy, or GET_PED_NEARBY_PEDS if for whatever reason g_pScene_buddy no longer exists (see B*1881917) FUNC BOOL GRABBED_CHOP_FROM_TIMETABLE_SCENE() IF IS_ENTITY_ALIVE(g_pScene_buddy) // Check to see if Chop already exists (from timetable scene) AND IS_PED_MODEL(g_pScene_buddy, GET_CHOP_MODEL()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Grabbed Chop from g_pScene_buddy, now waiting for timetable scene to end") #ENDIF chopID = g_pScene_buddy RETURN TRUE ENDIF // If for whatever reason g_pScene_buddy doesn't exist by the time the Chop script needs to setup Chop, as a backup plan check GET_PED_NEARBY_PEDS for a ped with Chop's model PED_INDEX NearbyPeds[10] INT iCount = GET_PED_NEARBY_PEDS(PLAYER_PED_ID(), NearbyPeds) INT i REPEAT iCount i IF NearbyPeds[i] != NULL AND IS_ENTITY_ALIVE(NearbyPeds[i]) AND GET_ENTITY_MODEL(NearbyPeds[i]) = GET_CHOP_MODEL() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Grabbed Chop using GET_PED_NEARBY_PEDS, now waiting for timetable scene to end") #ENDIF chopID = NearbyPeds[i] RETURN TRUE ENDIF ENDREPEAT RETURN FALSE ENDFUNC /// PURPOSE: /// Creates Chop or grabs him from timetable scene if he already exists in the world. PROC INIT_CHOP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Initialising Chop") #ENDIF IF bDoingTimetableSwitchChopNotInVehicle = TRUE IF GRABBED_CHOP_FROM_TIMETABLE_SCENE() SET_ENTITY_AS_MISSION_ENTITY(chopID, TRUE, TRUE) CLEAR_PED_TASKS(chopID) UPDATE_CHOP_COLLAR() WHILE Is_Player_Timetable_Scene_In_Progress() WAIT(0) // Playing this anim on Chop is causing 1449657 for some reason /*IF Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F0_PLAYCHOP OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F1_PLAYCHOP IF IS_ENTITY_ALIVE(chopID) AND NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PLAY_ANIM) REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@base") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@base") SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(chopID, TRUE) CLEAR_PED_TASKS_IMMEDIATELY(chopID) TASK_PLAY_ANIM(chopID, "creatures@rottweiler@amb@world_dog_barking@base", "base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_NOT_INTERRUPTABLE) REMOVE_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@base") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing anim on Chop during timetable scene") #ENDIF ENDIF ENDIF ENDIF*/ ENDWHILE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Timetable scene has now finished") #ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Tried to create Chop for timetable switch, but couldn't grab g_pScene_buddy or using GET_PED_NEARBY_PEDS") #ENDIF ENDIF ELIF bDoingTimetableSwitchChopIsInVehicle = TRUE IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Creating Chop for in-vehicle timetable scene..") #ENDIF vehChop = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) SET_LAYOUT_HASH_FOR_CHOP_VEHICLE() SET_CHOPS_DOOR_FOR_CHOP_VEHICLE() CREATE_CHOP(chopID, GET_ENTITY_COORDS(PLAYER_PED_ID())) IF IS_ENTITY_ALIVE(chopID) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(chopID, TRUE) SET_PED_ALLOW_VEHICLES_OVERRIDE(chopID, TRUE) SET_PED_CAN_PLAY_AMBIENT_ANIMS(chopID, FALSE) SET_PED_CAN_PLAY_AMBIENT_BASE_ANIMS(chopID, FALSE) PUT_CHOP_IN_PLAYER_GROUP() SET_ENTITY_INVINCIBLE(chopID, TRUE) // B*1337712 SET_PED_INTO_VEHICLE(chopID, vehChop, VS_FRONT_RIGHT) chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_SAT_IN_CAR UPDATE_CHOP_COLLAR() FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Created Chop for in-vehicle timetable scene now waiting for timetable scene to end") #ENDIF WHILE Is_Player_Timetable_Scene_In_Progress() IF IS_ENTITY_ALIVE(chopID) AND NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PLAY_ANIM) REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) IF HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) TASK_PLAY_ANIM(chopID, stringChopInVehicleAnimDict, "sit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing anim on Chop in vehicle") #ENDIF ENDIF ENDIF WAIT(0) ENDWHILE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Timetable scene has now finished") #ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Tried to create Chop for in-vehicle timetable switch, but the player isn't in a vehicle") #ENDIF ENDIF ENDIF ENDIF IF NOT DOES_ENTITY_EXIST(chopID) // This script needs to create Chop - not handed over from timetable scene #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Creating new Chop instance") #ENDIF CREATE_CHOP(chopID, sChopData.vSpawnCoords, sChopData.fSpawnHeading, TRUE) ENDIF IF IS_ENTITY_ALIVE(chopID) ADD_RELATIONSHIP_GROUP("rel_group_chop", relGroupChop) bRelGroupExists = TRUE SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, RELGROUPHASH_PLAYER, relGroupChop) SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, relGroupChop, RELGROUPHASH_PLAYER) SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_DISLIKE, RELGROUPHASH_CAT, relGroupChop) SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_DISLIKE, relGroupChop, RELGROUPHASH_CAT) SET_PED_RELATIONSHIP_GROUP_HASH(chopID, relGroupChop) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(chopID, TRUE) SET_PED_ALLOW_VEHICLES_OVERRIDE(chopID, TRUE) // Allow chop into vehicles - see B*893918 SET_PED_CONFIG_FLAG(chopID, PCF_UseKinematicModeWhenStationary, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_DontAllowToBeDraggedOutOfVehicle, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_WillFlyThroughWindscreen, FALSE) SET_PED_CONFIG_FLAG(chopID, PCF_GetOutUndriveableVehicle, FALSE) SET_PED_CONFIG_FLAG(chopID, PCF_GetOutBurningVehicle, FALSE) SET_PED_CONFIG_FLAG(chopID, PCF_RunFromFiresAndExplosions, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_KeepRelationshipGroupAfterCleanUp, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_TeleportToLeaderVehicle, FALSE) // Don't warp Chop into Franklin's vehicle, he uses sync scenes attached to the vehicle SET_PED_CONFIG_FLAG(chopID, PCF_DontActivateRagdollFromBulletImpact, TRUE) // B*1424904 Prevent Chop repeatedly being shot to the ground when in combat SET_PED_CONFIG_FLAG(chopID, PCF_DisableGoToWritheWhenInjured, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_RemoveDeadExtraFarAway, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_DisableLadderClimbing, TRUE) SET_PED_CONFIG_FLAG(chopID, PCF_CanBeArrested, FALSE) SET_PED_CONFIG_FLAG(chopID, PCF_AllowLockonToFriendlyPlayers, TRUE) // B*1502571 Ensure Chop can target peds he's in the same rel group as SET_PED_CONFIG_FLAG(chopID, PCF_DontEnterVehiclesInPlayersGroup, TRUE) // B*1583936 Ensure Chop won't automatically follow Franklin into a vehicle SET_PED_CAN_PLAY_AMBIENT_ANIMS(chopID, FALSE) SET_PED_CAN_PLAY_AMBIENT_BASE_ANIMS(chopID, FALSE) GIVE_WEAPON_TO_PED(chopID, WEAPONTYPE_ANIMAL, 1, TRUE, TRUE) SET_PED_COMBAT_ATTRIBUTES(chopID, CA_ALWAYS_FIGHT, TRUE) SET_PED_COMBAT_ATTRIBUTES(chopID, CA_USE_COVER, FALSE) SET_PED_COMBAT_ATTRIBUTES(chopID, CA_CAN_FIGHT_ARMED_PEDS_WHEN_NOT_ARMED, TRUE) SET_PED_HEARING_RANGE(chopID, CHOP_ATTACK_RANGE) SET_PED_SEEING_RANGE(chopID, CHOP_ATTACK_RANGE) SET_PED_FLEE_ATTRIBUTES(chopID, FA_NEVER_FLEE, TRUE) SET_PED_SUFFERS_CRITICAL_HITS(chopID, FALSE) SET_PED_MAX_HEALTH(chopID, 800) SET_ENTITY_HEALTH(chopID, 800) SET_ENTITY_LOD_DIST(chopID, 200) // B*1405898 Ensure Chop never vanishes due to LOD dist IF NOT IS_PED_IN_ANY_VEHICLE(chopID) CREATE_CHOP_BLIP() ENDIF ADD_PED_FOR_DIALOGUE(sConversation, 3, chopID, "CHOP") SET_PED_CAN_BE_TARGETTED(chopID, FALSE) SET_ENTITY_IS_TARGET_PRIORITY(chopID, FALSE) SET_ALLOW_LOCKON_TO_PED_IF_FRIENDLY(chopID, FALSE) bIsChopTargettable = FALSE g_bPlayerHasKilledChop = FALSE iChopSicBallsMeter = 0 iChopSicBallsTimer = GET_GAME_TIMER() ENDIF ENDPROC /// PURPOSE: /// Resets the scan values used to find the closest pickup PROC RESET_PICKUP_SCAN_VALUES() INT i_pickup = 0 REPEAT 5 i_pickup // Reset the values iClosestPickupOfType[i_pickup] = -1 fDistanceToClosestPickupOfType[i_pickup] = 999999 vClosestPickupOfType[i_pickup] = <<0,0,0>> vChopSitNearClosestPickupOfType[i_pickup] = <<0,0,0>> ENDREPEAT ENDPROC /// PURPOSE: /// Creates Chop. PROC DO_INITIALISE() g_bPlayerInteractingWithChop = FALSE REQUEST_MODEL(GET_CHOP_MODEL()) IF NOT HAS_MODEL_LOADED(GET_CHOP_MODEL()) EXIT ENDIF IF Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_VH) sChopData.eSavehouse = SAVEHOUSE_FRANKLIN_VH sChopData.vSpawnCoords = << 18.1531, 535.2469, 169.6324 >> sChopData.fSpawnHeading = 204.8112 sChopData.vKennelCoords = << 19.527712,537.436035,170.143021 >> sChopData.fKennelHeading = 151.306351 vChopShit = << 19.45963, 535.78174, 169.62770 >> vChopWanderPositions[0] = <<17.36033, 528.89728, 169.62770>> vChopWanderPositions[1] = <<19.46877, 529.17847, 169.62770>> vChopWanderPositions[2] = <<20.82979, 531.51685, 169.62770>> vChopWanderPositions[3] = <<22.83555, 532.32813, 169.62770>> vChopWanderPositions[4] = <<20.79285, 535.00098, 169.62770>> vChopWanderPositions[5] = <<18.05178, 535.63214, 169.62770>> vChopWanderPositions[6] = <<18.92047, 534.09375, 169.62770>> vChopWanderPositions[7] = <<17.51333, 533.47748, 169.62770>> OPEN_TEST_POLY(g_polyPlayArea) ADD_TEST_POLY_VERT(g_polyPlayArea, << 12.41124, 535.54688, 169.62770 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << 19.04497, 538.57288, 169.62770 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << 25.00015, 534.44141, 169.62770 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << 28.09980, 527.76385, 169.42769 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << 17.75896, 523.31293, 169.22769 >>) CLOSE_TEST_POLY(g_polyPlayArea) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Data set for SAVEHOUSE_FRANKLIN_VH") #ENDIF ELSE sChopData.eSavehouse = SAVEHOUSE_FRANKLIN_SC sChopData.vSpawnCoords = << -10.25168, -1422.90698, 29.67775 >> sChopData.fSpawnHeading = 157.9037 sChopData.vKennelCoords = << -9.73, -1421.55, 30.10 >> sChopData.fKennelHeading = 148.26 vChopShit = << -10.63790, -1424.56055, 29.67365 >> vChopWanderPositions[0] = <<-10.03643, -1423.52869, 29.67602>> vChopWanderPositions[1] = <<-10.78779, -1425.30566, 29.70937>> vChopWanderPositions[2] = <<-12.70480, -1424.74805, 29.72222>> vChopWanderPositions[3] = <<-12.47465, -1422.48462, 29.74699>> vChopWanderPositions[4] = <<-14.26666, -1424.85522, 29.71964>> vChopWanderPositions[5] = <<-14.55816, -1423.04810, 29.78372>> vChopWanderPositions[6] = <<-16.13293, -1424.48914, 29.76139>> vChopWanderPositions[7] = <<-16.25662, -1423.32495, 29.81294>> OPEN_TEST_POLY(g_polyPlayArea) ADD_TEST_POLY_VERT(g_polyPlayArea, << -7.26821, -1427.06482, 29.67468 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << -7.39631, -1418.85083, 29.58580 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << -14.27201, -1421.59021, 29.76819 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << -22.85347, -1423.17273, 29.74042 >>) ADD_TEST_POLY_VERT(g_polyPlayArea, << -22.77974, -1427.16797, 29.65953 >>) CLOSE_TEST_POLY(g_polyPlayArea) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Data set for SAVEHOUSE_FRANKLIN_SC") #ENDIF ENDIF CPRINTLN(DEBUG_AMBIENT, "CHOP: ChopTrainingLevel = ", GET_CHOP_TRAINING_LEVEL_FROM_APP()) bPlayerUsedApp = HAS_PLAYER_USED_CHOP_APP() CPRINTLN(DEBUG_AMBIENT, "CHOP: bPlayerUsedApp = ", bPlayerUsedApp) CPRINTLN(DEBUG_AMBIENT, "CHOP: fMaxChopHuntDist = ", fMaxChopHuntDist) INIT_CHOP() IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD CLEAR_AREA_OF_OBJECTS(vChopShit, 2, CLEAROBJ_FLAG_FORCE) // B*1211717 Ensure previous Chop shit has been cleared REQUEST_MODEL(PROP_BIG_SHIT_02) WHILE NOT HAS_MODEL_LOADED(PROP_BIG_SHIT_02) WAIT(0) ENDWHILE oChopShit = CREATE_OBJECT(PROP_BIG_SHIT_02, vChopShit) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has been bad so create a turd prop near his kennel") #ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(PROP_BIG_SHIT_02) bChopDoneShitDialogue = FALSE ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop hasn't been bad so not creating a turd prop") #ENDIF bChopDoneShitDialogue = TRUE ENDIF bChopDidShit = FALSE IF GET_RANDOM_INT_IN_RANGE(0, 2) = 0 iChopExitKennelTime = -1 ELSE iChopExitKennelTime = GET_RANDOM_INT_IN_RANGE(20000, 30000) ENDIF IF bDoingTimetableSwitchChopNotInVehicle = TRUE eChopTask = CHOP_TASK_BEG // B*1168773 Do something after the switch scene has ended bPlayerChoseToWalkChop = TRUE // Ensures Chop will change to walk state after his trick ELIF bDoingTimetableSwitchChopIsInVehicle = TRUE eChopTask = CHOP_TASK_WALK ELIF iChopExitKennelTime > -1 eChopTask = CHOP_TASK_SPAWNED_IN_KENNEL bPlayerChoseToWalkChop = FALSE ELSE eChopTask = CHOP_TASK_WAIT bPlayerChoseToWalkChop = FALSE ENDIF iNavBlockerPool = ADD_NAVMESH_BLOCKING_OBJECT(<<11.23, 515.40, 168>>, <<9, 21, 4>>, DEG_TO_RAD(113)) // B*1018859 Stop Chop going near the pool at Franklin's VH safehouse iNavBlockerJacuzzi = ADD_NAVMESH_BLOCKING_OBJECT(<<24.0, 528.0, 168>>, <<5, 5, 4>>, DEG_TO_RAD(113)) // B*1463144 Stop Chop going near the jacuzzi at Franklin's VH safehouse vChopCableCarPos[0] = <<444.1685, 5569.0161, 780.1895>> vChopCableCarPos[1] = <<443.8968, 5574.9312, 780.1895>> vChopCableCarPos[2] = <<-739.1624, 5596.7837, 40.6594>> vChopCableCarPos[3] = <<-738.8002, 5593.2686, 40.6594>> fChopCableCarPos[0] = 270.0 fChopCableCarPos[1] = 270.0 fChopCableCarPos[2] = 95.0 fChopCableCarPos[3] = 95.0 RESET_PICKUP_SCAN_VALUES() bFranklinTaskedToLookAtChop = FALSE bChopGreetedFranklinDone = FALSE iWhistleTimer = GET_GAME_TIMER() // Ensure this has a default value INT i_chop_training_level = GET_CHOP_TRAINING_LEVEL_FROM_APP() IF i_chop_training_level > 4 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: GET_CHOP_TRAINING_LEVEL_FROM_APP returned a value greater than 4") #ENDIF i_chop_training_level = 4 ENDIF tlChopHelp = "CHOP_H_WAIT_" // Ensure this has a default value tlChopHelp += i_chop_training_level IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) tlChopHelp += "_KM" ENDIF g_bPlayerIsInCinema = FALSE // The player can't recruit Chop in a cinema so immediately reset the flag in case it got set to true eStage = STAGE_PROCESS ENDPROC /// PURPOSE: /// Returns TRUE if Chop is in the area allowed to perform tricks. See B*1040752. FUNC BOOL IS_PED_IN_TRICK_AREA(PED_INDEX ped_to_check, BOOL b_check_z_diff = TRUE) IF IS_ENTITY_ALIVE(chopID) AND IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_IN_RANGE_COORDS_2D(ped_to_check, sChopData.vSpawnCoords, 30) // Do a quick check before the complex poly test //DISPLAY_POLY(g_polyPlayArea) IF b_check_z_diff = TRUE IF IS_POINT_IN_POLY_2D(g_polyPlayArea, GET_ENTITY_COORDS(ped_to_check)) VECTOR v_chop = GET_ENTITY_COORDS(chopID) VECTOR v_franklin = GET_ENTITY_COORDS(PLAYER_PED_ID()) IF ABSF(v_chop.z - v_franklin.z) < 2.5 RETURN TRUE ENDIF ENDIF ELSE RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Is the letter scrap ambient running? FUNC BOOL IS_LETTER_SCRAP_MISSION_ACTIVE() RETURN g_savedGlobals.sAmbient.sLetterScrapData.bMissionActive ENDFUNC /// PURPOSE: /// Has specified letter scrap been collected yet? FUNC BOOL HAS_LETTER_SCRAP_BEEN_COLLECTED(INT iIndex) // Invalid index IF (iIndex < 0) OR (iIndex >= NUMBER_OF_LETTER_SCRAPS) SCRIPT_ASSERT("HAS_LETTER_SCRAP_BEEN_COLLECTED() - Passed an invalid index") RETURN FALSE ENDIF // if scrap index is 31 or less use first int IF (iIndex <= 31) RETURN IS_BIT_SET(g_savedGlobals.sAmbient.sLetterScrapData.iScrap0to31, iIndex) ENDIF // Other take 32 from index and use second int RETURN IS_BIT_SET(g_savedGlobals.sAmbient.sLetterScrapData.iScrap32to63, iIndex - 32) ENDFUNC /// PURPOSE: /// Is the spaceship part ambient running? FUNC BOOL IS_SPACESHIP_PART_MISSION_ACTIVE() RETURN g_savedGlobals.sAmbient.sSpaceshipPartData.bMissionActive ENDFUNC /// PURPOSE: Has specified spaceship part been collected yet? FUNC BOOL HAS_SPACESHIP_PART_BEEN_COLLECTED(INT iIndex) // Invalid index IF (iIndex < 0) OR (iIndex >= NUMBER_OF_SPACESHIP_PARTS) SCRIPT_ASSERT("HAS_SPACESHIP_PART_BEEN_COLLECTED() - Passed an invalid index") RETURN FALSE ENDIF // if scrap index is 31 or less use first int IF (iIndex <= 31) RETURN IS_BIT_SET(g_savedGlobals.sAmbient.sSpaceshipPartData.iScrap0to31, iIndex) ENDIF // Other take 32 from index and use second int RETURN IS_BIT_SET(g_savedGlobals.sAmbient.sSpaceshipPartData.iScrap32to63, iIndex - 32) ENDFUNC /// PURPOSE: /// Continuous scan to find the nearest pickup of each type PROC SCAN_FOR_NEAREST_PICKUP() IF chopCurrentValidityScan != CHOP_CURRENT_PICKUP_TYPE_NONE // Don't allow continuous scanning if we're checking for validity prior to Chop sniffing the nearest pickup OR (GET_GAME_TIMER() - iClosestPickupTimer) < 1000 OR bPlayerUsedApp = FALSE EXIT ENDIF VECTOR v_pickup_pos FLOAT f_current_dist INT i_pickup RESET_PICKUP_SCAN_VALUES() i_pickup = 0 REPEAT NUMBER_OF_WEAPON_PICKUPS i_pickup IF CAN_CHOP_REACH_WEAPON(i_pickup) v_pickup_pos = GET_WEAPON_PICKUP_COORDS(i_pickup, TRUE) IF NOT IS_VECTOR_ZERO(v_pickup_pos) f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(chopID), v_pickup_pos) IF f_current_dist < fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] AND f_current_dist < fMaxChopHuntDist iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] = i_pickup fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] = f_current_dist vClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] = GET_WEAPON_PICKUP_COORDS(i_pickup, FALSE) vChopSitNearClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] = v_pickup_pos ENDIF ENDIF ENDIF ENDREPEAT i_pickup = 0 REPEAT NUMBER_OF_HEALTH_PICKUPS i_pickup IF CAN_CHOP_REACH_HEALTH(i_pickup) v_pickup_pos = GET_HEALTH_PICKUP_COORDS(i_pickup, TRUE) IF NOT IS_VECTOR_ZERO(v_pickup_pos) f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(chopID), v_pickup_pos) IF f_current_dist < fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] AND f_current_dist < fMaxChopHuntDist iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] = i_pickup fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] = f_current_dist vClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] = GET_HEALTH_PICKUP_COORDS(i_pickup, FALSE) vChopSitNearClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] = v_pickup_pos ENDIF ENDIF ENDIF ENDREPEAT i_pickup = 0 REPEAT NUMBER_OF_ARMOUR_PICKUPS i_pickup IF CAN_CHOP_REACH_ARMOUR(i_pickup) v_pickup_pos = GET_ARMOUR_PICKUP_COORDS(i_pickup, TRUE) IF NOT IS_VECTOR_ZERO(v_pickup_pos) f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(chopID), v_pickup_pos) IF f_current_dist < fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] AND f_current_dist < fMaxChopHuntDist iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] = i_pickup fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] = f_current_dist vClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] = GET_ARMOUR_PICKUP_COORDS(i_pickup, FALSE) vChopSitNearClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] = v_pickup_pos ENDIF ENDIF ENDIF ENDREPEAT IF IS_LETTER_SCRAP_MISSION_ACTIVE() i_pickup = 0 REPEAT NUMBER_OF_LETTER_SCRAPS i_pickup IF NOT HAS_LETTER_SCRAP_BEEN_COLLECTED(i_pickup) AND CAN_CHOP_REACH_LETTERSCRAP(i_pickup) v_pickup_pos = GET_LETTERSCRAP_PICKUP_COORDS(i_pickup, TRUE) IF NOT IS_VECTOR_ZERO(v_pickup_pos) f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(chopID), v_pickup_pos) IF f_current_dist < fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] AND f_current_dist < fMaxChopHuntDist iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] = i_pickup fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] = f_current_dist vClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] = GET_LETTERSCRAP_PICKUP_COORDS(i_pickup, FALSE) vChopSitNearClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] = v_pickup_pos ENDIF ENDIF ENDIF ENDREPEAT ENDIF IF IS_SPACESHIP_PART_MISSION_ACTIVE() i_pickup = 0 REPEAT NUMBER_OF_SPACESHIP_PARTS i_pickup IF NOT HAS_SPACESHIP_PART_BEEN_COLLECTED(i_pickup) AND CAN_CHOP_REACH_UFOSCRAP(i_pickup) v_pickup_pos = GET_UFOSCRAP_PICKUP_COORDS(i_pickup, TRUE) IF NOT IS_VECTOR_ZERO(v_pickup_pos) f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(chopID), v_pickup_pos) IF f_current_dist < fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] AND f_current_dist < fMaxChopHuntDist iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] = i_pickup fDistanceToClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] = f_current_dist vClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] = GET_UFOSCRAP_PICKUP_COORDS(i_pickup, FALSE) vChopSitNearClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] = v_pickup_pos ENDIF ENDIF ENDIF ENDREPEAT ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Closest.. armour = ", iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR], " health = ", iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH], " weapon = ", iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON], " letter = ", iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER], " ufo = ", iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP]) #ENDIF iClosestPickupTimer = GET_GAME_TIMER() ENDPROC /// PURPOSE: /// Returns TRUE if the validity check for the current closest pickup for all 5 types has been completed. FUNC BOOL HAS_PICKUP_SCAN_BEEN_COMPLETED() IF chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_NONE chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_ARMOUR #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting HAS_PICKUP_SCAN_BEEN_COMPLETED") #ENDIF ENDIF SWITCH chopCurrentValidityScan CASE CHOP_CURRENT_PICKUP_TYPE_ARMOUR IF iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] > -1 IF IS_QUERY_RESULT_INACTIVE() INIT_PICKUP_QUERY_REQUEST(PC_QUERY_TYPE_ARMOUR, iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR]) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting armour check") #ENDIF ENDIF IF HAS_RETURNED_QUERY_RESULT() IF HAS_QUERIED_PICKUP_BEEN_COLLECTED() iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_ARMOUR] = -1 ENDIF END_PICKUP_QUERY_REQUEST() chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_HEALTH ENDIF ELSE chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_HEALTH ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_HEALTH IF iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] > -1 IF IS_QUERY_RESULT_INACTIVE() INIT_PICKUP_QUERY_REQUEST(PC_QUERY_TYPE_HEALTH, iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH]) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting health check") #ENDIF ENDIF IF HAS_RETURNED_QUERY_RESULT() IF HAS_QUERIED_PICKUP_BEEN_COLLECTED() iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_HEALTH] = -1 ENDIF END_PICKUP_QUERY_REQUEST() chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_WEAPON ENDIF ELSE chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_WEAPON ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_WEAPON IF iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] > -1 IF IS_QUERY_RESULT_INACTIVE() INIT_PICKUP_QUERY_REQUEST(PC_QUERY_TYPE_WEAPON, iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON]) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting weapon check") #ENDIF ENDIF IF HAS_RETURNED_QUERY_RESULT() IF HAS_QUERIED_PICKUP_BEEN_COLLECTED() iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_WEAPON] = -1 ENDIF END_PICKUP_QUERY_REQUEST() chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_LETTER ENDIF ELSE chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_LETTER ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_LETTER // and SPACESHIP (can do both at the same time) IF iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] > -1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting letter check") #ENDIF IF HAS_LETTER_SCRAP_BEEN_COLLECTED(iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER]) iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_LETTER] = -1 ENDIF ENDIF IF iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] > -1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting ufo check") #ENDIF IF HAS_SPACESHIP_PART_BEEN_COLLECTED(iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP]) iClosestPickupOfType[CHOP_CURRENT_PICKUP_TYPE_SPACESHIP] = -1 ENDIF ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Finished HAS_PICKUP_SCAN_BEEN_COMPLETED") #ENDIF chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_NONE RETURN TRUE BREAK ENDSWITCH RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the player already has full armour / health. FUNC BOOL IGNORE_FULL_HEALTH_AMMO_CHECK(BOOL b_ignore_check_for_full_health_armour, INT i_pickup_type) IF b_ignore_check_for_full_health_armour = TRUE RETURN TRUE ENDIF IF i_pickup_type = ENUM_TO_INT(CHOP_CURRENT_PICKUP_TYPE_HEALTH) AND GET_ENTITY_HEALTH(PLAYER_PED_ID()) >= 200 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player already has full health so not including health in this check") #ENDIF RETURN FALSE ENDIF IF i_pickup_type = ENUM_TO_INT(CHOP_CURRENT_PICKUP_TYPE_ARMOUR) AND GET_PED_ARMOUR(PLAYER_PED_ID()) >= 100 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player already has full armour so not including armour in this check") #ENDIF RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Works out the closest pickup. PROC FIND_CLOSEST_PICKUP(BOOL b_ignore_check_for_full_health_armour) FLOAT f_closest_dist = 9999 INT i_index = 0 REPEAT 5 i_index IF iClosestPickupOfType[i_index] > -1 // Only include in calcs if the continuous scan has found a pickup of this type within fMaxChopHuntDist AND fDistanceToClosestPickupOfType[i_index] < f_closest_dist AND IGNORE_FULL_HEALTH_AMMO_CHECK(b_ignore_check_for_full_health_armour, i_index) f_closest_dist = fDistanceToClosestPickupOfType[i_index] iClosestPickup = iClosestPickupOfType[i_index] chopCurrentPickupType = INT_TO_ENUM(CHOP_CURRENT_PICKUP_TYPE, i_index) vClosestPickup = vClosestPickupOfType[i_index] vChopSitNearClosestPickup = vChopSitNearClosestPickupOfType[i_index] ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Find the closest weapon / letter scrap / spaceship part to Franklin. FUNC BOOL IS_CHOP_WITHIN_RANGE_OF_NEAREST_PICKUP() iClosestPickup = -1 vClosestPickup = <<0,0,0>> vChopSitNearClosestPickup = <<0,0,0>> #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player health = ", GET_ENTITY_HEALTH(PLAYER_PED_ID()), " Player armour = ", GET_PED_ARMOUR(PLAYER_PED_ID())) #ENDIF FIND_CLOSEST_PICKUP(FALSE) // First try to find the closest pickup, but not including health/armour if the player already has full IF iClosestPickup = -1 // Still haven't found a closest pickup... #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Ignored health/armour if already full but didn't find another pickup type so trying again with a full check") #ENDIF FIND_CLOSEST_PICKUP(TRUE) // ...so search again but this time allow health/armour if the player is already full ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Ignored health/armour if already full and found another pickup type so not trying again with a full check") #ENDIF ENDIF IF iClosestPickup > -1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: chopCurrentPickupType = ", chopCurrentPickupType, " iClosestPickup = ", iClosestPickup, " fDistanceToClosestPickupOfType ", fDistanceToClosestPickupOfType[chopCurrentPickupType]) #ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Plays a bark / howl type sound from Chop. /// List of possible sounds to use: /// BARK /// BARK_SEQ (plays 2 or 3 barks in a sequence) /// SNARL /// GROWL /// PLAYFUL (a friendly-type moan) /// WHINE /// BREATH_AGITATED /// AGITATED PROC PLAY_CHOP_SOUND(STRING chop_sound) PLAY_ANIMAL_VOCALIZATION(chopID, AUD_ANIMAL_DOG_ROTTWEILER, chop_sound) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing Chop sound: ", chop_sound) #ENDIF ENDPROC /// PURPOSE: /// Plays an in-vehicle bark anim on Chop then goes back to his sit loop. PROC CHOP_BARK_IN_VEHICLE() IF (GET_GAME_TIMER() - iBarkInVehicleTimer) > 500 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Performing Chop bark in vehicle") #ENDIF iBarkInVehicleTimer = GET_GAME_TIMER() IF IS_ENTITY_ALIVE(chopID) AND IS_PED_IN_ANY_VEHICLE(chopID) OPEN_SEQUENCE_TASK(taskSequence) TASK_PLAY_ANIM(NULL, stringChopInVehicleAnimDict, "bark", SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, stringChopInVehicleAnimDict, "sit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: NOT Performing Chop bark in vehicle") #ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns true if Franklin has got into a car without any doors. FUNC BOOL IS_PLAYER_IN_CAR_CHOP_CANT_GET_INTO() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) MODEL_NAMES model_player_car = GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE)) IF model_player_car = CADDY // B*1380043 OR model_player_car = CADDY2 OR model_player_car = DUNE OR model_player_car = AIRTUG OR model_player_car = BLAZER OR model_player_car = BLAZER2 OR model_player_car = BULLDOZER OR model_player_car = CUTTER OR model_player_car = DUMP OR model_player_car = FORKLIFT OR model_player_car = HANDLER OR model_player_car = MOWER OR model_player_car = RHINO OR model_player_car = TRACTOR OR model_player_car = TRACTOR2 OR model_player_car = TRACTOR3 OR model_player_car = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("bifta")) // Beach Bum DLC OR model_player_car = BLAZER3 // Beach Bum DLC OR model_player_car = DUNE2 // Beach Bum DLC RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Some vehicles Chop should just warp into rather than playing Franklin's open/close door anims and Chop's entering/exiting anims. FUNC BOOL SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL() IF IS_ENTITY_ALIVE(vehChop) MODEL_NAMES model_player_car = GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE)) IF model_player_car = AIRBUS OR model_player_car = BARRACKS OR model_player_car = BARRACKS2 OR model_player_car = BIFF OR model_player_car = BUS OR model_player_car = COACH OR model_player_car = HAULER OR model_player_car = MIXER OR model_player_car = MIXER2 OR model_player_car = PACKER OR model_player_car = PBUS OR model_player_car = PHANTOM OR model_player_car = POUNDER OR model_player_car = RIOT OR model_player_car = RUBBLE OR model_player_car = SCRAP OR model_player_car = STOCKADE OR model_player_car = STOCKADE3 OR model_player_car = TIPTRUCK OR model_player_car = TIPTRUCK2 OR model_player_car = TOWTRUCK OR model_player_car = TOWTRUCK2 OR model_player_car = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("monster")) // Independence Day DLC OR model_player_car = INT_TO_ENUM(MODEL_NAMES, GET_HASH_KEY("marshall")) // B*2013329 RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Returns true if Franklin has got into a vehicle that Chop can also get into too. FUNC BOOL IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_ENTER() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) AND NOT IS_PED_ON_ANY_BIKE(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_PLANE(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_HELI(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_BOAT(PLAYER_PED_ID()) AND GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) >= 1 AND IS_VEHICLE_SEAT_FREE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VS_FRONT_RIGHT) AND NOT IS_PLAYER_IN_CAR_CHOP_CANT_GET_INTO() // Chop can't get into these as they're awkward vehicles like the dune buggy etc RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// When riding in Franklin's car or following Franklin's bike, Chop will occasionally check for nearby pickups and alert the player if he finds one. See B*1007705. PROC PERIODICALLY_CHECK_FOR_NEARBY_PICKUPS() IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) = 0 AND bPlayerUsedApp = TRUE // B*1096431 Don't scan for pickups if player hasn't used the app IF iDelayUntilNextPickupScan = -1 iDelayUntilNextPickupScan = GET_GAME_TIMER() ENDIF IF (GET_GAME_TIMER() - iDelayUntilNextPickupScan) > 10000 AND iDoingChopInVehicleCollisionAnim > -1 // Don't bark when doing a collision anim AND HAS_PICKUP_SCAN_BEEN_COMPLETED() IF IS_CHOP_WITHIN_RANGE_OF_NEAREST_PICKUP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Silently scanned for nearby pickup and found one") #ENDIF IF IS_ENTITY_ALIVE(chopID) IF IS_PED_IN_ANY_VEHICLE(chopID) // B*1406358 Check Chop is in a vehicle so should play a bark anim CHOP_BARK_IN_VEHICLE() ELSE PLAY_CHOP_SOUND("BARK") ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Silently scanned for nearby pickup but didn't find one") #ENDIF ENDIF iDelayUntilNextPickupScan = GET_GAME_TIMER() ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns true if the player either is locked onto Chop or is free-aiming at Chop FUNC BOOL IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() IF IS_PLAYER_TARGETTING_ENTITY(PLAYER_ID(), chopID) OR (eChopTask = CHOP_TASK_PET AND IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_AIM)) // Petting Chop will cause the player to cease targetting Chop // Using INPUT_AIM to fix B*1499642 WEAPON_TYPE current_player_weapon GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), current_player_weapon) IF current_player_weapon = WEAPONTYPE_UNARMED //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is targetting Chop") #ENDIF RETURN TRUE ENDIF ENDIF //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player isn't targetting Chop") #ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Sets Chop task and resets task stage. PROC GIVE_CHOP_TASK(CHOP_TASK_ENUM eTask, BOOL b_clear_chop_tasks = TRUE) chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE IF IS_ENTITY_ALIVE(chopID) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(chopID, TRUE) CLEAR_PED_LAST_WEAPON_DAMAGE(chopID) // Prevent Chop bailing out of a trick/shit straight away if he's previously been damaged IF NOT IS_PED_IN_ANY_VEHICLE(chopID) // If Chop is spawned in vehicle from switch scene don't clear his anim IF b_clear_chop_tasks = TRUE CLEAR_PED_TASKS(chopID) ENDIF SET_ENTITY_INVINCIBLE(chopID, FALSE) ENDIF ENDIF eChopTask = eTask eNextChopTask = CHOP_TASK_NONE iChopStage = 0 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: new primary task[", ENUM_TO_INT(eTask), "]") #ENDIF iClosestPickup = -1 vClosestPickup = <<0,0,0>> vChopSitNearClosestPickup = <<0,0,0>> chopCurrentValidityScan = CHOP_CURRENT_PICKUP_TYPE_NONE END_PICKUP_QUERY_REQUEST() bChopWanderingBetweenPositions = FALSE bPlayedChopBusyDialogue = FALSE iBulletNearChopTimer = GET_GAME_TIMER() SET_AUDIO_FLAG("DisableBarks", FALSE) ENDPROC /// PURPOSE: /// See B*1445449 - Chop whines if player shoots near to him PROC CHECK_FOR_PLAYER_BULLET_NEAR_CHOP() IF (GET_GAME_TIMER() - iBulletNearChopTimer) > 2000 AND IS_ENTITY_ALIVE(chopID) AND IS_BULLET_IN_AREA(GET_ENTITY_COORDS(chopID), 5) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player fired near Chop") #ENDIF PLAY_CHOP_SOUND("WHINE") iBulletNearChopTimer = GET_GAME_TIMER() ENDIF ENDPROC /// PURPOSE: /// Returns true if Franklin has got into a vehicle that Chop can follow. FUNC BOOL IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_FOLLOW() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) IF IS_PED_ON_ANY_BIKE(PLAYER_PED_ID()) OR IS_PLAYER_IN_CAR_CHOP_CANT_GET_INTO() // Chop can't get into these so just make him follow RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// See B*1502293 - Delete any nearby old balls. PROC SCAN_FOR_OLD_BALLS_NEAR_FRANKLIN() IF (GET_GAME_TIMER() - iOldBallNearFranklinTimer) > 500 iOldBallNearFranklinTimer = GET_GAME_TIMER() IF eChopTask != CHOP_TASK_FETCH AND GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(PLAYER_PED_ID(), WEAPONTYPE_BALL, 1.5, vBallPosition, eBall) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Found old ball near Franklin so deleting it") #ENDIF CLEANUP_BALL(TRUE) ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns TRUE if Franklin is in an interior that Chop can't follow into. Also see B*1006788 - Don't allow interaction with Chop if player is inside Franklin's house. FUNC BOOL IS_PLAYER_IN_RESTRICTED_INTERIOR() IF IS_VALID_INTERIOR(GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())) IF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = GET_INTERIOR_AT_COORDS(<<-14.5,-1437.2,31.1>>) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is in Franklin's VC safehouse") #ENDIF RETURN TRUE ENDIF IF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = GET_INTERIOR_AT_COORDS(<<7.6,537.3,176.0>>) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is in Franklin's SH safehouse") #ENDIF RETURN TRUE ENDIF IF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = GET_INTERIOR_AT_COORDS(<<130.2632, -1295.0345, 28.2695>>) // B*1407356 Prevent Chop following into the strip club #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is in strip club") #ENDIF RETURN TRUE ENDIF // Add any other interiors here ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Trigger conversation for if Franklin and Chop are in a car and the player puts on a radio station that Chop doesn't like. PROC PLAY_RADIO_HOWL_DIALOGUE() IF iDoingChopInVehicleCollisionAnim > -1 // Don't bark when doing a collision anim AND (GET_GAME_TIMER() - iRadioStationHowlTimer) > iDelayUntilNextHowl IF GET_PLAYER_RADIO_STATION_GENRE() = ENUM_TO_INT(RADIO_GENRE_LEFT_WING_TALK) OR GET_PLAYER_RADIO_STATION_GENRE() = ENUM_TO_INT(RADIO_GENRE_RIGHT_WING_TALK) OR GET_PLAYER_RADIO_STATION_GENRE() = ENUM_TO_INT(RADIO_GENRE_COUNTRY) OR GET_PLAYER_RADIO_STATION_GENRE() = ENUM_TO_INT(RADIO_GENRE_JAZZ) CHOP_BARK_IN_VEHICLE() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Making Chop howl due to disliking current radio station") #ENDIF iRadioStationHowlTimer = GET_GAME_TIMER() iDelayUntilNextHowl = GET_RANDOM_INT_IN_RANGE(6000, 8000) ENDIF ENDIF ENDPROC /// PURPOSE: /// Updates Chop's anims when he's sat in a car. PROC UPDATE_CHOPS_IN_VEHICLE_ANIMS() IF IS_ENTITY_ALIVE(chopID) AND IS_ENTITY_ALIVE(vehChop) IF iDoingChopInVehicleCollisionAnim > -1 IF (GET_GAME_TIMER() - iDoingChopInVehicleCollisionAnim) > 500 // B*1433652 Prevent retriggering straight away AND GET_ENTITY_SPEED(vehChop) > 5.0 AND HAS_ENTITY_COLLIDED_WITH_ANYTHING(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: vehChop collided with something so playing shunt anim on Chop") #ENDIF TASK_PLAY_ANIM(chopID, stringChopInVehicleAnimDict, "shunt_from_back") FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) PLAY_CHOP_SOUND("GROWL") iDoingChopInVehicleCollisionAnim = -1 iBarkInVehicleTimer = GET_GAME_TIMER() // B*1801754 Prevent barking immediately after a vehicle shunt ENDIF ELSE IF NOT IS_ENTITY_PLAYING_ANIM(chopID, stringChopInVehicleAnimDict, "shunt_from_back") OR (IS_ENTITY_PLAYING_ANIM(chopID, stringChopInVehicleAnimDict, "shunt_from_back") AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, stringChopInVehicleAnimDict, "shunt_from_back") > 0.98) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Restoring Chop's sit in vehicle anim") #ENDIF TASK_PLAY_ANIM(chopID, stringChopInVehicleAnimDict, "sit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) iDoingChopInVehicleCollisionAnim = GET_GAME_TIMER() iBarkInVehicleTimer = GET_GAME_TIMER() // B*1801754 Prevent barking immediately after a vehicle shunt ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Chop barks to alert Franklin the nearer he gets to a hidden package or weapon pickup. PROC PLAY_ALERT_BARK_DIALOGUE() IF (GET_GAME_TIMER() - iBarkTimer) > iDelayUntilNextBark FLOAT f_distance = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, vChopSitNearClosestPickup) IF f_distance < 10 PLAY_CHOP_SOUND("BARK_SEQ") ELSE PLAY_CHOP_SOUND("BARK") ENDIF //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Making Chop bark when sniffing out hidden package or weapon pickup") #ENDIF iBarkTimer = GET_GAME_TIMER() IF f_distance < 20.0 iDelayUntilNextBark = GET_RANDOM_INT_IN_RANGE(4000, 5000) ELIF f_distance < 50.0 iDelayUntilNextBark = GET_RANDOM_INT_IN_RANGE(5000, 6000) ELSE iDelayUntilNextBark = GET_RANDOM_INT_IN_RANGE(8000, 12000) ENDIF //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: iDelayUntilNextBark = ", iDelayUntilNextBark) #ENDIF IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_BARK_NEAR_PICKUPS)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_BARK_NEAR_PICKUPS)) PRINT_HELP("CHOP_H_HUNT") // "Chop will bark more often when he nears hidden packages and pickups." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_HUNT") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Plays dialogue for Franklin. PROC PLAY_FRANKLIN_DIALOGUE(STRING s_string_to_play, enumSubtitlesState display_subs = DISPLAY_SUBTITLES) ADD_PED_FOR_DIALOGUE(sConversation, 1, PLAYER_PED_ID(), "FRANKLIN") ADD_NON_CRITICAL_STANDARD_CONVERSATION_TO_BUFFER(sConversation, "CHOP_AU", s_string_to_play, CONV_PRIORITY_AMBIENT_MEDIUM, display_subs) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing dialogue ", s_string_to_play) #ENDIF ENDPROC /// PURPOSE: /// Plays Franklin's open/close car door anim. PROC PLAY_FRANKLIN_DOOR_ANIM() TASK_PLAY_ANIM(PLAYER_PED_ID(), "misschop_vehicleenter_exit", stringFranklinInVehicleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_SECONDARY|AF_NOT_INTERRUPTABLE) // Needs to be secondary see B*1467740 iFranklinVehicleDoorAnimTimer = GET_GAME_TIMER() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing Franklin open door anim") #ENDIF ENDPROC /// PURPOSE: /// Returns true when Franklin's open/close door anim reaches the point at which the door should be opened/closed. FUNC BOOL SHOULD_DOOR_OPEN_OR_CLOSE_NOW() IF IS_ENTITY_ALIVE(vehChop) IF (GET_GAME_TIMER() - iFranklinVehicleDoorAnimTimer) > 500 OR IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) OR SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL() RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Make Chop go to the passenger door of the player's car. PROC SEND_CHOP_TO_PASSENGER_DOOR() IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) AND GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), chopID) > 1 TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE),<<2,0,0>>), PEDMOVE_RUN) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Sending Chop close to passenger's door") #ENDIF ENDIF ENDPROC PROC START_CHOP_ENTER_VEHICLE_CAM(BOOL b_start, BOOL b_set_cam_behind_player = TRUE) IF b_start = TRUE IF NOT DOES_CAM_EXIST(camChopEnterVehicle) AND IS_ENTITY_ALIVE(vehChop) VECTOR v_cam_pos, v_lookat_pos_offset INT i_random = GET_RANDOM_INT_IN_RANGE(0, 4) #IF IS_DEBUG_BUILD IF iOverrideChopEnterVehicleCamera > -1 i_random = iOverrideChopEnterVehicleCamera ENDIF #ENDIF IF i_random = 0 v_cam_pos = << 1.11573, -1.40338, 0.555789 >> v_lookat_pos_offset = << 0.5, 0, 0.3 >> ELIF i_random = 1 v_cam_pos = << -1.15872, 1.75252, 0.761228 >> v_lookat_pos_offset = << 0, 0, 0.3 >> ELIF i_random = 2 v_cam_pos = << -1.89975, 0.339287, 0.661881 >> v_lookat_pos_offset = << 0, 0, 0.3 >> ELSE v_cam_pos = << 1.38134, -0.1248, 0.580783 >> v_lookat_pos_offset = << 0, 0, 0.3 >> ENDIF camChopEnterVehicle = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA", TRUE) VECTOR v_seat_bone_pos = GET_WORLD_POSITION_OF_ENTITY_BONE(vehChop, GET_ENTITY_BONE_INDEX_BY_NAME(vehChop, "seat_pside_f")) VECTOR v_seat_bone_pos_offset = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(vehChop, v_seat_bone_pos) VECTOR v_cam_from_car = v_cam_pos + v_seat_bone_pos_offset ATTACH_CAM_TO_ENTITY(camChopEnterVehicle, vehChop, v_cam_from_car) POINT_CAM_AT_ENTITY(camChopEnterVehicle, vehChop, v_seat_bone_pos_offset+v_lookat_pos_offset) SET_CAM_FOV(camChopEnterVehicle, 50.0) SHAKE_CAM(camChopEnterVehicle, "HAND_SHAKE", 0.3) SET_CAM_DOF_PLANES(camChopEnterVehicle, 0.0, 0.0, 100000.0, 100000.0) // Requested in B*1861426 RENDER_SCRIPT_CAMS(TRUE, FALSE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Created Chop enter vehicle camera at position ", i_random) #ENDIF ENDIF ELSE IF DOES_CAM_EXIST(camChopEnterVehicle) IF b_set_cam_behind_player = TRUE SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0) ENDIF RENDER_SCRIPT_CAMS(FALSE, FALSE) DESTROY_ALL_CAMS() ENDIF ENDIF ENDPROC /// PURPOSE: /// In case Chop can't get out of a vehicle using anims. PROC WARP_CHOP_OUT_OF_VEHICLE(VECTOR v_offset, BOOL b_open_door_for_chop) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(chopID) IF IS_ENTITY_ALIVE(vehChop) IF b_open_door_for_chop = TRUE AND NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) AND GET_VEHICLE_DOOR_ANGLE_RATIO(vehChop, SC_DOOR_FRONT_RIGHT) < 0.9 SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Opening door for Chop to warp out") #ENDIF ENDIF IF IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) DETACH_SYNCHRONIZED_SCENE(iSynchSceneChop) ENDIF CLEAR_PED_TASKS_IMMEDIATELY(chopID) SAFE_TELEPORT_ENTITY(chopID, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehChop, v_offset), GET_ENTITY_HEADING(chopID), TRUE, FALSE) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) START_CHOP_ENTER_VEHICLE_CAM(FALSE, FALSE) // B*1552775 Ensure cam is stopped if player is dragged out #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Warped Chop to offset from vehicle ", v_offset) #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELSE IF IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) DETACH_SYNCHRONIZED_SCENE(iSynchSceneChop) ENDIF CLEAR_PED_TASKS_IMMEDIATELY(chopID) SAFE_TELEPORT_ENTITY(chopID, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(), <>), GET_ENTITY_HEADING(chopID), TRUE, FALSE) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) START_CHOP_ENTER_VEHICLE_CAM(FALSE, FALSE) // B*1552775 Ensure cam is stopped if player is dragged out #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Warped Chop to offset from player ", <>) #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ENDIF ENDIF ENDPROC /// PURPOSE: /// Checks if the vehicle Chop is sat in is submerged too much in water. For B*1266256. FUNC BOOL IS_CHOP_VEHICLE_SUBMERGED_IN_WATER() IF IS_ENTITY_ALIVE(vehChop) IF IS_ENTITY_IN_WATER(vehChop) FLOAT f_water_height VECTOR v_chop_vehicle = GET_ENTITY_COORDS(vehChop) IF iChopVehicleInWaterTimer = -1 iChopVehicleInWaterTimer = GET_GAME_TIMER() ENDIF IF GET_WATER_HEIGHT(v_chop_vehicle, f_water_height) IF f_water_height-v_chop_vehicle.z > 1.0 // Chop's vehicle is deep in water //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: v_chop_vehicle.z = ", v_chop_vehicle.z, " f_water_height = ", f_water_height, " Difference = ", f_water_height-v_chop_vehicle.z) #ENDIF RETURN TRUE ELIF (GET_GAME_TIMER() - iChopVehicleInWaterTimer) > 3000 // Chop's vehicle is in shallow water so make him whine occasionally PLAY_CHOP_SOUND("AGITATED") iChopVehicleInWaterTimer = GET_GAME_TIMER() ENDIF ENDIF ELSE iChopVehicleInWaterTimer = -1 ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Gives a ball weapon to Franklin. PROC GIVE_BALL_TO_PLAYER(BOOL b_force_into_hand = FALSE, BOOL bPlayPickupSound = FALSE, BOOL b_equip = FALSE) IF NOT HAS_PED_GOT_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_BALL) OR GET_AMMO_IN_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_BALL) = 0 GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), WEAPONTYPE_BALL, 1, b_force_into_hand, b_equip) HUD_SET_WEAPON_WHEEL_TOP_SLOT(WEAPONTYPE_BALL) // B*1258230 IF bPlayPickupSound = TRUE // B*1701733 - Play sfx when Franklin picks up ball PLAY_SOUND_FRONTEND(iPickupBallSound, "PICKUP_WEAPON_BALL", "HUD_FRONTEND_WEAPONS_PICKUPS_SOUNDSET") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Playing ball pickup sound") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Warps Chop into the front passenger seat. PROC WARP_CHOP_INTO_PLAYER_VEHICLE(BOOL b_reset_cam_behind_vehicle) IF b_reset_cam_behind_vehicle = TRUE SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0) ENDIF SAFE_REMOVE_BLIP(blipChop) SET_ENTITY_INVINCIBLE(chopID, TRUE) // B*1337712 SET_PED_INTO_VEHICLE(chopID, vehChop, VS_FRONT_RIGHT) TASK_PLAY_ANIM(chopID, stringChopInVehicleAnimDict, "sit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) ENDPROC /// PURPOSE: /// Returns true when one of the conditions for Chop warping into the vehicle returns true. FUNC BOOL SHOULD_CHOP_GET_INTO_VEHICLE_NOW() IF IS_ENTITY_ALIVE(vehChop) AND IS_ENTITY_ALIVE(chopID) IF iChopWarpToVehicleTimeLimit = -1 FLOAT f_dist = GET_DISTANCE_BETWEEN_ENTITIES(vehChop, chopID) iChopWarpToVehicleTimeLimit = FLOOR(f_dist * 1000) // B*1492723 - Increase warp failsafe time limit depending on distance IF iChopWarpToVehicleTimeLimit < 5000 iChopWarpToVehicleTimeLimit = 5000 ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: iChopWarpToVehicleTimeLimit = ", iChopWarpToVehicleTimeLimit) #ENDIF ENDIF IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehChop,<<2,0,0>>), FALSE) < 1 OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_ACCELERATE) OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_BRAKE) OR (iChopWarpToVehicleTimer > -1 AND (GET_GAME_TIMER() - iChopWarpToVehicleTimer) > iChopWarpToVehicleTimeLimit) // Safety timer RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC PROC SET_FRANKLIN_SIDE_OF_VEHICLE() VECTOR char_pos, right_pos, left_pos, right_vec, left_vec CONST_INT LEFT_PASSENGER 1 CONST_INT RIGHT_PASSENGER 2 char_pos = GET_ENTITY_COORDS(PLAYER_PED_ID()) right_pos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE), <<2.0, 0.0, 0.0>>) right_vec = right_pos - char_pos left_pos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE), <<-2.0, 0.0, 0.0>>) left_vec = left_pos - char_pos IF VMAG(right_vec) < VMAG(left_vec) // Choose the smaller of the two bPlayerEnteringRightSide = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player entering vehicle from right hand side") #ENDIF ELSE bPlayerEnteringRightSide = FALSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player entering vehicle from left hand side") #ENDIF ENDIF ENDPROC PROC PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ENTER) ENDPROC /// PURPOSE: /// Handles what Chop does if Franklin gets into a vehicle. PROC MANAGE_CHOP_IN_PLAYER_VEHICLE() IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF chopInVehicleStatus > CHOP_VEHICLE_STATUS_FRANKLIN_ENTERING_VEHICLE AND chopInVehicleStatus < CHOP_VEHICLE_STATUS_CHOP_SAT_IN_CAR SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_DisableInVehicleActions, TRUE) // B*1431816 Prevent hotwiring as we have to play anims to open the door for Chop ENDIF IF bPlayerEnteringRightSide = TRUE AND chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_ENTERING_VEHICLE SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_DontCloseVehicleDoor, TRUE) // B*1412946 Prevent Franklin closing the passenger door only to have to reopen it ENDIF ENDIF #IF IS_DEBUG_BUILD IF bOutputCameraToTTY = TRUE AND IS_ENTITY_ALIVE(vehChop) // Work out the position of the camera relative to the front passenger seat bone of vehChop VECTOR v_cam_pos = GET_FINAL_RENDERED_CAM_COORD() VECTOR v_cam_pos_offset = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(vehChop, v_cam_pos) VECTOR v_seat_bone_pos = GET_WORLD_POSITION_OF_ENTITY_BONE(vehChop, GET_ENTITY_BONE_INDEX_BY_NAME(vehChop, "seat_pside_f")) VECTOR v_seat_bone_pos_offset = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(vehChop, v_seat_bone_pos) VECTOR v_cam_from_bone = v_cam_pos_offset - v_seat_bone_pos_offset // Work out the rotation of the camera relative to vehChop VECTOR v_car_rot = GET_ENTITY_ROTATION(vehChop) VECTOR v_cam_rot = GET_FINAL_RENDERED_CAM_ROT() VECTOR v_cam_rot_minus_car = v_car_rot - v_cam_rot // Output to TTY #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: cam pos offset relative to front passenger seat bone = ", v_cam_from_bone, " cam rot relative to car = ", v_cam_rot_minus_car) #ENDIF ENDIF #ENDIF SWITCH chopInVehicleStatus CASE CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player started entering a vehicle") #ENDIF iDoingChopInVehicleCollisionAnim = GET_GAME_TIMER() iChopWarpToVehicleTimer = -1 iChopWarpToVehicleTimeLimit = -1 iBarkInVehicleTimer = GET_GAME_TIMER() SET_FRANKLIN_SIDE_OF_VEHICLE() SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillFlyThroughWindscreen, FALSE) // B*1434346 bPlayerHasBeenInCarWithChop = TRUE chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_ENTERING_VEHICLE ELSE // Player isn't in a vehicle or in the process of doing so - generally when Chop is on a walk it'll mostly be looping here IF vehLayoutHash != LAYOUT_INVALID vehLayoutHash = LAYOUT_INVALID #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Reset vehLayoutHash to LAYOUT_INVALID") #ENDIF ENDIF bPlayedVehicleDialogue = FALSE iDelayUntilNextPickupScan = -1 IF IS_PLAYER_IN_RESTRICTED_INTERIOR() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player entered an interior so stop Chop following") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_RETURN) ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_ENTERING_VEHICLE IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle before Chop could enter it") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELIF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_ENTER() IF GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VS_DRIVER) != PLAYER_PED_ID() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is in a taxi as a passenger") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_RETURN) ELSE IF NOT IS_ENTITY_ALIVE(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player sitting in a vehicle suitable for Chop to enter") #ENDIF vehChop = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) // Grab vehicle handle in case player exits it before Chop SET_LAYOUT_HASH_FOR_CHOP_VEHICLE() SET_CHOPS_DOOR_FOR_CHOP_VEHICLE() ENDIF REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) IF HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) AND IS_ENTITY_ALIVE(vehChop) IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF IF SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL() IF iChopWarpToVehicleTimer = -1 iChopWarpToVehicleTimer = GET_GAME_TIMER() ENDIF IF SHOULD_CHOP_GET_INTO_VEHICLE_NOW() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL returned true so warp Chop in") #ENDIF WARP_CHOP_INTO_PLAYER_VEHICLE(TRUE) chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR ELSE SEND_CHOP_TO_PASSENGER_DOOR() ENDIF ELIF IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), vehChop, VS_FRONT_RIGHT) IF IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) OR GET_VEHICLE_DOOR_ANGLE_RATIO(vehChop, SC_DOOR_FRONT_RIGHT) > 0.9 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Front right door is not present or is already open") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_ENTER_VEHICLE ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Franklin needs to open the front right door for Chop") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Seat entry point isn't clear so warp Chop in") #ENDIF WARP_CHOP_INTO_PLAYER_VEHICLE(TRUE) chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR ENDIF ENDIF ENDIF ELIF IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_FOLLOW() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player sitting in a vehicle suitable for Chop to follow") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_FOLLOWING_BIKE ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player isn't in suitable vehicle for Chop to get into or follow") #ENDIF IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_VEHICLE_NOT_SUITABLE)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_VEHICLE_NOT_SUITABLE)) PRINT_HELP("CHOP_H_NOVEH") // "Chop can only get into suitable cars with an empty front passenger seat." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_NOVEH") #ENDIF ENDIF GIVE_CHOP_TASK(CHOP_TASK_RETURN) ENDIF ELSE IF IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_ENTER() REQUEST_ANIM_DICT("misschop_vehicleenter_exit") // Preload SEND_CHOP_TO_PASSENGER_DOOR() ENDIF IF bPlayedVehicleDialogue = FALSE // See B*1040633 - need to start the dialogue when the player starts to enter, not when he's finished AND IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID())) SET_PED_CONFIG_FLAG(chopID, PCF_UseKinematicModeWhenStationary, FALSE) // B*1402589 Turn kinematic off IF IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID()))) AND NOT IS_PLAYER_IN_CAR_CHOP_CANT_GET_INTO() IF GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID())) = TAXI #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player getting into a taxi so don't play 'get in' dialogue in case he's getting in as a passenger") #ENDIF ELSE IF GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID())) >= 1 AND IS_VEHICLE_SEAT_FREE(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID()), VS_FRONT_RIGHT) // B*1550935 Don't play if front passenger seat is occupied because we'll soon be sending Chop home IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() // B*1553941 Don't allow this to be queued if the is already dialogue going on PLAY_FRANKLIN_DIALOGUE("CHOP_RIDE") ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: IS_ANY_CONVERSATION_ONGOING_OR_QUEUED returned false so not playing CHOP_RIDE dialogue") #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: VS_FRONT_RIGHT isn't free so not playing CHOP_RIDE dialogue") #ENDIF ENDIF ENDIF ELSE IF IS_THIS_MODEL_A_BIKE(GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID()))) OR IS_PLAYER_IN_CAR_CHOP_CANT_GET_INTO() PLAY_FRANKLIN_DIALOGUE("CHOP_FOLLOW") ENDIF ENDIF bPlayedVehicleDialogue = TRUE // Set to true, even if player is getting into a non-car/bike, so it won't check again (flag gets reset when player gets out) ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR) before Chop could enter it") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELSE REQUEST_ANIM_DICT("misschop_vehicleenter_exit") IF HAS_ANIM_DICT_LOADED("misschop_vehicleenter_exit") PLAY_FRANKLIN_DOOR_ANIM() chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR) before Chop could enter it") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELSE IF IS_ENTITY_ALIVE(vehChop) AND SHOULD_DOOR_OPEN_OR_CLOSE_NOW() IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Opening door for Chop to get in") #ENDIF ENDIF i_DoorOpenTimer = GET_GAME_TIMER() iChopWarpToVehicleTimer = GET_GAME_TIMER() chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_ENTER_VEHICLE ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_ENTER_VEHICLE IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_CHOP_ENTER_VEHICLE) before Chop could enter it") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELSE REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) IF IS_ENTITY_ALIVE(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Passenger Door Open Angle: ", GET_VEHICLE_DOOR_ANGLE_RATIO(vehChop, doorChop)) #ENDIF // url:bugstar:2336322 - Make sure door is open for chop to jump in IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) AND GET_VEHICLE_DOOR_ANGLE_RATIO(vehChop, doorChop) < 0.95 SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) i_DoorOpenTimer = GET_GAME_TIMER() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Door not fully open - Opening door") #ENDIF ENDIF IF SHOULD_CHOP_GET_INTO_VEHICLE_NOW() AND GET_GAME_TIMER() >= i_DoorOpenTimer + 300 // url:bugstar:2336322 IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_PLAY_ANIM) AND HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() START_CHOP_ENTER_VEHICLE_CAM(TRUE) CLEAR_PED_TASKS_IMMEDIATELY(chopID) iSynchSceneChop = CREATE_SYNCHRONIZED_SCENE(<<0,0,0>>,<<0,0,0>>) ATTACH_SYNCHRONIZED_SCENE_TO_ENTITY(iSynchSceneChop, vehChop, GET_ENTITY_BONE_INDEX_BY_NAME(vehChop, "seat_pside_f")) TASK_SYNCHRONIZED_SCENE(chopID, iSynchSceneChop, stringChopInVehicleAnimDict, "get_in", INSTANT_BLEND_IN, NORMAL_BLEND_OUT, SYNCED_SCENE_DONT_INTERRUPT) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop getting into vehicle") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_ENTERING_VEHICLE ENDIF ELSE SEND_CHOP_TO_PASSENGER_DOOR() ENDIF ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_ENTERING_VEHICLE PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_CHOP_ENTERING_VEHICLE) before Chop had finished getting inside so he needs to exit") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELSE IF DOES_CAM_EXIST(camChopEnterVehicle) SET_USE_HI_DOF() // Requested in B*1861426 ENDIF REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) IF HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) AND IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) AND GET_SYNCHRONIZED_SCENE_PHASE(iSynchSceneChop) > 0.99 AND IS_ENTITY_ALIVE(vehChop) START_CHOP_ENTER_VEHICLE_CAM(FALSE) WARP_CHOP_INTO_PLAYER_VEHICLE(FALSE) chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_CLOSING_DOOR) before Chop had finished getting inside so he needs to exit") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELSE REQUEST_ANIM_DICT("misschop_vehicleenter_exit") IF HAS_ANIM_DICT_LOADED("misschop_vehicleenter_exit") AND IS_ENTITY_ALIVE(vehChop) IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) AND GET_VEHICLE_DOOR_ANGLE_RATIO(vehChop, SC_DOOR_FRONT_RIGHT) > 0.1 AND NOT SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL() PLAY_FRANKLIN_DOOR_ANIM() ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_CLOSING_DOOR ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_CLOSING_DOOR PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_CLOSING_DOOR) before Franklin had closed door so Chop needs to exit") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELSE IF IS_ENTITY_ALIVE(vehChop) AND SHOULD_DOOR_OPEN_OR_CLOSE_NOW() IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) SET_VEHICLE_DOOR_SHUT(vehChop, doorChop, FALSE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Closing door for Chop") #ENDIF ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is now sat in car") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_SAT_IN_CAR ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_SAT_IN_CAR PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() SAFE_REMOVE_BLIP(blipChop) CLEANUP_BALL(TRUE) IF iRadioStationHowlTimer = -1 iRadioStationHowlTimer = GET_GAME_TIMER() iDelayUntilNextHowl = 7000 ENDIF IF IS_ENTITY_ALIVE(vehChop) IF IS_CHOP_VEHICLE_SUBMERGED_IN_WATER() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: vehChop is in water, so warping Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELIF IS_ENTITY_ON_FIRE(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: vehChop is on fire, so warping Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELIF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF GET_ENTITY_SPEED(vehChop) < 5 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player dived out or was dragged out, vehChop speed is less than 5 so make Chop get out") #ENDIF IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_EXIT_VEHICLE //ELSE commented out due to B*1469648 //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player dived out or was dragged out, vehChop speed is greater than 5 so halting vehChop") #ENDIF //BRING_VEHICLE_TO_HALT(vehChop, 30, 1) // B*1413372 Halt car before Chop warps out ENDIF ELIF IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_VEH_EXIT) IF IS_ENTITY_UPSIDEDOWN(vehChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player vehicle upside down, so warping Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELIF SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: SHOULD_CHOP_WARP_INTO_THIS_VEHICLE_MODEL returned true so waiting until player exited vehicle to disguise warp before warping Chop out") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_WAIT_UNTIL_PLAYER_EXITED ELIF IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), vehChop, VS_FRONT_RIGHT) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player wants to exit vehicle, VS_FRONT_RIGHT is clear so getting Chop out using anims") #ENDIF BRING_VEHICLE_TO_HALT(vehChop, 10.0, 1) IF IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_EXIT_VEHICLE ELSE chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR_FOR_EXIT ENDIF ELIF IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), vehChop, VS_DRIVER) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player wants to exit vehicle, VS_FRONT_RIGHT isn't clear, VS_DRIVER is clear so warping Chop out") #ENDIF BRING_VEHICLE_TO_HALT(vehChop, 10.0, 1) WARP_CHOP_OUT_OF_VEHICLE(<<-2,0,0>>, FALSE) ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player wants to exit vehicle, VS_FRONT_RIGHT and VS_DRIVER aren't clear, so warping Chop out behind") #ENDIF BRING_VEHICLE_TO_HALT(vehChop, 10.0, 1) WARP_CHOP_OUT_OF_VEHICLE(<<0,-4,0>>, FALSE) ENDIF ELSE PERIODICALLY_CHECK_FOR_NEARBY_PICKUPS() PLAY_RADIO_HOWL_DIALOGUE() UPDATE_CHOPS_IN_VEHICLE_ANIMS() IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_VEHICLE_IS_SUITABLE)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_VEHICLE_IS_SUITABLE)) PRINT_HELP("CHOP_H_CAR") // "Chop will follow Franklin into suitable cars with an empty front passenger seat." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_CAR") #ENDIF ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: IS_ENTITY_ALIVE(vehChop) returned false, so warping Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ENDIF BREAK CASE CHOP_VEHICLE_STATUS_WAIT_UNTIL_PLAYER_EXITED PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_LEAVE_ANY_VEHICLE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Make Franklin exit vehicle that Chop will have to warp out of") #ENDIF TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID()) ENDIF IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player now exited vehicle so warp Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR_FOR_EXIT PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_PLAYING_ANIM_OPENING_DOOR_FOR_EXIT) before Franklin had opened door to let Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELSE REQUEST_ANIM_DICT("misschop_vehicleenter_exit") IF HAS_ANIM_DICT_LOADED("misschop_vehicleenter_exit") PLAY_FRANKLIN_DOOR_ANIM() chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR_FOR_EXIT ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR_FOR_EXIT PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player exited vehicle (during CHOP_VEHICLE_STATUS_FRANKLIN_OPENING_DOOR_FOR_EXIT) before Franklin had opened door to let Chop out") #ENDIF WARP_CHOP_OUT_OF_VEHICLE(<<2,0,0>>, TRUE) ELSE IF IS_ENTITY_ALIVE(vehChop) AND SHOULD_DOOR_OPEN_OR_CLOSE_NOW() IF NOT IS_VEHICLE_DOOR_DAMAGED(vehChop, doorChop) SET_VEHICLE_DOOR_OPEN(vehChop, doorChop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Opening door for Chop to get out") #ENDIF ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_EXIT_VEHICLE ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_EXIT_VEHICLE PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() REQUEST_ANIM_DICT(stringChopInVehicleAnimDict) IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_PLAY_ANIM) AND HAS_ANIM_DICT_LOADED(stringChopInVehicleAnimDict) AND IS_ENTITY_ALIVE(vehChop) CLEAR_PED_TASKS_IMMEDIATELY(chopID) iSynchSceneChop = CREATE_SYNCHRONIZED_SCENE(<<0,0,0>>,<<0,0,0>>) ATTACH_SYNCHRONIZED_SCENE_TO_ENTITY(iSynchSceneChop, vehChop, GET_ENTITY_BONE_INDEX_BY_NAME(vehChop, "seat_pside_f")) TASK_SYNCHRONIZED_SCENE(chopID, iSynchSceneChop, stringChopInVehicleAnimDict, "get_out", INSTANT_BLEND_IN, NORMAL_BLEND_OUT, SYNCED_SCENE_TAG_SYNC_OUT|SYNCED_SCENE_ON_ABORT_STOP_SCENE) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop getting out of vehicle") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CHOP_EXITING_VEHICLE ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_EXITING_VEHICLE PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND (GET_GAME_TIMER() - iFranklinVehicleDoorAnimTimer) > 1500 AND NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_LEAVE_ANY_VEHICLE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Franklin finished opening door for Chop so exit, so now make Franklin exit") #ENDIF TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID()) ENDIF IF NOT IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) OR (IS_SYNCHRONIZED_SCENE_RUNNING(iSynchSceneChop) AND GET_SYNCHRONIZED_SCENE_PHASE(iSynchSceneChop) > 0.99) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop finished getting out of vehicle") #ENDIF TASK_GO_STRAIGHT_TO_COORD_RELATIVE_TO_ENTITY(chopID, chopID, <<0, 5, 0>>, PEDMOVEBLENDRATIO_WALK) // B*1550917 Make Chop walk a few steps away to clear the door chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CHOP_FOLLOWING_BIKE IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player got off bike") #ENDIF chopInVehicleStatus = CHOP_VEHICLE_STATUS_CLEANUP ELSE PERIODICALLY_CHECK_FOR_NEARBY_PICKUPS() IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_FOLLOW_ON_BIKE)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_FOLLOW_ON_BIKE)) PRINT_HELP("CHOP_H_BIKE") // "Chop will follow if you get on a bike." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_BIKE") #ENDIF ENDIF ENDIF BREAK CASE CHOP_VEHICLE_STATUS_CLEANUP PREVENT_PLAYER_ENTERING_EXITING_VEHICLE() IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Cleaning up Chop vehicle proc") #ENDIF CREATE_CHOP_BLIP() GIVE_BALL_TO_PLAYER() // B*1165651 - Ensure player has ball if he threw it while driving REMOVE_ANIM_DICT("misschop_vehicleenter_exit") REMOVE_ANIM_DICT(stringChopInVehicleAnimDict) iChopBehaviourNotMovingTimer = GET_GAME_TIMER() // Reset this so Chop doesn't instantly go have a piss SET_LATCH_DOOR_ON_LAST_PLAYER_VEHICLE() SAFE_RELEASE_VEHICLE(vehChop) vehChop = NULL iRadioStationHowlTimer = -1 CLEAR_PED_TASKS(chopID) SET_ENTITY_INVINCIBLE(chopID, FALSE) SET_PED_CONFIG_FLAG(chopID, PCF_UseKinematicModeWhenStationary, TRUE) // B*1402589 Turn kinematic back on SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillFlyThroughWindscreen, TRUE) // B*1434346 GIVE_CHOP_TASK(CHOP_TASK_WALK) ELIF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_LEAVE_ANY_VEHICLE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Reached CHOP_VEHICLE_STATUS_CLEANUP and Franklin was still in vehicle so making him exit it") #ENDIF TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID()) ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Handles Franklin whistling to retrieve Chop if he goes far away. PROC HANDLE_FRANKLIN_WHISTLING_TO_CHOP() IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // B*1122405 - Prevent conflicts with changing radio stations AND NOT IS_ENTITY_IN_WATER(PLAYER_PED_ID()) // B*1151615 - Prevent whistling while in water IF GET_DISTANCE_BETWEEN_PEDS(PLAYER_PED_ID(), chopID) > 10.0 OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WHIS") IF (GET_GAME_TIMER() - iWhistleTimer) > 4000 // Delay before allowing retrigger AND IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_DETONATE) iWhistleTimer = GET_GAME_TIMER() PLAY_PED_AMBIENT_SPEECH(PLAYER_PED_ID(), "CALL_CHOP", SPEECH_PARAMS_FORCE) // B*1076691 B*1583074 IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WHIS") CLEAR_HELP() ENDIF IF eChopTask = CHOP_TASK_FETCH AND iChopStage > 1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player whistled to Chop, but Chop in process of retrieving ball so just continue fetch task") #ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player whistled to Chop") #ENDIF CLEANUP_BALL(FALSE) // B*1381598 Ensure ball is dropped if playing fetch IF eChopTask = CHOP_TASK_WALK GIVE_CHOP_TASK(CHOP_TASK_WALK, FALSE) // B*1861149 Don't clear tasks if repeat whistling ELSE GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDIF ENDIF IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_WHISTLE)) AND NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_WHISTLE)) PRINT_HELP("CHOP_H_WHIS") // "Press ~INPUT_DETONATE~ to whistle to make Chop return to Franklin." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_WHIS") #ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles Chop whining if he's unhappy. PROC HANDLE_CHOP_WHINING_IF_UNHAPPY() IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD AND (GET_GAME_TIMER() - iUnhappyTimer) > iUnhappyDelay // Delay before allowing retrigger iUnhappyTimer = GET_GAME_TIMER() iUnhappyDelay = GET_RANDOM_INT_IN_RANGE(10000, 15000) //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Next iUnhappyDelay = ", iUnhappyDelay) #ENDIF PLAY_CHOP_SOUND("WHINE") ENDIF ENDPROC /// PURPOSE: /// Handles Chop snarling if the player is wanted. PROC HANDLE_CHOP_WHEN_PLAYER_WANTED() IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 IF iNextWantedWhimperTimer = -1 iNextWantedWhimperTimer = GET_GAME_TIMER() iDelayUntilNextWantedWhimper = GET_RANDOM_INT_IN_RANGE(4000, 6000) ENDIF IF (GET_GAME_TIMER() - iNextWantedWhimperTimer) > iDelayUntilNextWantedWhimper PLAY_CHOP_SOUND("SNARL") iNextWantedWhimperTimer = -1 ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles Chop pissing and shitting when following the player but idle. PROC HANDLE_CHOP_NOT_MOVING() IF GET_CHOP_BEHAVIOUR_FROM_APP() != CHOP_BEHAVIOUR_GOOD AND (GET_GAME_TIMER() - iChopBehaviourNotMovingTimer) > 10000 AND NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE AND wThrownWeapon != WEAPONTYPE_BALL // Prevent Chop taking a piss/shit when the player wants to play fetch AND COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(PLAYER_PED_ID(), GET_ENTITY_COORDS(PLAYER_PED_ID()), CHOP_ATTACK_RANGE) = 0 // B*1556780 Don't start a piss/shit task if there are peds in combat with Franklin AND COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(chopID, GET_ENTITY_COORDS(chopID), CHOP_ATTACK_RANGE) = 0 // B*1556780 Don't start a piss/shit task if there are peds in combat with Franklin REQUEST_PTFX_ASSET() IF HAS_PTFX_ASSET_LOADED() VECTOR v_new_chop_position = GET_ENTITY_COORDS(chopID) IF GET_DISTANCE_BETWEEN_COORDS(v_new_chop_position, vLastChopBehaviourPosition, FALSE) < 1 IF GET_DISTANCE_BETWEEN_COORDS(v_new_chop_position, vChopLastPissPosition, FALSE) > 20 SAFE_RELEASE_OBJECT(oLamppost) oLamppost = GET_CLOSEST_OBJECT_OF_TYPE(v_new_chop_position, 10, prop_streetlight_01) IF DOES_ENTITY_EXIST(oLamppost) vChopLastPissPosition = GET_ENTITY_COORDS(oLamppost) GIVE_CHOP_TASK(CHOP_TASK_PISS) ENDIF ELIF GET_DISTANCE_BETWEEN_COORDS(v_new_chop_position, vChopLastShitPosition, FALSE) > 20 vChopLastShitPosition = v_new_chop_position GIVE_CHOP_TASK(CHOP_TASK_SHIT) ENDIF ENDIF vLastChopBehaviourPosition = GET_ENTITY_COORDS(chopID) iChopBehaviourNotMovingTimer = GET_GAME_TIMER() ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles Chop if the player enters a shop. PROC HANDLE_PLAYER_ENTERING_SHOPS() IF IS_PLAYER_IN_ANY_SHOP() AND NOT IS_PLAYER_IN_SHOP_OF_TYPE(SHOP_TYPE_CARMOD) // B*1100720 Leave Chop inside the player car if in a car mod shop IF IS_ENTITY_ALIVE(chopID) AND chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE AND IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player has entered a shop") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_SIT_OUTSIDE_SHOP) ENDIF ENDPROC /// PURPOSE: /// Handles Franklin playing fetch with Chop. PROC HANDLE_FRANKLIN_THROWING_BALL() IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_PLAY_FETCH)) AND NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_PLAY_FETCH)) PRINT_HELP("CHOP_H_BALL") // When taking Chop for a walk Franklin can play fetch using the ball in the inventory. #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_BALL") #ENDIF ENDIF IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) AND IS_ENTITY_ALIVE(chopID) AND NOT IS_PED_IN_ANY_VEHICLE(chopID, TRUE) GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), wThrownWeapon) IF wThrownWeapon = WEAPONTYPE_BALL OR wThrownWeapon = WEAPONTYPE_GRENADE OR wThrownWeapon = WEAPONTYPE_SMOKEGRENADE OR wThrownWeapon = WEAPONTYPE_STICKYBOMB OR wThrownWeapon = WEAPONTYPE_MOLOTOV OR wThrownWeapon = WEAPONTYPE_FLARE IF IS_PED_SHOOTING(PLAYER_PED_ID()) GIVE_CHOP_TASK(CHOP_TASK_FETCH) ELSE IF (GET_GAME_TIMER() - iChopFetchExcitedTimer) > CHOP_REPEAT_EXCITED_DELAY AND GET_ENTITY_SPEED(chopID) < 1 // Don't play excited barking if Chop is moving, only when stationary AND GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), chopID) < 5 REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@enter") REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@idle_a") REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@exit") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@enter") AND HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@idle_a") AND HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@exit") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@enter", "enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@idle_a", "idle_a", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@exit", "exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) iChopFetchExcitedTimer = GET_GAME_TIMER() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop excited to be playing fetch") #ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Plays a sitting anim on Chop, used with CHOP_TASK_WAIT_PLAY_ANIM. PROC PLAY_SITTING_ANIM_ON_CHOP() INT i_random = GET_RANDOM_INT_IN_RANGE(0, 6) IF i_random = 0 TASK_PLAY_ANIM(chopID, sAnimDict[1] , "idle_a") sAnimPlaying = "idle_a" ELIF i_random = 1 TASK_PLAY_ANIM(chopID, sAnimDict[1] , "idle_c") sAnimPlaying = "idle_c" ELSE TASK_PLAY_ANIM(chopID, sAnimDict[1] , "idle_b") sAnimPlaying = "idle_b" ENDIF ENDPROC /// PURPOSE: /// Makes Chop randomly wander around near his kennel then play idle anims. PROC MAKE_CHOP_WANDER_NEAR_KENNEL() IF bChopWanderingBetweenPositions = FALSE INT i_random_pos = GET_RANDOM_INT_IN_RANGE(0, NUM_CHOP_WANDER_POSITIONS) IF NOT IS_ENTITY_AT_COORD(chopID, vChopWanderPositions[i_random_pos], <<2, 2, LOCATE_SIZE_ON_FOOT_ONLY>>) AND NOT IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vChopWanderPositions[i_random_pos], <<2, 2, LOCATE_SIZE_ON_FOOT_ONLY>>) TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, vChopWanderPositions[i_random_pos], PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_BEFORE_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_SUPPRESS_EXACT_STOP) bChopWanderingBetweenPositions = TRUE ENDIF ELSE IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) INT i_dump_threshold IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD i_dump_threshold = 15 // Percentage chance of Chop doing a shit ELIF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_MEDIUM i_dump_threshold = 10 // Percentage chance of Chop doing a shit ELSE i_dump_threshold = -1 // Never let Chop do a shit if his behaviour is good ENDIF INT i_random = GET_RANDOM_INT_IN_RANGE(0, 100) IF i_random < i_dump_threshold AND bChopDidShit = FALSE bChopDidShit = TRUE // Prevents Chop randomly doing two shits in succession at the same place GIVE_CHOP_TASK(CHOP_TASK_SHIT) ELIF i_random < 50 bPlayWaitStandAnim = TRUE sAnimDict[0] = "creatures@rottweiler@amb@world_dog_barking@enter" sAnimDict[1] = "creatures@rottweiler@amb@world_dog_barking@base" sAnimDict[2] = "creatures@rottweiler@amb@world_dog_barking@exit" GIVE_CHOP_TASK(CHOP_TASK_WAIT_PLAY_ANIM) ELSE bPlayWaitStandAnim = FALSE sAnimDict[0] = "creatures@rottweiler@amb@world_dog_sitting@enter" sAnimDict[1] = "creatures@rottweiler@amb@world_dog_sitting@idle_a" sAnimDict[2] = "creatures@rottweiler@amb@world_dog_sitting@exit" GIVE_CHOP_TASK(CHOP_TASK_WAIT_PLAY_ANIM) ENDIF ENDIF ENDIF ENDPROC FUNC STRING DETERMINE_CHOP_INDICATE_ANIM() STRING string_to_use IF IS_ENTITY_ALIVE(chopID) VECTOR v_chop = GET_ENTITY_COORDS(chopID) IF v_chop.z + 1 < vClosestPickup.z string_to_use = "indicate_high" #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is more than 1m below the pickup") #ENDIF ELIF v_chop.z - 1 > vClosestPickup.z string_to_use = "indicate_low" #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is more than 1m above the pickup") #ENDIF ELSE string_to_use = "indicate_ahead" #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is roughly on same level as the pickup") #ENDIF ENDIF ENDIF RETURN string_to_use ENDFUNC /// PURPOSE: /// Makes Chop face the pickup when he's near to it then play an idle. PROC MAKE_CHOP_FACE_PICKUP() IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PERFORM_SEQUENCE) REQUEST_ANIM_DICT("creatures@rottweiler@indication@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@indication@") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_COORD(NULL, vClosestPickup) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@indication@", DETERMINE_CHOP_INDICATE_ANIM(), NORMAL_BLEND_IN, SLOW_BLEND_OUT, -1, AF_LOOPING) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop sitting at ", vChopSitNearClosestPickup, " facing pickup at ", vClosestPickup) #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles sending a query to the pickup controller. FUNC BOOL CHECK_PICKUP_QUERY_DOES_PICKUP_EXIST(QUERY_TYPE query_pickup_type) IF IS_QUERY_RESULT_INACTIVE() INIT_PICKUP_QUERY_REQUEST(query_pickup_type, iClosestPickup) ENDIF IF HAS_RETURNED_QUERY_RESULT() IF HAS_QUERIED_PICKUP_BEEN_COLLECTED() END_PICKUP_QUERY_REQUEST() RETURN FALSE ENDIF END_PICKUP_QUERY_REQUEST() ENDIF RETURN TRUE // Either pickup still exists or still waiting for the query to return a result ENDFUNC /// PURPOSE: /// Checks if the current pickup that Chop is sniffing out still exists. FUNC BOOL DOES_CHOP_CURRENT_PICKUP_EXIST() SWITCH chopCurrentPickupType CASE CHOP_CURRENT_PICKUP_TYPE_WEAPON IF NOT CHECK_PICKUP_QUERY_DOES_PICKUP_EXIST(PC_QUERY_TYPE_WEAPON) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1", DO_NOT_DISPLAY_SUBTITLES) RETURN FALSE ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_HEALTH IF NOT CHECK_PICKUP_QUERY_DOES_PICKUP_EXIST(PC_QUERY_TYPE_HEALTH) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1", DO_NOT_DISPLAY_SUBTITLES) RETURN FALSE ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_ARMOUR IF NOT CHECK_PICKUP_QUERY_DOES_PICKUP_EXIST(PC_QUERY_TYPE_ARMOUR) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1", DO_NOT_DISPLAY_SUBTITLES) RETURN FALSE ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_LETTER IF HAS_LETTER_SCRAP_BEEN_COLLECTED(iClosestPickup) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1", DO_NOT_DISPLAY_SUBTITLES) RETURN FALSE ENDIF BREAK CASE CHOP_CURRENT_PICKUP_TYPE_SPACESHIP IF HAS_SPACESHIP_PART_BEEN_COLLECTED(iClosestPickup) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1", DO_NOT_DISPLAY_SUBTITLES) RETURN FALSE ENDIF BREAK ENDSWITCH RETURN TRUE ENDFUNC /// PURPOSE: /// Returns TRUE if Chop should exit his kennel now. FUNC BOOL SHOULD_CHOP_EXIT_KENNEL() IF IS_PED_IN_TRICK_AREA(PLAYER_PED_ID()) IF (GET_GAME_TIMER() - iChopInKennelTimer) > iChopExitKennelTime // Else wait a random period of time #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop should exit kennel now - timer expired") #ENDIF RETURN TRUE ENDIF IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), sChopData.vKennelCoords) < 8 // Player is very close so just get Chop to exit immediately #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop should exit kennel now - closer than 8 metres") #ENDIF PLAY_FRANKLIN_DIALOGUE("CHOP_KENNEL") RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Give Chop a task after performing a trick. See B*1092487 - Chop should only follow player if he was on a walk prior to being given a trick. PROC CHOP_FINISHED_TRICK() iChopBehaviourNotMovingTimer = GET_GAME_TIMER() IF bPlayerChoseToWalkChop = FALSE GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELSE GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDPROC /// PURPOSE: /// Either Chop isn't close enough to anything or the pathfinding has failed. PROC CHOP_CANT_FIND_ANYTHING_NEARBY() VECTOR v_chop = GET_ENTITY_COORDS(chopID) DUMMY_REFERENCE_VECTOR(v_chop) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop couldn't find anything near ", v_chop) #ENDIF PLAY_CHOP_SOUND("WHINE") PLAY_FRANKLIN_DIALOGUE("CHOP_NONEAR") CHOP_FINISHED_TRICK() ENDPROC /// PURPOSE: /// Handles targetting Chop. PROC ALLOW_PLAYER_TO_TARGET_CHOP(BOOL b_allow) WEAPON_TYPE current_player_weapon GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), current_player_weapon) IF bIsChopTargettable = TRUE AND current_player_weapon != WEAPONTYPE_UNARMED // Scan for the player equiping a weapon b_allow = FALSE ENDIF IF b_allow = TRUE IF bIsChopTargettable = FALSE AND current_player_weapon = WEAPONTYPE_UNARMED SET_PED_CAN_BE_TARGETTED(chopID, TRUE) SET_ENTITY_IS_TARGET_PRIORITY(chopID, TRUE) SET_ALLOW_LOCKON_TO_PED_IF_FRIENDLY(chopID, TRUE) SET_USE_CAMERA_HEADING_FOR_DESIRED_DIRECTION_LOCK_ON_TEST(chopID, TRUE) bIsChopTargettable = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player allowed to target Chop") #ENDIF ENDIF ELSE IF bIsChopTargettable = TRUE SET_PED_CAN_BE_TARGETTED(chopID, FALSE) SET_ENTITY_IS_TARGET_PRIORITY(chopID, FALSE) SET_ALLOW_LOCKON_TO_PED_IF_FRIENDLY(chopID, FALSE) bIsChopTargettable = FALSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player prevented targeting Chop") #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns true if Chop has reached the ball. FUNC BOOL HAS_CHOP_REACHED_BALL() IF GET_DISTANCE_BETWEEN_ENTITIES(chopID, eBall) < DEFAULT_SEEK_RADIUS+0.25 VECTOR v_current_ball_position = GET_ENTITY_COORDS(eBall) FLOAT f_current_ball_ground_z IF GET_GROUND_Z_FOR_3D_COORD(<>, f_current_ball_ground_z) IF ABSF(v_current_ball_position.z-f_current_ball_ground_z) < 0.1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Ball is on the floor and Chop is near it") #ENDIF RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Returns true if Chop has finished his anim task sequence or been damaged while doing it. FUNC BOOL HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK OR IS_PED_RAGDOLL(chopID) // B*1554726 If someone kicks Chop to the ground OR HAS_ENTITY_BEEN_DAMAGED_BY_ANY_PED(chopID) // B*1554726 If someone kicks Chop to the ground CLEAR_PED_LAST_WEAPON_DAMAGE(chopID) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Process Chop's primary tasks such as wait, walk, and return. PROC PROCESS_PRIMARY_TASKS() NAVMESH_ROUTE_RESULT nrr_chop_route INT i_chop_route FLOAT f_chop_route VECTOR v_offset SWITCH eChopTask CASE CHOP_TASK_SPAWNED_IN_KENNEL IF iChopStage = 0 REQUEST_ANIM_DICT("creatures@rottweiler@amb@sleep_in_kennel@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@sleep_in_kennel@") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Putting Chop in kennel") #ENDIF IF IS_ENTITY_ALIVE(chopID) TASK_PLAY_ANIM(chopID, "creatures@rottweiler@amb@sleep_in_kennel@", "sleep_in_kennel", INSTANT_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) SAFE_TELEPORT_ENTITY(chopID, sChopData.vKennelCoords, sChopData.fKennelHeading) ENDIF iChopInKennelTimer = GET_GAME_TIMER() iChopStage++ ENDIF ELIF iChopStage = 1 IF SHOULD_CHOP_EXIT_KENNEL() REQUEST_ANIM_DICT("creatures@rottweiler@amb@sleep_in_kennel@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@sleep_in_kennel@") AND IS_ENTITY_ALIVE(chopID) TASK_PLAY_ANIM(chopID, "creatures@rottweiler@amb@sleep_in_kennel@", "exit_kennel", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) PLAY_CHOP_SOUND("WHINE") iChopStage++ ENDIF ENDIF ELIF iChopStage = 2 IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_PLAY_ANIM) = FINISHED_TASK REMOVE_ANIM_DICT("creatures@rottweiler@amb@sleep_in_kennel@") PLAY_CHOP_SOUND("PLAYFUL") GIVE_CHOP_TASK(CHOP_TASK_WAIT) ENDIF ENDIF BREAK CASE CHOP_TASK_WAIT IF bChopGreetedFranklinDone = FALSE AND IS_PED_IN_TRICK_AREA(PLAYER_PED_ID()) GIVE_CHOP_TASK(CHOP_TASK_GREET_FRANKLIN) ELSE HANDLE_CHOP_WHINING_IF_UNHAPPY() CHECK_FOR_PLAYER_BULLET_NEAR_CHOP() MAKE_CHOP_WANDER_NEAR_KENNEL() ENDIF BREAK CASE CHOP_TASK_WAIT_PLAY_ANIM // Handles playing anims when Chop is mooching near his kennel HANDLE_CHOP_WHINING_IF_UNHAPPY() CHECK_FOR_PLAYER_BULLET_NEAR_CHOP() IF iChopStage = 0 // Play enter anim REQUEST_ANIM_DICT(sAnimDict[0]) REQUEST_ANIM_DICT(sAnimDict[1]) REQUEST_ANIM_DICT(sAnimDict[2]) IF HAS_ANIM_DICT_LOADED(sAnimDict[0]) AND HAS_ANIM_DICT_LOADED(sAnimDict[1]) AND HAS_ANIM_DICT_LOADED(sAnimDict[2]) TASK_PLAY_ANIM(chopID, sAnimDict[0], "enter") iChopStage++ ENDIF ELIF iChopStage = 1 // Play loop anim IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PLAY_ANIM) OR (IS_ENTITY_PLAYING_ANIM(chopID, sAnimDict[0], "enter") AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, sAnimDict[0], "enter") > 0.98) // Enter anim is almost finished OR (IS_ENTITY_PLAYING_ANIM(chopID, sAnimDict[1], sAnimPlaying) AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, sAnimDict[1], sAnimPlaying) > 0.98) // Loop anim is almost finished IF eNextChopTask = CHOP_TASK_NONE IF bPlayWaitStandAnim = TRUE TASK_PLAY_ANIM(chopID, sAnimDict[1], "base") sAnimPlaying = "base" iChopStage++ ELSE PLAY_SITTING_ANIM_ON_CHOP() IF GET_RANDOM_INT_IN_RANGE(0, 4) = 0 // 75% of the time keep playing more sitting anims iChopStage++ ENDIF ENDIF ELSE // Player has given an order so we need to exit IF eNextChopTask != CHOP_TASK_SNIFF PLAY_FRANKLIN_DIALOGUE("CHOP_WAIT") ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Not playing CHOP_WAIT") #ENDIF // See B*1516024 ENDIF TASK_PLAY_ANIM(chopID, sAnimDict[2], "exit") iChopStage = 3 ENDIF ENDIF ELIF iChopStage = 2 // Play exit anim IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PLAY_ANIM) OR (IS_ENTITY_PLAYING_ANIM(chopID, sAnimDict[1], sAnimPlaying) AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, sAnimDict[1], sAnimPlaying) > 0.98) // Loop anim is almost finished TASK_PLAY_ANIM(chopID, sAnimDict[2], "exit") iChopStage++ ENDIF ELIF iChopStage = 3 // Cleanup play anim state IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PLAY_ANIM) bChopDidShit = FALSE IF eNextChopTask = CHOP_TASK_NONE GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELSE // Player has given Chop a task while these anims have been playing.. GIVE_CHOP_TASK(eNextChopTask) // .. so set the stored task as Chop's new task ENDIF ENDIF ENDIF BREAK CASE CHOP_TASK_GREET_FRANKLIN // Makes Chop greet Franklin. See B*1051650. CHECK_FOR_PLAYER_BULLET_NEAR_CHOP() IF iChopStage = 0 REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@enter") REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@idle_a") REQUEST_ANIM_DICT("creatures@rottweiler@amb@world_dog_barking@exit") TASK_GO_TO_ENTITY(chopID, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 3, PEDMOVEBLENDRATIO_WALK) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop sent to greet Franklin") #ENDIF iChopStage++ ELIF iChopStage = 1 IF eNextChopTask = CHOP_TASK_NONE IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_GO_TO_ENTITY) IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@enter") AND HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@idle_a") AND HAS_ANIM_DICT_LOADED("creatures@rottweiler@amb@world_dog_barking@exit") OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@enter", "enter") TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@idle_a", "idle_a") TASK_PLAY_ANIM(NULL, "creatures@rottweiler@amb@world_dog_barking@exit", "exit") CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop now greeting Franklin") #ENDIF iChopStage++ ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player gave Chop a task before Chop reached Franklin to greet him") #ENDIF GIVE_CHOP_TASK(eNextChopTask) ENDIF ELIF iChopStage = 2 IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() bChopGreetedFranklinDone = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop greeting Franklin has finished") #ENDIF IF eNextChopTask = CHOP_TASK_NONE GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELSE // Player has given Chop a task while these anims have been playing.. GIVE_CHOP_TASK(eNextChopTask) // .. so set the stored task as Chop's new task ENDIF ENDIF ENDIF BREAK CASE CHOP_TASK_WALK HANDLE_FRANKLIN_WHISTLING_TO_CHOP() IF iChopStage = 0 IF IS_ENTITY_ALIVE(chopID) AND NOT IS_PED_IN_ANY_VEHICLE(chopID) // If Chop is spawned in vehicle from switch scene don't clear his anim AND NOT IS_PED_IN_GROUP(chopID) // B*1861149 Don't clear tasks if repeat whistling CLEAR_PED_TASKS(chopID) ENDIF PUT_CHOP_IN_PLAYER_GROUP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop told to follow Franklin") #ENDIF GIVE_BALL_TO_PLAYER() SUPPRESS_OTHER_CREATURES(TRUE) iNextWantedWhimperTimer = -1 iClosestPickupTimer = GET_GAME_TIMER() iChopBehaviourNotMovingTimer = GET_GAME_TIMER() iChopFetchExcitedTimer = GET_GAME_TIMER() - CHOP_REPEAT_EXCITED_DELAY // Allow playing the excited fetch bark straight away vLastChopBehaviourPosition = GET_ENTITY_COORDS(chopID) REQUEST_ANIM_DICT("creatures@rottweiler@melee@streamed_taunts@") // B*1555787 Ensure taunts are preloaded iChopStage++ ELIF iChopStage = 1 // Chop is following Franklin around SCAN_FOR_NEAREST_PICKUP() MANAGE_CHOP_IN_PLAYER_VEHICLE() HANDLE_CHOP_WHEN_PLAYER_WANTED() HANDLE_PLAYER_ENTERING_SHOPS() HANDLE_FRANKLIN_THROWING_BALL() HANDLE_CHOP_NOT_MOVING() HANDLE_CHOP_WHINING_IF_UNHAPPY() ENDIF BREAK CASE CHOP_TASK_RETURN IF iChopStage = 0 PLAY_CHOP_SOUND("WHINE") PLAY_FRANKLIN_DIALOGUE("CHOP_GOHOME") CLEANUP_BALL(FALSE) REMOVE_ANIM_DICT("creatures@rottweiler@melee@streamed_taunts@") IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND HAS_PED_GOT_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_BALL) REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), WEAPONTYPE_BALL) ENDIF IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) // B*1891517 remove Chop from player group to prevent the group leader code warping Chop nearby if the player gets teleported elsewhere (such as by the taxi script) ENDIF IF IS_PED_IN_TRICK_AREA(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop already near kennel") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELIF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, sChopData.vSpawnCoords) < 100 CLEAR_PED_TASKS(chopID) IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, sChopData.vSpawnCoords) < 20 // Walk back if Chop is close to his kennel (rather than sprinting if he's only a few metres away etc) TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, sChopData.vSpawnCoords, PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_BEFORE_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_NEVER_ENTER_WATER, sChopData.fSpawnHeading) ELSE TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, sChopData.vSpawnCoords, PEDMOVEBLENDRATIO_SPRINT, 60000, DEFAULT_NAVMESH_RADIUS, ENAV_NEVER_ENTER_WATER, sChopData.fSpawnHeading) ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop told to return to his kennel") #ENDIF iChopStage++ ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop is too far away to return to his kennel") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_WANDER) ENDIF ELIF iChopStage = 1 IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) = FINISHED_TASK IF IS_ENTITY_AT_COORD(chopID, sChopData.vSpawnCoords, <<2.5, 2.5, LOCATE_SIZE_ON_FOOT_ONLY>>) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop has returned back to his kennel") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop's return task has finished but he's not at his kennel, so need to reapply the return task") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_RETURN) ENDIF ENDIF ENDIF BREAK CASE CHOP_TASK_WANDER IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_SMART_FLEE_PED) TASK_SMART_FLEE_PED(chopID, PLAYER_PED_ID(), 100, -1) // B*1109931 - Chop can't use a wander task #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop told to flee") #ENDIF ENDIF BREAK CASE CHOP_TASK_SNIFF IF iChopStage = 0 IF HAS_PICKUP_SCAN_BEEN_COMPLETED() IF IS_CHOP_WITHIN_RANGE_OF_NEAREST_PICKUP() IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF CLEAR_PED_TASKS(chopID) iBarkTimer = GET_GAME_TIMER() iDelayUntilNextBark = 1000 iNavmeshAttempts = 0 iChopReachedPickupTimer = -1 END_PICKUP_QUERY_REQUEST() iChopStage++ ELSE CHOP_CANT_FIND_ANYTHING_NEARBY() ENDIF ENDIF ELIF iChopStage = 1 IF NOT DOES_CHOP_CURRENT_PICKUP_EXIST() OR (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IS_PLAYER_IN_SUITABLE_VEHICLE_FOR_CHOP_TO_FOLLOW()) OR (iChopReachedPickupTimer > -1 AND (GET_GAME_TIMER() - iChopReachedPickupTimer) > 30000) // B*1226501 - Don't make Chop indefinitely wait at the pickup OR IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vClosestPickup, <<1, 1, 1>>) // B*1226501 - Player has reached the pickup but can't pick it up (already full) iChopStage++ ELSE IF IS_ENTITY_AT_COORD(chopID, vChopSitNearClosestPickup, <<3, 3, LOCATE_SIZE_ON_FOOT_ONLY>>) MAKE_CHOP_FACE_PICKUP() IF iChopReachedPickupTimer = -1 iChopReachedPickupTimer = GET_GAME_TIMER() ENDIF ELSE PLAY_ALERT_BARK_DIALOGUE() IF IsPedPerformingTask(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) nrr_chop_route = GET_NAVMESH_ROUTE_DISTANCE_REMAINING(chopID, f_chop_route, i_chop_route) IF nrr_chop_route = NAVMESHROUTE_ROUTE_NOT_FOUND iNavmeshAttempts++ ELIF nrr_chop_route = NAVMESHROUTE_ROUTE_FOUND IF iNavmeshAttempts <> 0 iNavmeshAttempts = 0 // Reset back to 0 so all the attempts don't get used up if the AI has to recompute the route, see B*1226729 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: nrr_chop_route = NAVMESHROUTE_ROUTE_FOUND so reset iNavmeshAttempts to 0") #ENDIF ENDIF ENDIF #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Navmesh task = ", nrr_chop_route, " iNavmeshAttempts = ", iNavmeshAttempts, " dist = ", f_chop_route, " last section = ", i_chop_route) #ENDIF IF iNavmeshAttempts > 9 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: nrr_chop_route = NAVMESHROUTE_ROUTE_NOT_FOUND so do GIVE_CHOP_TASK(CHOP_TASK_WALK)") #ENDIF CHOP_CANT_FIND_ANYTHING_NEARBY() ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop sniffing out a hidden package or weapon pickup") #ENDIF TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, vChopSitNearClosestPickup, PEDMOVE_SPRINT, DEFAULT_TIME_NEVER_WARP, 3.0, ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED|ENAV_NEVER_ENTER_WATER) ENDIF ENDIF ENDIF ELIF iChopStage = 2 CLEAR_PED_TASKS(chopID) REMOVE_ANIM_DICT("creatures@rottweiler@indication@") GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF HANDLE_FRANKLIN_WHISTLING_TO_CHOP() BREAK CASE CHOP_TASK_ATTACK IF iChopStage = 0 IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(chopID, FALSE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Starting CHOP_TASK_ATTACK") #ENDIF iChopStage++ ELIF iChopStage = 1 IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF (NOT IsPedPerformingTask(chopID, SCRIPT_TASK_COMBAT) AND NOT IS_PED_IN_COMBAT(chopID)) OR IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) // B*1088354 Player has got into a vehicle that Chop can get into, call off Chop #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Ending CHOP_TASK_ATTACK") #ENDIF iChopBehaviourNotMovingTimer = GET_GAME_TIMER() GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDIF ENDIF HANDLE_FRANKLIN_WHISTLING_TO_CHOP() BREAK CASE CHOP_TASK_BEG IF iChopStage = 0 REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) IF NOT IS_PED_FACING_PED(chopID, PLAYER_PED_ID(), 10) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) ENDIF TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "beg_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "beg_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "beg_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "beg_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) PLAY_CHOP_SOUND("PLAYFUL") iChopStage++ #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop performing a beg task") #ENDIF ENDIF ELIF iChopStage = 1 IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1") REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") CHOP_FINISHED_TRICK() ENDIF ENDIF BREAK CASE CHOP_TASK_SIT IF iChopStage = 0 REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) IF NOT IS_PED_FACING_PED(chopID, PLAYER_PED_ID(), 10) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) ENDIF TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) PLAY_CHOP_SOUND("PLAYFUL") iChopStage++ #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop performing a sit task") #ENDIF ENDIF ELIF iChopStage = 1 IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1") REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") CHOP_FINISHED_TRICK() ENDIF ENDIF BREAK CASE CHOP_TASK_PAW IF iChopStage = 0 REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) IF NOT IS_PED_FACING_PED(chopID, PLAYER_PED_ID(), 10) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) ENDIF TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "paw_right_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "paw_right_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "paw_right_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "paw_right_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) PLAY_CHOP_SOUND("PLAYFUL") iChopStage++ #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop performing a paw task") #ENDIF ENDIF ELIF iChopStage = 1 IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1") REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") CHOP_FINISHED_TRICK() ENDIF ENDIF BREAK CASE CHOP_TASK_PET // Disable everything except aiming, in order to keep the menu onscreen. Massive list ahoy... DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_UP_ONLY) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_LEFT_ONLY) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_RIGHT_ONLY) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_DOWN_ONLY) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_UD) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MOVE_LR) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_JUMP) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_DUCK) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_COVER) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK_HEAVY) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK_LIGHT) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK1) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK2) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_BLOCK) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK2) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_NEXT_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_PREV_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SPRINT) IF iChopStage = 0 // Turn Franklin to face Chop #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop performing a pet task") #ENDIF REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(PLAYER_PED_ID()) TASK_TURN_PED_TO_FACE_ENTITY(PLAYER_PED_ID(), chopID) iChopStage++ ELIF iChopStage = 1 // Move Chop into position and turn him to face Franklin IF GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_TURN_PED_TO_FACE_ENTITY) = FINISHED_TASK CLEAR_PED_TASKS(chopID) v_offset = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(),<<0,1,1>>) GET_GROUND_Z_FOR_3D_COORD(v_offset, v_offset.z) IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, v_offset, FALSE) > 0.3 TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, v_offset, PEDMOVE_WALK, 5000) ENDIF iChopStage++ ENDIF ELIF iChopStage = 2 // Check they're still facing each other IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) = FINISHED_TASK OR GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, v_offset, FALSE) < 0.3 IF NOT IS_PED_FACING_PED(chopID, PLAYER_PED_ID(), 15) TASK_TURN_PED_TO_FACE_ENTITY(chopID, PLAYER_PED_ID()) bChopAlreadyFacingFranklin = FALSE ELSE bChopAlreadyFacingFranklin = TRUE ENDIF IF NOT IS_PED_FACING_PED(PLAYER_PED_ID(), chopID, 15) TASK_TURN_PED_TO_FACE_ENTITY(PLAYER_PED_ID(), chopID) bFranklinAlreadyFacingChop = FALSE ELSE bFranklinAlreadyFacingChop = TRUE ENDIF iChopStage++ ENDIF ELIF iChopStage = 3 // Play their petting anims REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF (bChopAlreadyFacingFranklin = TRUE OR GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_TURN_PED_TO_FACE_ENTITY) = FINISHED_TASK) AND (bFranklinAlreadyFacingChop = TRUE OR GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_TURN_PED_TO_FACE_ENTITY) = FINISHED_TASK) AND HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") TASK_PLAY_ANIM(chopID, "creatures@rottweiler@tricks@", "petting_chop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE) TASK_PLAY_ANIM(PLAYER_PED_ID(), "creatures@rottweiler@tricks@", "petting_franklin", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE) PLAY_CHOP_SOUND("PLAYFUL") iChopStage++ ENDIF ELIF iChopStage = 4 // Petting finished IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_PLAY_ANIM) = FINISHED_TASK PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1") REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") CHOP_FINISHED_TRICK() ENDIF ENDIF BREAK CASE CHOP_TASK_SIT_OUTSIDE_SHOP IF iChopStage = 0 IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@tricks@", "sit_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET|AF_LOOPING) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) iChopStage++ ENDIF ELIF iChopStage = 1 IF NOT IS_PLAYER_IN_ANY_SHOP() REQUEST_ANIM_DICT("creatures@rottweiler@tricks@") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@tricks@") CLEAR_PED_TASKS(chopID) TASK_PLAY_ANIM(chopID, "creatures@rottweiler@tricks@", "sit_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) PLAY_FRANKLIN_DIALOGUE("CHOP_WALK") iChopStage++ ENDIF ENDIF ELIF iChopStage = 2 IF GET_SCRIPT_TASK_STATUS(chopID, SCRIPT_TASK_PLAY_ANIM) = FINISHED_TASK REMOVE_ANIM_DICT("creatures@rottweiler@tricks@") iChopBehaviourNotMovingTimer = GET_GAME_TIMER() GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDIF BREAK CASE CHOP_TASK_SHIT IF iChopStage = 0 IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF REQUEST_ANIM_DICT("creatures@rottweiler@move") REQUEST_PTFX_ASSET() IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@move") AND HAS_PTFX_ASSET_LOADED() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop doing a shit") #ENDIF CLEAR_PED_TASKS(chopID) OPEN_SEQUENCE_TASK(taskSequence) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "dump_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "dump_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "dump_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_EXTRACT_INITIAL_OFFSET) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) PLAY_CHOP_SOUND("AGITATED") iChopPtfxTimer = GET_GAME_TIMER() iChopStage++ ENDIF ELIF iChopStage = 1 IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() IF DOES_PARTICLE_FX_LOOPED_EXIST(ptfx_chop) STOP_PARTICLE_FX_LOOPED(ptfx_chop) ENDIF IF IS_PED_IN_TRICK_AREA(chopID, FALSE) GIVE_CHOP_TASK(CHOP_TASK_WAIT) ELSE GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ELSE IF NOT DOES_PARTICLE_FX_LOOPED_EXIST(ptfx_chop) IF iChopPtfxTimer > -1 AND (GET_GAME_TIMER() - iChopPtfxTimer) > 4000 ptfx_chop = START_PARTICLE_FX_LOOPED_ON_ENTITY("ent_anim_dog_poo", chopID, <<0,-0.15,-0.2>>, <<0,0,0>>) ENDIF ELIF (GET_GAME_TIMER() - iChopPtfxTimer) > 10000 STOP_PARTICLE_FX_LOOPED(ptfx_chop) iChopPtfxTimer = -1 ENDIF ENDIF ENDIF BREAK CASE CHOP_TASK_PISS IF iChopStage = 0 REQUEST_PTFX_ASSET() IF HAS_PTFX_ASSET_LOADED() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop doing a piss") #ENDIF IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF PLAY_CHOP_SOUND("AGITATED") iChopStage++ ENDIF ELIF iChopStage = 1 REQUEST_ANIM_DICT("creatures@rottweiler@move") IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) TASK_FOLLOW_NAV_MESH_TO_COORD(chopID, GET_ENTITY_COORDS(oLamppost), PEDMOVE_RUN, DEFAULT_TIME_BEFORE_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED|ENAV_NEVER_ENTER_WATER) ENDIF IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(chopID, GET_ENTITY_COORDS(oLamppost)) < 2 IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_MISBEHAVE)) // B*1382114 AND NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_MISBEHAVE)) IF bPlayerUsedApp = FALSE PRINT_HELP("CHOP_H_BEHAVE") // Chop is unhappy so is misbehaving. Download the GTA Chop The Dog app for your iOS, Android, Windows or Playstation device to train him. #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_BEHAVE") #ENDIF ELSE PRINT_HELP("CHOP_H_BEHAVA") // Chop is unhappy so is misbehaving. Use the GTA Chop The Dog app to train him. #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_BEHAVA") #ENDIF ENDIF ENDIF CLEAR_PED_TASKS(chopID) IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@move") AND GET_ENTITY_SPEED(chopID) < 1 vChopCurrentPositionAtLamppost = GET_ENTITY_COORDS(chopID) iChopPissDirection = GET_RANDOM_INT_IN_RANGE(0, 2) fLamppostHeading = GET_HEADING_BETWEEN_VECTORS_2D(vChopCurrentPositionAtLamppost, GET_ENTITY_COORDS(oLamppost)) IF iChopPissDirection = 0 // Turn to left, piss to right vLamppostOffset = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vChopCurrentPositionAtLamppost, fLamppostHeading, <<-0.5,1,0>>) ELSE // Turn to right, piss to left vLamppostOffset = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vChopCurrentPositionAtLamppost, fLamppostHeading, <<0.5,1,0>>) ENDIF OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_COORD(NULL, vLamppostOffset) IF iChopPissDirection = 0 TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_right_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_right_idle", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_right_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) ELSE TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_left_enter", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_left_idle", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "pee_left_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_DEFAULT) ENDIF CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) //SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE) iChopPtfxTimer = GET_GAME_TIMER() iChopStage++ ENDIF ENDIF ELIF iChopStage = 2 //DRAW_DEBUG_SPHERE(vChopCurrentPositionAtLamppost, 0.1) //DRAW_DEBUG_SPHERE(vLamppostOffset, 0.1) IF HAS_CHOP_FINISHED_ANIM_TASK_SEQUENCE() IF DOES_PARTICLE_FX_LOOPED_EXIST(ptfx_chop) STOP_PARTICLE_FX_LOOPED(ptfx_chop) ENDIF PLAY_CHOP_SOUND("BARK") GIVE_CHOP_TASK(CHOP_TASK_WALK) ELSE IF NOT DOES_PARTICLE_FX_LOOPED_EXIST(ptfx_chop) IF iChopPtfxTimer > -1 AND (GET_GAME_TIMER() - iChopPtfxTimer) > 7000 IF iChopPissDirection = 0 ptfx_chop = START_PARTICLE_FX_LOOPED_ON_ENTITY("ent_anim_dog_peeing", chopID, <<0.1,-0.32,-0.04>>, <<0,0,30>>) ELSE ptfx_chop = START_PARTICLE_FX_LOOPED_ON_ENTITY("ent_anim_dog_peeing", chopID, <<-0.1,-0.32,-0.04>>, <<0,0,150>>) ENDIF ENDIF ELIF (GET_GAME_TIMER() - iChopPtfxTimer) > 16000 STOP_PARTICLE_FX_LOOPED(ptfx_chop) iChopPtfxTimer = -1 ENDIF ENDIF ENDIF BREAK CASE CHOP_TASK_FETCH IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) CLEANUP_BALL(FALSE) iChopBehaviourNotMovingTimer = GET_GAME_TIMER() GIVE_CHOP_TASK(CHOP_TASK_WALK) ELSE IF iChopStage = 0 // Setup CLEANUP_BALL(TRUE) // Ensure last eBall has been released IF GET_PROJECTILE_OF_PROJECTILE_TYPE_WITHIN_DISTANCE(PLAYER_PED_ID(), wThrownWeapon, 50, vBallPosition, eBall) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Grabbed eBall ok") #ENDIF REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_CHOP) SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE) // B*1252713 bChopRetrievedBall = FALSE bPlayedFetchBallDialogue = FALSE iGoToBallTasksGiven = 0 IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF iChopFetchDelayTimer = GET_GAME_TIMER() iChopStage++ ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Couldn't grab eBall") #ENDIF ENDIF ELIF iChopStage = 1 // Chop going to ball IF DOES_ENTITY_EXIST(eBall) IF NOT IS_ENTITY_IN_WATER(eBall) IF (GET_GAME_TIMER() - iChopFetchDelayTimer) > 500 // B*1501715 Short delay before Chop runs to fetch the ball IF HAS_CHOP_REACHED_BALL() REQUEST_ANIM_DICT("creatures@rottweiler@move") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@move") OPEN_SEQUENCE_TASK(taskSequence) //TASK_TURN_PED_TO_FACE_ENTITY(NULL, eBall) This makes Chop take a few seconds turning to the ball - looks a bit forced IF wThrownWeapon = WEAPONTYPE_BALL TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "fetch_pickup", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_TAG_SYNC_IN|AF_TAG_SYNC_OUT) ENDIF TASK_GO_TO_ENTITY(NULL, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 4, PEDMOVE_SPRINT) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) IF wThrownWeapon = WEAPONTYPE_BALL bChopRetrievedBall = TRUE ENDIF iChopStage++ ENDIF ELIF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_GO_TO_ENTITY) TASK_GO_TO_ENTITY(chopID, eBall, 30000, DEFAULT_SEEK_RADIUS, PEDMOVE_SPRINT) iGoToBallTasksGiven++ #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop given TASK_GO_TO_ENTITY to eBall, iGoToBallTasksGiven = ", iGoToBallTasksGiven) #ENDIF iNavmeshAttempts = 0 IF iGoToBallTasksGiven > 3 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: TASK_GO_TO_ENTITY can't reach the ball so do GIVE_CHOP_TASK(CHOP_TASK_WALK)") #ENDIF TASK_GO_TO_ENTITY(chopID, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 5, PEDMOVE_SPRINT) CLEANUP_BALL(TRUE) iChopStage++ ENDIF ELSE nrr_chop_route = GET_NAVMESH_ROUTE_DISTANCE_REMAINING(chopID, f_chop_route, i_chop_route) //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: nrr_chop_route = ", nrr_chop_route) #ENDIF IF nrr_chop_route = NAVMESHROUTE_ROUTE_NOT_FOUND fBallZHeight = GET_ENTITY_HEIGHT_ABOVE_GROUND(eBall) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: fBallZHeight = ", fBallZHeight) #ENDIF IF fBallZHeight < 1 // B*1389305 Don't increase while waiting for the ball to land iNavmeshAttempts++ ENDIF ELIF nrr_chop_route = NAVMESHROUTE_ROUTE_FOUND IF bPlayedFetchBallDialogue = FALSE PLAY_CHOP_SOUND("BARK") IF wThrownWeapon = WEAPONTYPE_BALL // B*1404094 Don't play this dialogue if throwing something other than the ball PLAY_FRANKLIN_DIALOGUE("CHOP_FETCH") ENDIF bPlayedFetchBallDialogue = TRUE ENDIF ENDIF //#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Navmesh task = ", nrr_chop_route, " iNavmeshAttempts = ", iNavmeshAttempts, " dist = ", f_chop_route, " last section = ", i_chop_route) #ENDIF IF iNavmeshAttempts > 9 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: nrr_chop_route = NAVMESHROUTE_ROUTE_NOT_FOUND after 10 attempts so do GIVE_CHOP_TASK(CHOP_TASK_WALK)") #ENDIF TASK_GO_TO_ENTITY(chopID, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 5, PEDMOVE_SPRINT) CLEANUP_BALL(TRUE) iChopStage++ ENDIF ENDIF ENDIF ELSE // B*1475993 - Make Chop give up if the ball goes into water #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: eBall is in water") #ENDIF TASK_GO_TO_ENTITY(chopID, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 5, PEDMOVE_SPRINT) iChopStage++ ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: eBall no longer exists") #ENDIF TASK_GO_TO_ENTITY(chopID, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 5, PEDMOVE_SPRINT) iChopStage++ ENDIF ELIF iChopStage = 2 // Chop picking up ball IF bChopRetrievedBall = TRUE IF DOES_ENTITY_EXIST(eBall) AND IS_ENTITY_PLAYING_ANIM(chopID, "creatures@rottweiler@move", "fetch_pickup") AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, "creatures@rottweiler@move", "fetch_pickup") > 0.25 ATTACH_ENTITY_TO_ENTITY(eBall, chopID, 28, <<0.2042, 0.0, -0.0608>>, <<0,0,0>>) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Attached eBall to Chop") #ENDIF SET_AUDIO_FLAG("DisableBarks", TRUE) // B*1342696 - Prevent Chop barking when carrying the ball iChopStage++ ENDIF ELSE iChopStage++ ENDIF ELIF iChopStage = 3 // Chop returning to Franklin IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), chopID) < 5 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop returned to player") #ENDIF IF wThrownWeapon = WEAPONTYPE_BALL IF bChopRetrievedBall = TRUE REQUEST_ANIM_DICT("creatures@rottweiler@move") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@move") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop retrieved ball so playing drop anim") #ENDIF OPEN_SEQUENCE_TASK(taskSequence) TASK_TURN_PED_TO_FACE_ENTITY(NULL, PLAYER_PED_ID()) TASK_PLAY_ANIM(NULL, "creatures@rottweiler@move", "fetch_drop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_TAG_SYNC_IN) CLOSE_SEQUENCE_TASK(taskSequence) TASK_PERFORM_SEQUENCE(chopID, taskSequence) CLEAR_SEQUENCE_TASK(taskSequence) PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN1") SET_AUDIO_FLAG("DisableBarks", FALSE) iChopStage++ ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop didn't retrieve the ball") #ENDIF PLAY_CHOP_SOUND("BREATH_AGITATED") PLAY_FRANKLIN_DIALOGUE("CHOP_RETURN2") GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop returned after player threw a harmful weapon for Chop to chase") #ENDIF PLAY_CHOP_SOUND("BARK_WHINE") CLEANUP_BALL(TRUE) GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDIF ELIF iChopStage = 4 // Chop playing drop ball anim IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PERFORM_SEQUENCE) // Chop has finished his tasks AND NOT DOES_ENTITY_EXIST(eBall) IF IS_PHONE_ONSCREEN() // B*1433223 GIVE_BALL_TO_PLAYER(FALSE, TRUE) ELIF GET_FOLLOW_PED_CAM_VIEW_MODE() = CAM_VIEW_MODE_FIRST_PERSON GIVE_BALL_TO_PLAYER(FALSE, TRUE, TRUE) ELSE GIVE_BALL_TO_PLAYER(TRUE, TRUE, TRUE) ENDIF iChopBehaviourNotMovingTimer = GET_GAME_TIMER() GIVE_CHOP_TASK(CHOP_TASK_WALK) ELIF DOES_ENTITY_EXIST(eBall) IF IS_ENTITY_ATTACHED(eBall) IF IS_ENTITY_PLAYING_ANIM(chopID, "creatures@rottweiler@move", "fetch_drop") AND GET_ENTITY_ANIM_CURRENT_TIME(chopID, "creatures@rottweiler@move", "fetch_drop") > 0.4 DETACH_ENTITY(eBall) ENDIF ELSE IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), eBall) < 1.5 OR GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), eBall) > 20.0 OR IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) CLEANUP_BALL(TRUE) ENDIF IF NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PERFORM_SEQUENCE) // Check here cos we need to wait for the player to collect the ball, so ensure Chop gets put in the player group if the player messes around PUT_CHOP_IN_PLAYER_GROUP() ENDIF ENDIF ENDIF ENDIF HANDLE_FRANKLIN_WHISTLING_TO_CHOP() ENDIF BREAK CASE CHOP_TASK_CABLE_CAR IF iChopStage = 0 // Setup REQUEST_ANIM_DICT("creatures@rottweiler@in_vehicle@std_car") IF HAS_ANIM_DICT_LOADED("creatures@rottweiler@in_vehicle@std_car") IF IS_PED_IN_GROUP(chopID) REMOVE_PED_FROM_GROUP(chopID) ENDIF ATTACH_ENTITY_TO_ENTITY(chopID, GET_ENTITY_ATTACHED_TO(PLAYER_PED_ID()), 0, <<0,0,-6.1>>, <<0,0,0>>, TRUE) TASK_PLAY_ANIM(chopID, "creatures@rottweiler@in_vehicle@std_car", "sit", INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1, AF_LOOPING|AF_NOT_INTERRUPTABLE) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Set Chop into Franklin's cablecar") #ENDIF iChopStage++ ENDIF ELIF iChopStage = 1 // Wait until the cable car script warps Franklin back outside at the end IF NOT IS_ENTITY_ATTACHED(PLAYER_PED_ID()) FLOAT f_closest_dist, f_current_dist INT i_index, i_closest f_closest_dist = 99999 REPEAT NUM_CHOP_CABLE_CAR_POSITIONS i_index // Work out the closest position to Franklin so we can warp Chop there f_current_dist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), vChopCableCarPos[i_index]) IF f_current_dist < f_closest_dist f_closest_dist = f_current_dist i_closest = i_index ENDIF ENDREPEAT IF IS_ENTITY_ATTACHED(chopID) DETACH_ENTITY(chopID) ENDIF SAFE_TELEPORT_ENTITY(chopID, vChopCableCarPos[i_closest], fChopCableCarPos[i_closest]) FORCE_PED_AI_AND_ANIMATION_UPDATE(chopID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Warped Chop to cablecar position ", i_closest) #ENDIF iChopBehaviourNotMovingTimer = GET_GAME_TIMER() GIVE_CHOP_TASK(CHOP_TASK_WALK) ENDIF ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Returns TRUE if any of the Chop menus are currently being displayed. FUNC BOOL IS_CHOP_MENU_ONSCREEN() IF IS_HELP_MESSAGE_BEING_DISPLAYED() // Do a quick check first IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_0") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_HOME") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_0") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H1") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H2") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H3") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H4") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_NOAPP") RETURN TRUE ENDIF ENDIF IF IS_PC_VERSION() IF IS_HELP_MESSAGE_BEING_DISPLAYED() // Do a quick check first IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_0_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WAIT_H4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_HOME_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_0_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H1_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H2_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H3_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_WALK_H4_KM") OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_NOAPP_KM") RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Handles Chop attack any peds who are fighting with Franklin. PROC MANAGE_CHOP_ATTACKING_PEDS_FIGHTING_FRANKLIN() IF eChopTask != CHOP_TASK_ATTACK AND chopInVehicleStatus = CHOP_VEHICLE_STATUS_FRANKLIN_NOT_IN_VEHICLE AND NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) IF eChopTask = CHOP_TASK_WALK // See B*1001112 - Chop should only join in with fights if the player has him following or sniffing (perhaps fetch too?) OR eChopTask = CHOP_TASK_SNIFF OR eChopTask = CHOP_TASK_FETCH // B*1453857 and when fetching ball OR (eChopTask = CHOP_TASK_PISS AND NOT IsPedPerformingTask(chopID, SCRIPT_TASK_PERFORM_SEQUENCE)) // Chop on his way to have a piss IF COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(PLAYER_PED_ID(), GET_ENTITY_COORDS(PLAYER_PED_ID()), CHOP_ATTACK_RANGE) > 0 OR COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(chopID, GET_ENTITY_COORDS(chopID), CHOP_ATTACK_RANGE) > 0 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS > 0 so Chop needs to go into attack mode") #ENDIF REQUEST_ANIM_DICT("creatures@rottweiler@melee@streamed_taunts@") // B*1555787 Ensure taunts are preloaded INT i_ped PED_INDEX temp_ped[5], attackerID REPEAT GET_PED_NEARBY_PEDS(PLAYER_PED_ID(), temp_ped) i_ped IF NOT IS_ENTITY_ALIVE(attackerID) AND IS_ENTITY_ALIVE(temp_ped[i_ped]) AND (IS_PED_IN_COMBAT(temp_ped[i_ped], PLAYER_PED_ID()) OR IS_PED_IN_COMBAT(temp_ped[i_ped], chopID)) AND NOT IS_PED_IN_ANY_VEHICLE(temp_ped[i_ped]) // Chop can't attack peds in cars AND temp_ped[i_ped] != chopID // Chop can't attack himself attackerID = temp_ped[i_ped] ENDIF ENDREPEAT IF IS_ENTITY_ALIVE(attackerID) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: SICK BALLS! Found an enemy for Chop to attack") #ENDIF TASK_COMBAT_PED(chopID, attackerID) PLAY_FRANKLIN_DIALOGUE("CHOP_ATTACK2") IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_ATTACK_ENEMIES)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_ATTACK_ENEMIES)) PRINT_HELP("CHOP_H_ATTACK") // "Chop will attack anyone who attacks Franklin." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_ATTACK") #ENDIF ENDIF CLEANUP_BALL(FALSE) GIVE_CHOP_TASK(CHOP_TASK_ATTACK, FALSE) ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Couldn't find an enemy for Chop to attack") #ENDIF ENDIF ELSE weapon_type wep_current GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), wep_current) IF wep_current != WEAPONTYPE_BALL // B*1434236 AND NOT (eChopTask = CHOP_TASK_FETCH AND iChopStage = 1) // B*1434236 Immediately after throwing the ball the player will be unarmed so don't check while Chop is running to the ball ENTITY_INDEX target_entity IF GET_PLAYER_TARGET_ENTITY(PLAYER_ID(), target_entity) OR GET_ENTITY_PLAYER_IS_FREE_AIMING_AT(PLAYER_ID(), target_entity) IF IS_ENTITY_A_PED(target_entity) PED_INDEX attackerID = GET_PED_INDEX_FROM_ENTITY_INDEX(target_entity) IF NOT IS_PED_INJURED(attackerID) AND attackerID != chopID // Chop can't attack himself AND NOT IS_PED_IN_ANY_VEHICLE(attackerID) // Don't send Chop to attack peds in cars AND GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), attackerID) < 50 // Don't send Chop to attack targets in the player's crosshair that are far away #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player aiming at a ped so sending Chop to attack") #ENDIF TASK_COMBAT_PED(chopID, attackerID) iChopSicBallsMeter++ #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: iChopSicBallsMeter increased to ", iChopSicBallsMeter, ", CHOP_SIC_BALLS_CALL_COPS_LIMIT is ", CHOP_SIC_BALLS_CALL_COPS_LIMIT) #ENDIF IF iChopSicBallsMeter >= CHOP_SIC_BALLS_CALL_COPS_LIMIT #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: iChopSicBallsMeter >= CHOP_SIC_BALLS_CALL_COPS_LIMIT so giving player a wanted level") #ENDIF SET_WANTED_LEVEL_DIFFICULTY(PLAYER_ID(), 0) SET_PLAYER_WANTED_LEVEL_NO_DROP(PLAYER_ID(), 2) ENDIF PLAY_FRANKLIN_DIALOGUE("CHOP_ATTACK1") IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() AND NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_ATTACK_AIM)) AND NOT IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_ATTACK_AIM)) PRINT_HELP("CHOP_H_AIM") // "Chop will attack anyone who Franklin targets." #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_AIM") #ENDIF ENDIF CLEANUP_BALL(FALSE) GIVE_CHOP_TASK(CHOP_TASK_ATTACK, FALSE) ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF IF (GET_GAME_TIMER() - iChopSicBallsTimer) > CHOP_SIC_BALLS_COOLDOWN_TIMER // B*1431784 iChopSicBallsTimer = GET_GAME_TIMER() IF iChopSicBallsMeter > 0 iChopSicBallsMeter-- #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: iChopSicBallsMeter decreased to ", iChopSicBallsMeter, ", CHOP_SIC_BALLS_CALL_COPS_LIMIT is ", CHOP_SIC_BALLS_CALL_COPS_LIMIT) #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// The player pressed dpad right to remove the menu or gave an order to Chop. PROC PLAYER_REMOVED_MENU(BOOL b_stop_hint = TRUE) IF IS_CHOP_MENU_ONSCREEN() CLEAR_HELP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Cleared menu") #ENDIF ENDIF IF b_stop_hint = TRUE AND IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT() ENDIF ENDPROC /// PURPOSE: /// Handles displaying the initial help text for how to interact with Chop. PROC DISPLAY_INITIAL_CHOP_INTERACTION_HELP_TEXT() IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_INTERACT_WITH_CHOP)) AND NOT (IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO") OR (IS_PC_VERSION() AND IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO_KM")) ) //B* 2005474: Don't clear help forever if the player's trying to take a snap of Chop for Wildlife Photo. AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("PW_HELP_1") AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("PW_HELP_2") AND NOT Is_Player_Timetable_Scene_In_Progress() // Required to prevent B*1125295 AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() AND NOT IS_PHONE_ONSCREEN() // B*2013959 Prevent interacting with Chop when the phone is onscreen AND NOT IS_CUSTOM_MENU_ON_SCREEN() AND NOT IS_BROWSER_OPEN() // B*2121820 Prevent interacting with Chop when the internet browser in onscreen IF eChopTask = CHOP_TASK_WAIT OR eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN IF IS_PED_IN_TRICK_AREA(PLAYER_PED_ID()) CLEAR_HELP() IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) PRINT_HELP_FOREVER("CHOP_H_INTRO_KM") // Hold ~INPUT_AIM~ when unarmed to interact with Chop. // Using INPUT_AIM to fix B*1499642 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_INTRO_KM") #ENDIF ELSE PRINT_HELP_FOREVER("CHOP_H_INTRO") // Hold ~INPUT_AIM~ when unarmed to interact with Chop. // Using INPUT_AIM to fix B*1499642 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying help text CHOP_H_INTRO") #ENDIF ENDIF ENDIF ENDIF ENDIF IF (IS_PC_VERSION() AND IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO_KM")) OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO") IF Is_Player_Timetable_Scene_In_Progress() OR IS_PLAYER_SWITCH_IN_PROGRESS() OR IS_PHONE_ONSCREEN() OR IS_CUSTOM_MENU_ON_SCREEN() OR IS_BROWSER_OPEN() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: CHOP_H_INTRO or CHOP_H_INTRO_KM was onscreen but cleared it because the player can't now interact with Chop") #ENDIF CLEAR_HELP() ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns TRUE if the player is close enough to Chop to give orders. FUNC BOOL IS_PLAYER_WITHIN_CHOP_ORDER_RADIUS() IF GET_DISTANCE_BETWEEN_PEDS(PLAYER_PED_ID(), chopID) < 10.0 IF eChopTask = CHOP_TASK_FETCH AND iChopStage < 4 // Chop hasn't yet returned ball so don't allow giving a new order ELSE IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) ALLOW_PLAYER_TO_TARGET_CHOP(FALSE) FRANKLIN_SHOULD_LOOK_AT_CHOP(FALSE) RETURN FALSE ELSE DISPLAY_INITIAL_CHOP_INTERACTION_HELP_TEXT() ALLOW_PLAYER_TO_TARGET_CHOP(TRUE) FRANKLIN_SHOULD_LOOK_AT_CHOP(TRUE) RETURN TRUE ENDIF ENDIF ENDIF ALLOW_PLAYER_TO_TARGET_CHOP(FALSE) FRANKLIN_SHOULD_LOOK_AT_CHOP(FALSE) IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO") // B*946872 - remove this help text if the player leaves Chop without interacting with him OR (IS_PC_VERSION() AND IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("CHOP_H_INTRO_KM")) CLEAR_HELP() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Cleared help text CHOP_H_INTRO/CHOP_H_INTRO_KM") #ENDIF ENDIF RETURN FALSE // More than 10m away ENDFUNC /// PURPOSE: /// Returns true if Chop isn't already performing a trick. FUNC BOOL CAN_CHOP_PERFORM_TRICK() IF eChopTask = CHOP_TASK_SIT OR eChopTask = CHOP_TASK_BEG OR eChopTask = CHOP_TASK_PAW OR eChopTask = CHOP_TASK_PET RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Checks if we allow the menu to appear during the current Chop task. FUNC BOOL SHOULD_MENU_BE_DISPLAYED_DURING_CURRENT_CHOP_TASK() IF eChopTask = CHOP_TASK_SIT_OUTSIDE_SHOP // Don't allow menu if player is inside a shop RETURN FALSE ENDIF IF eChopTask = CHOP_TASK_SHIT OR (eChopTask = CHOP_TASK_PISS AND IsPedPerformingTask(chopID, SCRIPT_TASK_PERFORM_SEQUENCE)) IF bPlayedChopBusyDialogue = FALSE AND IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_SCRIPT_LT) PLAY_FRANKLIN_DIALOGUE("CHOP_BUSY") bPlayedChopBusyDialogue = TRUE ENDIF RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Handles the player giving orders to Chop. PROC MANAGE_PLAYER_GIVING_ORDERS_TO_CHOP() IF IS_PLAYER_WITHIN_CHOP_ORDER_RADIUS() AND SHOULD_MENU_BE_DISPLAYED_DURING_CURRENT_CHOP_TASK() AND NOT IS_CUSTOM_MENU_ON_SCREEN() // B*1812064 Prevent interacting with Chop when a custom menu is onscreen AND eNextChopTask = CHOP_TASK_NONE // Don't allow interaction if the player has given a task and Chop is in the process of doing it AND eChopTask != CHOP_TASK_ATTACK // Don't allow interaction if Chop is in the process of attacking someone AND IS_PLAYER_UNARMED_AND_AIMING_AT_CHOP() AND NOT IS_PLAYER_SWITCH_IN_PROGRESS() // Fix for B*791889 - don't allow performing tasks if player is currently switching character AND NOT IS_PED_IN_COMBAT(chopID) AND NOT IS_PLAYER_IN_RESTRICTED_INTERIOR() AND NOT IS_PLAYER_IN_ANY_SHOP() AND NOT IS_PHONE_ONSCREEN() // B*2013959 Prevent interacting with Chop when the phone is onscreen AND NOT IS_BROWSER_OPEN() // B*2121820 Prevent interacting with Chop when the internet browser in onscreen DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_CHARACTER_WHEEL) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_COVER) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_NEXT_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_PREV_WEAPON) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON) // B*1413360 Prevent weapon wheel when menu is onscreen IF bOverrideHappiness = FALSE DRAW_GENERIC_METER(FLOOR(g_savedGlobals.sSocialData.sDogAppData.fHappiness), 100, "CHOP_H_HAPPY", HUD_COLOUR_WHITE, -1, HUDORDER_DONTCARE, -1.0, -1.0, FALSE, TRUE, HUDFLASHING_NONE, 0, TRUE) ELSE DRAW_GENERIC_METER(100, 100, "CHOP_H_HAPPY", HUD_COLOUR_WHITE, -1, HUDORDER_DONTCARE, -1.0, -1.0, FALSE, TRUE, HUDFLASHING_NONE, 0, TRUE) ENDIF IF IS_CHOP_MENU_ONSCREEN() IF g_bPlayerInteractingWithChop = FALSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Setting g_bPlayerInteractingWithChop to true") #ENDIF g_bPlayerInteractingWithChop = TRUE ENDIF IF IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT_BEING_CANCELLED_THIS_UPDATE(TRUE) ELSE SET_GAMEPLAY_ENTITY_HINT(chopID, <<0,0,0>>, TRUE, -1, 1000, 1000, HINTTYPE_CHOP_HINT_HELPER) bHintCamAlreadyACtive = FALSE ENDIF SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_ENGAGE)) SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SEARCH)) SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SIT)) SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PAW)) // B*1491983 Just disable these regardless of whether tricks have been unlocked if the menu is onscreen SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_BEG)) SET_INPUT_EXCLUSIVE(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PET)) IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_ENGAGE)) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SEARCH)) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SIT)) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PAW)) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_BEG)) DISABLE_CONTROL_ACTION(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PET)) ENDIF ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM) // B*1397364 Re-enable aim to allow maintaining locking onto Chop IF IS_DISABLED_CONTROL_JUST_RELEASED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_ENGAGE)) AND CAN_CHOP_PERFORM_TRICK() SWITCH eChopTask CASE CHOP_TASK_WAIT CASE CHOP_TASK_RETURN CASE CHOP_TASK_WANDER bPlayerChoseToWalkChop = TRUE PLAYER_REMOVED_MENU(FALSE) PLAY_CHOP_SOUND("PLAYFUL") PLAY_FRANKLIN_DIALOGUE("CHOP_WALK") GIVE_CHOP_TASK(CHOP_TASK_WALK) BREAK CASE CHOP_TASK_WALK CASE CHOP_TASK_SNIFF CASE CHOP_TASK_FETCH bPlayerChoseToWalkChop = FALSE PLAYER_REMOVED_MENU(FALSE) GIVE_CHOP_TASK(CHOP_TASK_RETURN) BREAK CASE CHOP_TASK_WAIT_PLAY_ANIM CASE CHOP_TASK_GREET_FRANKLIN bPlayerChoseToWalkChop = TRUE PLAYER_REMOVED_MENU(FALSE) PLAY_FRANKLIN_DIALOGUE("CHOP_WALK") eNextChopTask = CHOP_TASK_WALK BREAK ENDSWITCH IF bPlayerChoseToWalkChop = TRUE AND STAT_GET_INT(SP_CHOP_WALK_DONE, iNumTimesChopTakenForWalk) iNumTimesChopTakenForWalk++ STAT_SET_INT(SP_CHOP_WALK_DONE, iNumTimesChopTakenForWalk) // B*1545868 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: SP_CHOP_WALK_DONE incremented to ", iNumTimesChopTakenForWalk) #ENDIF ENDIF ENDIF IF bPlayerUsedApp = TRUE IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SEARCH)) // Sniff out nearest hidden package or weapon pickup AND CAN_CHOP_PERFORM_TRICK() IF eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN eNextChopTask = CHOP_TASK_SNIFF ELSE GIVE_CHOP_TASK(CHOP_TASK_SNIFF) ENDIF ENDIF IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD // B*1382082 Chop won't do tricks if he's unhappy AND bOverrideHappiness = FALSE IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 1) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SIT)) PLAY_FRANKLIN_DIALOGUE("CHOP_CANT") ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 2) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PAW)) PLAY_FRANKLIN_DIALOGUE("CHOP_CANT") ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 3) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_BEG)) PLAY_FRANKLIN_DIALOGUE("CHOP_CANT") ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 4) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PET)) PLAY_FRANKLIN_DIALOGUE("CHOP_CANT") ENDIF ENDIF ELSE IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 1) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_SIT)) AND CAN_CHOP_PERFORM_TRICK() PLAY_FRANKLIN_DIALOGUE("CHOP_SIT") IF eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN eNextChopTask = CHOP_TASK_SIT ELSE GIVE_CHOP_TASK(CHOP_TASK_SIT) ENDIF ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 2) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PAW)) AND CAN_CHOP_PERFORM_TRICK() PLAY_FRANKLIN_DIALOGUE("CHOP_PAW") IF eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN eNextChopTask = CHOP_TASK_PAW ELSE GIVE_CHOP_TASK(CHOP_TASK_PAW) ENDIF ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 3) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_BEG)) AND CAN_CHOP_PERFORM_TRICK() PLAY_FRANKLIN_DIALOGUE("CHOP_BEG") IF eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN eNextChopTask = CHOP_TASK_BEG ELSE GIVE_CHOP_TASK(CHOP_TASK_BEG) ENDIF ENDIF ENDIF IF (GET_CHOP_TRAINING_LEVEL_FROM_APP() >= 4) IF IS_DISABLED_CONTROL_JUST_PRESSED(GET_CHOP_INPUT_CONTROL(), GET_CHOP_INPUT_ACTION(CHOP_INPUT_PET)) AND CAN_CHOP_PERFORM_TRICK() PLAY_FRANKLIN_DIALOGUE("CHOP_PET") IF eChopTask = CHOP_TASK_WAIT_PLAY_ANIM OR eChopTask = CHOP_TASK_GREET_FRANKLIN eNextChopTask = CHOP_TASK_PET ELSE GIVE_CHOP_TASK(CHOP_TASK_PET) ENDIF ENDIF ENDIF ENDIF ENDIF ELSE CLEAR_HELP() IF NOT IS_BIT_SET(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_INTERACT_WITH_CHOP)) SET_BIT(g_savedGlobals.sAmbient.iChopHintsDisplayed, ENUM_TO_INT(CHOP_HELP_INTERACT_WITH_CHOP)) // Only set this the first time the player interacts with Chop ENDIF IF bPlayerUsedApp = FALSE // B*1339036 - If this is set to false re-check whenever the player holds left trigger in case he's used the app while this Chop script is active bPlayerUsedApp = HAS_PLAYER_USED_CHOP_APP() ENDIF IF bPlayerUsedApp = TRUE INT i_chop_training_level = GET_CHOP_TRAINING_LEVEL_FROM_APP() IF i_chop_training_level > 4 i_chop_training_level = 4 ENDIF IF (eChopTask = CHOP_TASK_WAIT) OR (eChopTask = CHOP_TASK_WAIT_PLAY_ANIM) OR (eChopTask = CHOP_TASK_GREET_FRANKLIN) OR (eChopTask = CHOP_TASK_RETURN) OR (eChopTask = CHOP_TASK_WANDER) IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD AND bOverrideHappiness = FALSE AND i_chop_training_level > 0 // Required for B*1397363 - there is no CHOP_H_WALK_H0 text tlChopHelp = "CHOP_H_WAIT_H" ELSE tlChopHelp = "CHOP_H_WAIT_" ENDIF tlChopHelp += i_chop_training_level IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) tlChopHelp += "_KM" ENDIF ELSE IF (eChopTask = CHOP_TASK_WALK) OR (eChopTask = CHOP_TASK_FETCH) IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_BAD AND bOverrideHappiness = FALSE AND i_chop_training_level > 0 // Required for B*1397363 - there is no CHOP_H_WALK_H0 text tlChopHelp = "CHOP_H_WALK_H" ELSE tlChopHelp = "CHOP_H_WALK_" ENDIF tlChopHelp += i_chop_training_level IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) tlChopHelp += "_KM" ENDIF ENDIF ENDIF PRINT_HELP_FOREVER(tlChopHelp) // Print the orders help text with a list of orders currently available to the player that he's unlocking in the training app #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying menu ", tlChopHelp) #ENDIF ELSE IF eChopTask = CHOP_TASK_WALK OR eChopTask = CHOP_TASK_FETCH IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) PRINT_HELP_FOREVER("CHOP_H_HOME_KM") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying CHOP_H_HOME_KM") #ENDIF ELSE PRINT_HELP_FOREVER("CHOP_H_HOME") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying CHOP_H_HOME") #ENDIF ENDIF ELSE IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL) PRINT_HELP_FOREVER("CHOP_H_NOAPP_KM") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying CHOP_H_NOAPP_KM") #ENDIF ELSE PRINT_HELP_FOREVER("CHOP_H_NOAPP") #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Displaying CHOP_H_NOAPP") #ENDIF ENDIF ENDIF ENDIF ENDIF ELSE PLAYER_REMOVED_MENU() // See B*1043428 Ensure menu is removed ENDIF ENDPROC /// PURPOSE: /// Updates Chop's collar if the player has selected a different one in the app. PROC MANAGE_CHOP_DONE_SHIT_DIALOGUE() IF bChopDoneShitDialogue = FALSE IF IS_PED_IN_TRICK_AREA(PLAYER_PED_ID()) PLAY_FRANKLIN_DIALOGUE("CHOP_DUMP") bChopDoneShitDialogue = TRUE ENDIF ENDIF ENDPROC /// PURPOSE: /// Handles Chop doing something sensible if Franklin uses the cable car. PROC HANDLE_FRANKLIN_USING_CABLE_CAR() IF eChopTask != CHOP_TASK_CABLE_CAR AND g_bIsOnCableCar = TRUE AND IS_ENTITY_ATTACHED_TO_ANY_OBJECT(PLAYER_PED_ID()) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Franklin is in the cablecar") #ENDIF GIVE_CHOP_TASK(CHOP_TASK_CABLE_CAR) ENDIF ENDPROC /// PURPOSE: /// Update dog food value on the bawsaq stock market. PROC MANAGE_BAWSAQ_STOCK_VALUES() IF (GET_GAME_TIMER() - iStockMarketTimer) > 60000 iStockMarketTimer = GET_GAME_TIMER() IF eChopTask = CHOP_TASK_WALK OR eChopTask = CHOP_TASK_SNIFF OR eChopTask = CHOP_TASK_FETCH IF GET_CHOP_BEHAVIOUR_FROM_APP() = CHOP_BEHAVIOUR_GOOD BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_HDOG) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Incremented BSMF_SM_HDOG") #ENDIF ELSE BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_UHDOG) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Incremented BSMF_SM_UHDOG") #ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Main processing function. PROC DO_PROCESSING() IF IS_PED_INJURED(PLAYER_PED_ID()) EXIT ENDIF IF IS_PED_INJURED(chopID) EXIT ENDIF UPDATE_CHOP_COLLAR() MANAGE_CHOP_DONE_SHIT_DIALOGUE() IF eChopTask != CHOP_TASK_SPAWNED_IN_KENNEL HANDLE_FRANKLIN_USING_CABLE_CAR() MANAGE_CHOP_ATTACKING_PEDS_FIGHTING_FRANKLIN() MANAGE_PLAYER_GIVING_ORDERS_TO_CHOP() SCAN_FOR_OLD_BALLS_NEAR_FRANKLIN() MANAGE_BAWSAQ_STOCK_VALUES() ENDIF PROCESS_PRIMARY_TASKS() ENDPROC #IF IS_DEBUG_BUILD /// PURPOSE: /// Checks for debug keys being pressed. PROC DEBUG_Check_Debug_Keys() IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S)) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player pressed S") #ENDIF CLEANUP_SCRIPT() ENDIF IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F)) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player pressed F") #ENDIF CLEANUP_SCRIPT() ENDIF ENDPROC #ENDIF SCRIPT(coords_struct in_coords) IF HAS_FORCE_CLEANUP_OCCURRED() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Force cleanup has occurred") #ENDIF CLEANUP_SCRIPT() ENDIF // B*2219053 - If the game is loading wait until it's faded in and everything in setup before we allow the chop script to continue, or else it may create its own chop WHILE NOT IS_SCREEN_FADED_IN() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Waiting for screen to fade in") #ENDIF WAIT(0) ENDWHILE //B* 2002205: Remember if hint cam was already active bHintCamAlreadyACtive = IS_GAMEPLAY_HINT_ACTIVE() #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Script launched at ", in_coords.vec_coord[0]) #ENDIF vStartCoords = in_coords.vec_coord[0] IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_OF_THIS_SCRIPT_NAME()) > 1 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop script instance already running") #ENDIF CLEANUP_SCRIPT() ENDIF IF NOT Get_Mission_Flow_Flag_State(FLOWFLAG_CHOP_THE_DOG_UNLOCKED) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Chop hasn't been unlocked") #ENDIF CLEANUP_SCRIPT() ENDIF IF NOT Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_SC) AND NOT Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_VH) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Neither safehouse is available yet") #ENDIF CLEANUP_SCRIPT() ENDIF IF Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_VH) AND GET_CLOSEST_SAVEHOUSE(vStartCoords, CHAR_FRANKLIN) = SAVEHOUSE_FRANKLIN_SC #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player returned to old SC safehouse") #ENDIF CLEANUP_SCRIPT() ENDIF IF NOT IS_PED_THE_CURRENT_PLAYER_PED(CHAR_FRANKLIN) #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player isn't Franklin") #ENDIF CLEANUP_SCRIPT() ENDIF IF g_bSafehouseTutorialIsActive = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bSafehouseTutorialIsActive is TRUE") #ENDIF CLEANUP_SCRIPT() ENDIF IF g_bPlayerLockedInToTrigger = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bPlayerLockedInToTrigger is TRUE") #ENDIF CLEANUP_SCRIPT() ENDIF IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_STORY) IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("SH_Intro_F_Hills")) = 0 //B* 1837051: And the mission running isn't Martin1 which requres the chop script at the end AND GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("martin1")) = 0 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is on a mission") #ENDIF CLEANUP_SCRIPT() ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is on a mission but it's only the safehouse tutorial") #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is not on a mission") #ENDIF ENDIF IF Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F_WALKCHOP_a OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F_WALKCHOP_b OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F0_PLAYCHOP OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F1_PLAYCHOP OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F0_WALKCHOP // OR Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_F1_WALKCHOP //scene removed bDoingTimetableSwitchChopNotInVehicle = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Timetable scene is in progress, Chop not in a vehicle") #ENDIF ELIF Get_Player_Timetable_Scene_In_Progress() = PR_SCENE_Fa_EXILE2 bDoingTimetableSwitchChopIsInVehicle = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Timetable scene is in progress, Chop is in a vehicle") #ENDIF ELSE IF GET_DISTANCE_BETWEEN_COORDS(vStartCoords, << 154.0731, 765.5721, 209.6901 >>) <= 50 // PR_SCENE_F_WALKCHOP_a OR GET_DISTANCE_BETWEEN_COORDS(vStartCoords, << -268.1390, 415.2881, 109.7258 >>) <= 50 // PR_SCENE_F_WALKCHOP_b OR GET_DISTANCE_BETWEEN_COORDS(vStartCoords, << 314.4171, 965.2070, 208.4024 >>) <= 50 // PR_SCENE_Fa_EXILE2 #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: Player is near timetable coords but not on a timetable scene") #ENDIF CLEANUP_SCRIPT() // Prevent the Chop script launching any further if the player is just driving passed where the Chop timetable scenes take place ENDIF bDoingTimetableSwitchChopNotInVehicle = FALSE bDoingTimetableSwitchChopIsInVehicle = FALSE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: No timetable scene in progress - player is near to the SC or VH safehouse") #ENDIF IF g_bScriptsSetSafeForCutscene = TRUE #IF IS_DEBUG_BUILD CPRINTLN(DEBUG_AMBIENT, "CHOP: g_bScriptsSetSafeForCutscene is TRUE") #ENDIF CLEANUP_SCRIPT() ENDIF ENDIF #IF IS_DEBUG_BUILD SETUP_CHOP_WIDGETS() #ENDIF WHILE (TRUE) #IF IS_DEBUG_BUILD MAINTAIN_CHOP_WIDGETS() DEBUG_Check_Debug_Keys() #ENDIF IF NOT SHOULD_SCRIPT_CLEANUP() SWITCH eStage CASE STAGE_INIT DO_INITIALISE() BREAK CASE STAGE_PROCESS DO_PROCESSING() BREAK ENDSWITCH ELSE CLEANUP_SCRIPT() ENDIF WAIT(0) ENDWHILE ENDSCRIPT