//╒═════════════════════════════════════════════════════════════════════════════╕ //│ Author: Adam Westwood Date: 07/02/14 │ //│ Michael Wadelin Date: 10/09/14 │ //╞═════════════════════════════════════════════════════════════════════════════╡ //│ │ //│ Crowd Control Minigame │ //│ │ //│ Minigame for controlling a crowd │ //│ │ //│ │ //│ │ //╘═════════════════════════════════════════════════════════════════════════════╛ USING "timer_public.sch" USING "rage_builtins.sch" USING "globals.sch" USING "commands_audio.sch" USING "script_audio.sch" USING "commands_camera.sch" USING "commands_clock.sch" USING "commands_debug.sch" USING "commands_fire.sch" USING "commands_graphics.sch" USING "commands_hud.sch" USING "commands_misc.sch" USING "commands_object.sch" USING "commands_pad.sch" USING "commands_ped.sch" USING "commands_player.sch" USING "commands_script.sch" USING "commands_streaming.sch" USING "commands_task.sch" USING "commands_vehicle.sch" USING "commands_interiors.sch" USING "net_include.sch" USING "script_ped.sch" USING "model_enums.sch" USING "script_player.sch" USING "script_misc.sch" USING "selector_public.sch" USING "timer_public.sch" USING "LineActivation.sch" USING "clothes_shop_private.sch" USING "script_audio.sch" #IF IS_DEBUG_BUILD USING "shared_debug.sch" USING "script_debug.sch" #ENDIF // Enums //---------------------------------------------------------------- ENUM CROWD_CONTROL_HEIST_TYPE CCHEIST_NORMAL, CCHEIST_CUSTOM_FLEECA, CCHEIST_CUSTOM_ORNATE ENDENUM ENUM CROWD_CONTROL_PED_HERO_ACTION CCHERO_NONE, CCHERO_GUN, CCHERO_PHONE, CCHERO_ALARM ENDENUM ENUM CROWD_CONTROL_FAIL_REASON CCFAIL_NONE, CCFAIL_PEDHEROGUN, CCFAIL_PEDHEROPHONE, CCFAIL_PEDHEROALARM, CCFAIL_PEDKILLED, CCFAIL_PEDSKILLED, CCFAIL_FEARLOW, CCFAIL_TOOMANYKNOCKOUTS, CCFAIL_NOHITSREMAINING ENDENUM ENUM CROWD_CONTROL_PED_ENUM CCPED_CASHIER_A, CCPED_CASHIER_B, CCPED_CUSTOMER_A, CCPED_CUSTOMER_B, CCPED_CUSTOMER_C, CCPED_CUSTOMER_D, CCPED_CUSTOMER_E, CCPED_CUSTOMER_F, CCPED_CUSTOMER_G, CCPED_CUSTOMER_H ENDENUM ENUM CROWD_CONTROL_PED_STATE CCPS_INVALID = -1, CCPS_INTRO, CCPS_COWER, CCPS_FLINCH, CCPS_FLINCH_UNDERFIRE, CCPS_BEATDOWN, CCPS_HERO_ATTEMPT, CCPS_HERO, CCPS_COMBAT ENDENUM // List of all the anim types for the custom animated versions of the minigame ENUM CROWD_CONTROL_PED_ANIM_TYPE CCPANIM_INTRO_LOOP, CCPANIM_INTRO, CCPANIM_COWER_LOOP, // Flinch CCPANIM_COWER_TO_FLINCH_INTRO, CCPANIM_FLINCH_LOOP, CCPANIM_FLINCH_TO_IDLE_OUTRO, // Flinch underfire CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO, CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO, CCPANIM_FLINCH_UNDERFIRE_LOOP, CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO, CCPANIM_BEATDOWN_INTRO, CCPANIM_BEATDOWN_LOOP, CCPANIM_BEATDOWN_HIT_A, CCPANIM_BEATDOWN_HIT_B, CCPANIM_BEATDOWN_DIE, CCPANIM_BEATDOWN_DIE_LOOP, CCPANIM_BEATDOWN_OUTRO, CCPANIM_HERO_START, CCPANIM_HERO_LOOP, CCPANIM_HERO_PASS, CCPANIM_HERO_FAIL ENDENUM // List of anims for the player ped to play in the custom anim version of this minigame ENUM CROWD_CONTROL_PLAYER_ANIM_TYPE CCPLAYERANIM_INVALID = -1, CCPLAYERANIM_BEATDOWN_PISTOL_A, CCPLAYERANIM_BEATDOWN_PISTOL_B, CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A, CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B, CCPLAYERANIM_BEATDOWN_RIFLE_A, CCPLAYERANIM_BEATDOWN_RIFLE_B, CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A, CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B, CCPLAYERANIM_BEATDOWN_LONG_PISTOL_A, CCPLAYERANIM_BEATDOWN_LONG_PISTOL_KICK_A, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_A, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_B, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_A, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_B ENDENUM // Represents the type of threat the player is imposing on a crowd control ped ENUM CROWD_CONTROL_THREAT_TYPE CCTHREAT_NONE, CCTHREAT_PROXIMITY, CCTHREAT_SHOUTING, CCTHREAT_BEATING_NEIGHBOUR, CCTHREAT_SHOUTING_CLOSE, CCTHREAT_AIMED_AT, CCTHREAT_BEATING, CCTHREAT_SHOOTING, CCTHREAT_KILLED_OTHER, CCTHREAT_PROJECTILE_EXPLOSIVE, CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB, CCTHREAT_SHOOTING_CLOSE ENDENUM // PRIORITY ORDER ENUM CROWD_CONTROL_DIALOGUE CCDIA_NONE, CCDIA_COWER_LOW_FEAR, CCDIA_COWER_HIGH_FEAR, CCDIA_APPROACH, CCDIA_ALARM_GOES_OFF, CCDIA_RECEIVES_SCARE, CCDIA_STICKS_UP_FOR_OTHER, CCDIA_SEES_OTHER_KILLED, CCDIA_SHOT_NEAR, CCDIA_SHOT_DIRECTLY_AT, CCDIA_ALARM_GOES_OFF_INITIAL, // Hero stuff should be higher than general stuff CCDIA_HERO_ALARM_START, CCDIA_HERO_ALARM_CAUGHT, CCDIA_HERO_ALARM_COMPLETE, CCDIA_HERO_GUN_START, CCDIA_HERO_GUN_CAUGHT, CCDIA_HERO_GUN_COMPLETE, CCDIA_HERO_PHONE_START, CCDIA_HERO_PHONE_CAUGHT, CCDIA_HERO_PHONE_COMPLETE, CCDIA_HERO_PHONE_APOLOGISE, // 1 offs, high priority CCDIA_INITIAL_PANIC ENDENUM // List of the different context timers ENUM CROWD_CONTROL_DIALOGUE_CONTEXT CCDIACONTEXT_SCARED_HIGH, CCDIACONTEXT_SCARED_MEDIUM, CCDIACONTEXT_SCARED_LOW, CCDIACONTEXT_SCARED_SECOND_HAND, CCDIACONTEXT_AMBIENT, CCDIACONTEXT_NUM_CONTEXTS ENDENUM // List of all the sequences used to task the crowd ped animations ENUM CROWD_CONTROL_SEQUENCES CCSEQ_COWER_TO_FLINCH, CCSEQ_COWER_TO_FLINCH_UNDERFIRE, CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE, CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH, CCSEQ_FLINCH_TO_COWER, // CCSEQ_OPEN_SAFE, CCSEQ_HERO_START, // CCSEQ_HERO_ALT, CCSEQ_HERO_FAIL, CCSEQ_HERO_PASS, CCSEQ_BEATDOWN_TO_FLINCH, CCSEQ_NUM_SEQUENCES ENDENUM // Server bitset flags ENUM CROWD_CONTROL_DATA_BITSET_FLAGS CCDATA_Active // 0 ,CCDATA_Failed ,CCDATA_FailProcessed ,CCDATA_FailDisabled ,CCDATA_Restricted ,CCDATA_EasyPassComplete // 5 ,CCDATA_EasyPassProcessed ,CCDATA_FearFailsBlocked ,CCDATA_RaiseAlarmDiagloue #IF IS_DEBUG_BUILD ,CCDATA_DebugUnlimitedBeatings ,CCDATA_DebugDisableFails // 10 ,CCDATA_RestrictedDebug #ENDIF ENDENUM // Local bitset flags ENUM CROWD_CONTROL_LOCAL_DATA_BITSET_FLAGS CCLOCALDATA_IntroAnimsRequested // 0 ,CCLOCALDATA_MainAnimsRequested ,CCLOCALDATA_StartedFailCutscene ,CCLOCALDATA_RecievedSyncedScene ,CCLOCALDATA_HelpText1 ,CCLOCALDATA_HelpText2 // 5 ,CCLOCALDATA_HelpText3 ,CCLOCALDATA_DisplayHUD ,CCLOCALDATA_Initialised ,CCLOCALDATA_RaiseAlarms ,CCLOCALDATA_AlarmsPlaying // 10 ,CCLOCALDATA_AwardGiven ,CCLOCALDATA_BeatdownInterrupt ,CCLOCALDATA_BeatdownFirst ,CCLOCALDATA_BeatdownInputTaken ,CCLOCALDATA_BeatdownProbeResultAllowHit // 15 ,CCLOCALDATA_HUDWarning ,CCLOCALDATA_TimerSetFearFail ,CCLOCALDATA_TimerSetFearUnblocked ,CCLOCALDATA_TimeSetNextHeroPick ,CCLOCALDATA_BlockingActionMode // 20 #IF IS_DEBUG_BUILD ,CCLOCALDATA_DebugLogDialogue #ENDIF ENDENUM // Server ped data bit flags ENUM CROWD_CONTROL_PED_DATA_BITSET_FLAGS CCPEDDATA_HasBeenInitialised ,CCPEDDATA_RunningBespokeAnims ,CCPEDDATA_KnockedOut ,CCPEDDATA_Dead ,CCPEDDATA_DeadProcessed ,CCPEDDATA_FearLocked ,CCPEDDATA_HeroComplete ,CCPEDDATA_HeroBroken ,CCPEDDATA_HeroAttempted ,CCPEDDATA_BeatdownSyncSceneStarted ,CCPEDDATA_IgnoreStickyBombs ENDENUM // Local ped data bit flags ENUM CROWD_CONTROL_LOCAL_PED_DATA_BITSET_FLAGS CCLOCALPEDDATA_OwnThisPed ,CCLOCALPEDDATA_LocallyInitialised ,CCLOCALPEDDATA_DialogueClientToHostForcePain ,CCLOCALPEDDATA_DialogueClientToHostForceCritical ,CCLOCALPEDDATA_DialogueHostToClientInterrupt ,CCLOCALPEDDATA_DialogueHostToClientPain ,CCLOCALPEDDATA_ShotAtFearWasClose ,CCLOCALPEDDATA_TimeLastThreatenedSet ,CCLOCALPEDDATA_TimeLastShotAtSet ,CCLOCALPEDDATA_TimeLastBeatSet ,CCLOCALPEDDATA_TimeSetStartThreaten ,CCLOCALPEDDATA_TimeSetHoldBeforeEscape ,CCLOCALPEDDATA_TimeSetStartFearProjectile ,CCLOCALPEDDATA_TimeSetStartProximityThreat ,CCLOCALPEDDATA_TimeSetShootingCloseFlinching ,CCLOCALPEDDATA_BeatdownFired ,CCLOCALPEDDATA_HeroPropDetatchedForLastTime ENDENUM ENUM CROWD_CONTROL_PED_DECORATOR CCPDECOR_iState ,CCPDECOR_iStatePrev ,CCPDECOR_iBitSet ,CCPDECOR_fInfluenceDirectThreat ,CCPDECOR_fInfluenceShouting ,CCPDECOR_iBeatdownHitsRemaining ,CCPDECOR_iBeatdownRounds ENDENUM #IF IS_DEBUG_BUILD ENUM CROWD_CONTROL_DEBUG_DISPLAY CCDEBUG_OFF = -1, CCDEBUG_ALL, CCDEBUG_BASIC, CCDEBUG_FEAR_AND_THREATS, CCDEBUG_HERO, CCDEBUG_BEATDOWNS, CCDEBUG_DIALOGUE, CCDEBUG_MISC, CCDEBUG_NUM_DEBUG ENDENUM #ENDIF // Constants //---------------------------------------------------------------- CONST_INT ciCC_MaxActiveHeros 1 CONST_FLOAT cfCC_ShoutVolumeLevel 0.75 CONST_INT ciCC_DialogueBroadcastDelay 2000 CONST_INT ciCC_MaxNumberOfAmbientDialogue 1 CONST_INT ciCC_MaxNumberOfPain 3 CONST_INT ciCC_MaxNumberOfSpeakers ciCC_MaxNumberOfAmbientDialogue + ciCC_MaxNumberOfPain CONST_INT ciCC_MaxBeatdownHits 2 CONST_INT ciCC_MaxBeatdownHitsTotal 6 CONST_INT ciCC_BeatdownHitsLostOnPedDeath 3 TWEAK_FLOAT cfCC_BeatdownDistMin 0.5 TWEAK_FLOAT cfCC_BeatdownDistMax 1.5 TWEAK_FLOAT cfCC_BeatdownLongAnimDistThreshold 1.25 TWEAK_FLOAT cfCC_BeatdownMeleeDisableDist 2.0 TWEAK_FLOAT cfCC_BeatdownFacingAngleChangeDistMin 0.75 TWEAK_FLOAT cfCC_BeatdownFacingAngleChangeDistMax 1.3 TWEAK_FLOAT cfCC_BeatdownFacingAngleRangeMin 23.5 TWEAK_FLOAT cfCC_BeatdownFacingAngleRangeMax 80.0 CONST_FLOAT cfCC_PlayerPedCapsuleRadiusStationary 0.25 CONST_FLOAT cfCC_PedBreakoutCowerThreshold 25.0 CONST_INT ciCC_PedThreatenCoolOffDuration 2000 CONST_INT ciCC_PedShotAtCoolOffDuration 1000 CONST_INT ciCC_PedShotAtCoolOffDurationClose 3000 CONST_INT ciCC_ProjectileCoolOffDuration 6000 CONST_INT ciCC_ProximityCoolOffDuration 5000 CONST_INT ciCC_FearFailMin 0 TWEAK_FLOAT cfCC_FearIncreaseRateMin 1.0 TWEAK_FLOAT cfCC_FearIncreaseRateMax 8.0 TWEAK_FLOAT cfCC_FearDecreaseRateMin 0.5 TWEAK_FLOAT cfCC_FearDecreaseRateMax 4.0 CONST_INT ciCC_Range 30 CONST_INT ciCC_ThreatTypeDataBitWidth 4 // max 16 numbers/states CONST_INT ciCC_DialogueDataBitWidth 5 // max 32 numbers/states CONST_INT ciCC_HeroAttemptsDataBitWidth 6 // max 64 numbers/states CONST_INT ciCC_MaxAlarms 2 ANIMATION_FLAGS eCrowdControlAnimFlags = AF_USE_KINEMATIC_PHYSICS | AF_USE_MOVER_EXTRACTION // | AF_NOT_INTERRUPTABLE #IF IS_DEBUG_BUILD TWEAK_INT ciCC_DebugColNormalR 0 TWEAK_INT ciCC_DebugColNormalG 0 TWEAK_INT ciCC_DebugColNormalB 255 TWEAK_INT ciCC_DebugColWarningR 30 TWEAK_INT ciCC_DebugColWarningG 255 TWEAK_INT ciCC_DebugColWarningB 255 TWEAK_INT ciCC_DebugColActiveR 190 TWEAK_INT ciCC_DebugColActiveG 0 TWEAK_INT ciCC_DebugColActiveB 255 #ENDIF // Structs //---------------------------------------------------------------- STRUCT CROWD_CONTROL_SERVER_DATA INT iMinigameStage = 0 INT iCrowdControlCloudIndex[FMMC_MAX_CROWD_PEDS] // can this be cached locally? FLOAT fFear = -1.0 // the overall fear level of the crowd INT iBitSet = 0 INT iCurrentActiveHeros = 0 INT iHeroAttempts[2] // use 6 bits per ped to save storage (instead of an int per ped i.e. 10 ints) INT iSyncScene = -1 INT iPedIsNowInvolvedInCrowdControl[2] // can this be removed? INT iNumCrowdControlPeds INT iNumHitsRemaining = ciCC_MaxBeatdownHitsTotal ENDSTRUCT STRUCT CROWD_CONTROL_LOCAL_DATA // Locals cached info INT iCCRule[FMMC_MAX_TEAMS] INT iThermiteTeam = -1 INT iThermiteRule = -1 CROWD_CONTROL_HEIST_TYPE eHeistType = CCHEIST_NORMAL INT iCashierPed = -1 INTERIOR_INSTANCE_INDEX interiorHeist = NULL // Local Variables // General INT iBitSet = 0 INT iSyncSceneIntroLoop = -1 // Heroes TIME_DATATYPE timeNextHeroPick // Dialogue TIME_DATATYPE timeDialogueGlobalContextTimers[CCDIACONTEXT_NUM_CONTEXTS] TIME_DATATYPE timeCrowdKickedOff // Beating INT iSyncSceneBeatdown = -1 INT iPlayerBeatingThisPed = -1 CROWD_CONTROL_PLAYER_ANIM_TYPE eLastBeatdown = CCPLAYERANIM_INVALID SHAPETEST_INDEX shapetestBeatdownProbe = NULL INT iCrowdPedBeatdownProbe = -1 // Fear FLOAT fFear FLOAT fIntimidationBar FLOAT fIntimidationBarInterpRate INT iUpdateTimer = 0 // Fail INT iFailCutsceneHash = 0 INT iFailCausedByPed = -1 TIME_DATATYPE timeFailDelay TIME_DATATYPE timeFearFail TIME_DATATYPE timeFearFailsUnblocked CROWD_CONTROL_FAIL_REASON eFailReason = CCFAIL_NONE // Alarms INT iSFXAlarms[ciCC_MaxAlarms] #IF IS_DEBUG_BUILD // Debug vars CROWD_CONTROL_DEBUG_DISPLAY eDebugDisplay = CCDEBUG_OFF #ENDIF ENDSTRUCT // Used locally for delaying the update of decorators STRUCT CROWD_CONTROL_PED_DECORATOR_DATA CROWD_CONTROL_PED_STATE eState CROWD_CONTROL_PED_STATE eStatePrev INT iBitSet FLOAT fInfluenceDirectThreat FLOAT fInfluenceShouting INT iBeatdownHitsRemaining INT iBeatdownRounds ENDSTRUCT STRUCT CROWD_CONTROL_LOCAL_PED_DATA // Cached ped data CROWD_CONTROL_PED_ENUM eCreatorAssignedPedID // Local ped variables INT iBitSet = 0 INT iUpdateTimer // Prop related stuff OBJECT_INDEX objProp = NULL //For props like phones // Dialogue CROWD_CONTROL_DIALOGUE eDialogueClientToHost = CCDIA_NONE // what a ped wants to play CROWD_CONTROL_DIALOGUE eDialogueHostToClient = CCDIA_NONE // what they have been allowed to play CROWD_CONTROL_DIALOGUE eDialogueCurrentlyPlaying = CCDIA_NONE // what they are currently playing TIME_DATATYPE timeDialogueLastBroadcast // the last time a ped told the host it wanted to speak TIME_DATATYPE timeDialogueContextTimers[CCDIACONTEXT_NUM_CONTEXTS] // last time dialogue from each context was spoken // Threat CROWD_CONTROL_THREAT_TYPE eBiggestThreat = CCTHREAT_NONE PED_INDEX pedBiggestThreat = NULL TIME_DATATYPE timeThreatUpdate // used to control how often we update the player threat BD TIME_DATATYPE timeStartThreaten TIME_DATATYPE timeLastThreatened TIME_DATATYPE timeLastShotAt TIME_DATATYPE timeLastBeat TIME_DATATYPE timeStartProjectileFear TIME_DATATYPE timeStartProximityThreat TIME_DATATYPE timeShootingCloseFlinchingStarted TIME_DATATYPE timeDied // Sequences SEQUENCE_INDEX seqs[CCSEQ_NUM_SEQUENCES] #IF IS_DEBUG_BUILD CROWD_CONTROL_THREAT_TYPE eDebugThreatFelt = CCTHREAT_NONE CROWD_CONTROL_THREAT_TYPE eDebugThreatUsedForFear = CCTHREAT_NONE #ENDIF ENDSTRUCT // Cleanup //---------------------------------------------------------------------------- PROC RESET_CROWD_CONTROL_SERVER_DATA( CROWD_CONTROL_SERVER_DATA &sCrowdControlData ) CPRINTLN(DEBUG_NET_MINIGAME, "RESET_CROWD_CONTROL_SERVER_DATA()") CROWD_CONTROL_SERVER_DATA sEmpty sCrowdControlData = sEmpty ENDPROC PROC RESET_CROWD_CONTROL_LOCAL_DATA( CROWD_CONTROL_LOCAL_DATA &sLocalData ) CPRINTLN(DEBUG_NET_MINIGAME, "RESET_CROWD_CONTROL_LOCAL_DATA()") CROWD_CONTROL_LOCAL_DATA sEmpty sEmpty.iSFXAlarms[0] = -1 sEmpty.iSFXAlarms[1] = -1 sLocalData = sEmpty ENDPROC PROC RESET_CROWD_CONTROL_PED_DECOR_DATA(CROWD_CONTROL_PED_DECORATOR_DATA &sPedDecorData[] ) CPRINTLN(DEBUG_NET_MINIGAME, "RESET_CROWD_CONTROL_PED_DECOR_DATA()") CROWD_CONTROL_PED_DECORATOR_DATA sEmpty INT i REPEAT COUNT_OF(sPedDecorData) i sPedDecorData[i] = sEmpty ENDREPEAT ENDPROC PROC RESET_CROWD_CONTROL_LOCAL_PED_DATA( CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[] ) CPRINTLN(DEBUG_NET_MINIGAME, "RESET_CROWD_CONTROL_LOCAL_PED_DATA()") CROWD_CONTROL_LOCAL_PED_DATA sEmpty INT i REPEAT COUNT_OF(sLocalPedData) i sLocalPedData[i] = sEmpty ENDREPEAT ENDPROC PROC CLEANUP_CROWD_CONTROL_MINIGAME( CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[] ) CPRINTLN(DEBUG_NET_MINIGAME, "CLEANUP_CROWD_CONTROL_MINIGAME()") INT i IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_Initialised ) REPEAT COUNT_OF( sLocalData.iSFXAlarms ) i IF sLocalData.iSFXAlarms[i] != -1 IF NOT HAS_SOUND_FINISHED( sLocalData.iSFXAlarms[i] ) STOP_SOUND( sLocalData.iSFXAlarms[i] ) ENDIF sLocalData.iSFXAlarms[i] = -1 ENDIF ENDREPEAT REPEAT COUNT_OF( sLocalPedData ) i IF DOES_ENTITY_EXIST( sLocalPedData[i].objProp ) DELETE_OBJECT( sLocalPedData[i].objProp ) ENDIF INT j REPEAT CCSEQ_NUM_SEQUENCES j IF sLocalPedData[i].seqs[j] != NULL CLEAR_SEQUENCE_TASK( sLocalPedData[i].seqs[j] ) ENDIF ENDREPEAT ENDREPEAT ENDIF ENDPROC // Debug procs/funcs //---------------------------------------------------------------------------- #IF IS_DEBUG_BUILD PROC SETUP_CROWD_CONTROL_DEBUG( CROWD_CONTROL_SERVER_DATA &sServerData, CROWD_CONTROL_LOCAL_DATA &sLocalData ) START_WIDGET_GROUP( "Crowd Control" ) ADD_BIT_FIELD_WIDGET( "Server bitset", sServerData.iBitSet ) ADD_BIT_FIELD_WIDGET( "Local bitset", sLocalData.iBitSet ) START_WIDGET_GROUP( "Fear" ) ADD_WIDGET_FLOAT_SLIDER( "FearIncreaseRateMin", cfCC_FearIncreaseRateMin, 0.0, 20.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "FearIncreaseRateMax", cfCC_FearIncreaseRateMax, 0.0, 20.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "FearDecreaseRateMin", cfCC_FearDecreaseRateMin, 0.0, 20.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "FearDecreaseRateMax", cfCC_FearDecreaseRateMax, 0.0, 20.0, 0.1 ) STOP_WIDGET_GROUP() START_WIDGET_GROUP( "Beatdown" ) ADD_WIDGET_FLOAT_SLIDER( "Distance Min", cfCC_BeatdownDistMin, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Distance Max", cfCC_BeatdownDistMax, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Long Anim Dist", cfCC_BeatdownLongAnimDistThreshold, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Standard Melee Disable Dist", cfCC_BeatdownMeleeDisableDist, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Facing Angle Change Dist Min", cfCC_BeatdownFacingAngleChangeDistMin, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Facing Angle Change Dist Max", cfCC_BeatdownFacingAngleChangeDistMax, 0.0, 10.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Facing Angle Min", cfCC_BeatdownFacingAngleRangeMin, 0.0, 360.0, 0.1 ) ADD_WIDGET_FLOAT_SLIDER( "Facing Angle Max", cfCC_BeatdownFacingAngleRangeMax, 0.0, 360.0, 0.1 ) STOP_WIDGET_GROUP() START_WIDGET_GROUP( "Debug Display" ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColNormalR", ciCC_DebugColNormalR, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColNormalG", ciCC_DebugColNormalG, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColNormalB", ciCC_DebugColNormalB, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColWarningR", ciCC_DebugColWarningR, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColWarningG", ciCC_DebugColWarningG, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColWarningB", ciCC_DebugColWarningB, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColActiveR", ciCC_DebugColActiveR, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColActiveG", ciCC_DebugColActiveG, 0, 255, 1 ) ADD_WIDGET_INT_SLIDER( "ciCC_DebugColActiveB", ciCC_DebugColActiveB, 0, 255, 1 ) STOP_WIDGET_GROUP() STOP_WIDGET_GROUP() ENDPROC FUNC STRING GET_CROWD_CONTROL_PED_STATE_STRING( CROWD_CONTROL_PED_STATE eState ) SWITCH eState CASE CCPS_INVALID RETURN "CCPS_INVALID" BREAK CASE CCPS_INTRO RETURN "CCPS_INTRO" BREAK CASE CCPS_COWER RETURN "CCPS_COWER" BREAK CASE CCPS_FLINCH RETURN "CCPS_FLINCH" BREAK CASE CCPS_FLINCH_UNDERFIRE RETURN "CCPS_FLINCH_UNDERFIRE" BREAK CASE CCPS_BEATDOWN RETURN "CCPS_BEATDOWN" BREAK CASE CCPS_HERO_ATTEMPT RETURN "CCPS_HERO_ATTEMPT" BREAK CASE CCPS_HERO RETURN "CCPS_HERO" BREAK CASE CCPS_COMBAT RETURN "CCPS_COMBAT" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_PED_ANIM_ENUM_NAME( CROWD_CONTROL_PED_ANIM_TYPE eAnim ) SWITCH eAnim CASE CCPANIM_INTRO_LOOP RETURN "CCPANIM_INTRO_LOOP" BREAK CASE CCPANIM_INTRO RETURN "CCPANIM_INTRO" BREAK CASE CCPANIM_COWER_LOOP RETURN "CCPANIM_COWER_LOOP" BREAK CASE CCPANIM_COWER_TO_FLINCH_INTRO RETURN "CCPANIM_COWER_TO_FLINCH_INTRO" BREAK CASE CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO RETURN "CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO" BREAK CASE CCPANIM_FLINCH_LOOP RETURN "CCPANIM_FLINCH_LOOP" BREAK CASE CCPANIM_FLINCH_TO_IDLE_OUTRO RETURN "CCPANIM_FLINCH_TO_IDLE_OUTRO" BREAK CASE CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO RETURN "CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO" BREAK CASE CCPANIM_FLINCH_UNDERFIRE_LOOP RETURN "CCPANIM_FLINCH_UNDERFIRE_LOOP" BREAK CASE CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO RETURN "CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO" BREAK CASE CCPANIM_BEATDOWN_INTRO RETURN "CCPANIM_BEATDOWN_INTRO" BREAK CASE CCPANIM_BEATDOWN_LOOP RETURN "CCPANIM_BEATDOWN_LOOP" BREAK CASE CCPANIM_BEATDOWN_HIT_A RETURN "CCPANIM_BEATDOWN_HIT_A" BREAK CASE CCPANIM_BEATDOWN_HIT_B RETURN "CCPANIM_BEATDOWN_HIT_B" BREAK CASE CCPANIM_BEATDOWN_DIE RETURN "CCPANIM_BEATDOWN_DIE" BREAK CASE CCPANIM_BEATDOWN_DIE_LOOP RETURN "CCPANIM_BEATDOWN_DIE_LOOP" BREAK CASE CCPANIM_HERO_START RETURN "CCPANIM_HERO_START" BREAK CASE CCPANIM_HERO_LOOP RETURN "CCPANIM_HERO_LOOP" BREAK CASE CCPANIM_HERO_PASS RETURN "CCPANIM_HERO_PASS" BREAK CASE CCPANIM_HERO_FAIL RETURN "CCPANIM_HERO_FAIL" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( CROWD_CONTROL_PED_ENUM eCrowdPedAnimID ) SWITCH eCrowdPedAnimID CASE CCPED_CASHIER_A RETURN "Cashier A" BREAK CASE CCPED_CASHIER_B RETURN "Cashier B" BREAK CASE CCPED_CUSTOMER_A RETURN "Ped A" BREAK CASE CCPED_CUSTOMER_B RETURN "Ped B" BREAK CASE CCPED_CUSTOMER_C RETURN "Ped C" BREAK CASE CCPED_CUSTOMER_D RETURN "Ped D" BREAK CASE CCPED_CUSTOMER_E RETURN "Ped E" BREAK CASE CCPED_CUSTOMER_F RETURN "Ped F" BREAK CASE CCPED_CUSTOMER_G RETURN "Ped G" BREAK CASE CCPED_CUSTOMER_H RETURN "Ped H" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_THREAT_TYPE_STRING( CROWD_CONTROL_THREAT_TYPE eThreat ) SWITCH eThreat CASE CCTHREAT_NONE RETURN "CCTHREAT_NONE" BREAK CASE CCTHREAT_PROXIMITY RETURN "CCTHREAT_PROXIMITY" BREAK CASE CCTHREAT_SHOUTING RETURN "CCTHREAT_SHOUTING" BREAK CASE CCTHREAT_SHOUTING_CLOSE RETURN "CCTHREAT_SHOUTING_CLOSE" BREAK CASE CCTHREAT_BEATING_NEIGHBOUR RETURN "CCTHREAT_BEATING_NEIGHBOUR" BREAK CASE CCTHREAT_KILLED_OTHER RETURN "CCTHREAT_KILLED_OTHER" BREAK CASE CCTHREAT_AIMED_AT RETURN "CCTHREAT_AIMED_AT" BREAK CASE CCTHREAT_BEATING RETURN "CCTHREAT_BEATING" BREAK CASE CCTHREAT_SHOOTING RETURN "CCTHREAT_SHOOTING" BREAK CASE CCTHREAT_PROJECTILE_EXPLOSIVE RETURN "CCTHREAT_PROJECTILE_EXPLOSIVE" BREAK CASE CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB RETURN "CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB" BREAK CASE CCTHREAT_SHOOTING_CLOSE RETURN "CCTHREAT_SHOOTING_CLOSE" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_HEIST_TYPE_STRING( CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_NORMAL RETURN "CCHEIST_NORMAL" BREAK CASE CCHEIST_CUSTOM_FLEECA RETURN "CCHEIST_CUSTOM_FLEECA" BREAK CASE CCHEIST_CUSTOM_ORNATE RETURN "CCHEIST_CUSTOM_ORNATE" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_HERO_ACTION( CROWD_CONTROL_PED_HERO_ACTION eHeroAction ) SWITCH eHeroAction CASE CCHERO_NONE RETURN "CCHERO_NONE" BREAK CASE CCHERO_ALARM RETURN "CCHERO_ALARM" BREAK CASE CCHERO_PHONE RETURN "CCHERO_PHONE" BREAK CASE CCHERO_GUN RETURN "CCHERO_GUN" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_FAIL_REASON_STRING( CROWD_CONTROL_FAIL_REASON eFailReason ) SWITCH eFailReason CASE CCFAIL_NONE RETURN "CCFAIL_NONE" BREAK CASE CCFAIL_PEDKILLED RETURN "CCFAIL_PEDKILLED" BREAK CASE CCFAIL_PEDSKILLED RETURN "CCFAIL_PEDSKILLED" BREAK CASE CCFAIL_PEDHEROALARM RETURN "CCFAIL_PEDHEROALARM" BREAK CASE CCFAIL_PEDHEROPHONE RETURN "CCFAIL_PEDHEROPHONE" BREAK CASE CCFAIL_PEDHEROGUN RETURN "CCFAIL_PEDHEROGUN" BREAK CASE CCFAIL_FEARLOW RETURN "CCFAIL_FEARLOW" BREAK CASE CCFAIL_TOOMANYKNOCKOUTS RETURN "CCFAIL_TOOMANYKNOCKOUTS" BREAK CASE CCFAIL_NOHITSREMAINING RETURN "CCFAIL_NOHITSREMAINING" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( CROWD_CONTROL_DIALOGUE eDialogue ) SWITCH eDialogue CASE CCDIA_NONE RETURN "CCDIA_NONE" BREAK CASE CCDIA_APPROACH RETURN "CCDIA_APPROACH" BREAK CASE CCDIA_ALARM_GOES_OFF RETURN "CCDIA_ALARM_GOES_OFF" BREAK CASE CCDIA_ALARM_GOES_OFF_INITIAL RETURN "CCDIA_ALARM_GOES_OFF_INITIAL" BREAK CASE CCDIA_COWER_HIGH_FEAR RETURN "CCDIA_COWER_HIGH_FEAR" BREAK CASE CCDIA_COWER_LOW_FEAR RETURN "CCDIA_COWER_LOW_FEAR" BREAK CASE CCDIA_HERO_ALARM_CAUGHT RETURN "CCDIA_HERO_ALARM_CAUGHT" BREAK CASE CCDIA_HERO_ALARM_COMPLETE RETURN "CCDIA_HERO_ALARM_COMPLETE" BREAK CASE CCDIA_HERO_ALARM_START RETURN "CCDIA_HERO_ALARM_START" BREAK CASE CCDIA_HERO_GUN_CAUGHT RETURN "CCDIA_HERO_GUN_CAUGHT" BREAK CASE CCDIA_HERO_GUN_COMPLETE RETURN "CCDIA_HERO_GUN_COMPLETE" BREAK CASE CCDIA_HERO_GUN_START RETURN "CCDIA_HERO_GUN_START" BREAK CASE CCDIA_HERO_PHONE_CAUGHT RETURN "CCDIA_HERO_PHONE_CAUGHT" BREAK CASE CCDIA_HERO_PHONE_COMPLETE RETURN "CCDIA_HERO_PHONE_COMPLETE" BREAK CASE CCDIA_HERO_PHONE_START RETURN "CCDIA_HERO_PHONE_START" BREAK CASE CCDIA_HERO_PHONE_APOLOGISE RETURN "CCDIA_HERO_PHONE_APOLOGISE" BREAK CASE CCDIA_INITIAL_PANIC RETURN "CCDIA_INITIAL_PANIC" BREAK CASE CCDIA_RECEIVES_SCARE RETURN "CCDIA_RECEIVES_SCARE" BREAK CASE CCDIA_SEES_OTHER_KILLED RETURN "CCDIA_SEES_OTHER_KILLED" BREAK CASE CCDIA_SHOT_NEAR RETURN "CCDIA_SHOT_NEAR" BREAK CASE CCDIA_SHOT_DIRECTLY_AT RETURN "CCDIA_SHOT_DIRECTLY_AT" BREAK CASE CCDIA_STICKS_UP_FOR_OTHER RETURN "CCDIA_STICKS_UP_FOR_OTHER" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_SEQUENCE_NAME( CROWD_CONTROL_SEQUENCES eSeq ) SWITCH eSeq CASE CCSEQ_BEATDOWN_TO_FLINCH RETURN "CCSEQ_BEATDOWN_TO_FLINCH" BREAK CASE CCSEQ_COWER_TO_FLINCH RETURN "CCSEQ_COWER_TO_FLINCH" BREAK CASE CCSEQ_COWER_TO_FLINCH_UNDERFIRE RETURN "CCSEQ_COWER_TO_FLINCH_UNDERFIRE" BREAK CASE CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE RETURN "CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE" BREAK CASE CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH RETURN "CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH" BREAK CASE CCSEQ_FLINCH_TO_COWER RETURN "CCSEQ_FLINCH_TO_COWER" BREAK CASE CCSEQ_HERO_FAIL RETURN "CCSEQ_HERO_FAIL" BREAK CASE CCSEQ_HERO_PASS RETURN "CCSEQ_HERO_PASS" BREAK CASE CCSEQ_HERO_START RETURN "CCSEQ_HERO_START" BREAK CASE CCSEQ_NUM_SEQUENCES RETURN "CCSEQ_NUM_SEQUENCES" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_DEBUG_NAME( CROWD_CONTROL_DEBUG_DISPLAY eDebug ) SWITCH eDebug CASE CCDEBUG_OFF RETURN "OFF" BREAK CASE CCDEBUG_ALL RETURN "ALL" BREAK CASE CCDEBUG_BASIC RETURN "BASIC" BREAK CASE CCDEBUG_FEAR_AND_THREATS RETURN "FEAR & THREATS" BREAK CASE CCDEBUG_HERO RETURN "HERO" BREAK CASE CCDEBUG_BEATDOWNS RETURN "BEATDOWNS" BREAK CASE CCDEBUG_DIALOGUE RETURN "DIALOGUE" BREAK CASE CCDEBUG_MISC RETURN "MISC" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC FUNC STRING GET_CROWD_CONTROL_DEBUG_ENUM_NAME( CROWD_CONTROL_DEBUG_DISPLAY eDebug ) SWITCH eDebug CASE CCDEBUG_OFF RETURN "CCDEBUG_OFF" BREAK CASE CCDEBUG_ALL RETURN "CCDEBUG_ALL" BREAK CASE CCDEBUG_BASIC RETURN "CCDEBUG_BASIC" BREAK CASE CCDEBUG_FEAR_AND_THREATS RETURN "CCDEBUG_FEAR_AND_THREATS" BREAK CASE CCDEBUG_HERO RETURN "CCDEBUG_HERO" BREAK CASE CCDEBUG_BEATDOWNS RETURN "CCDEBUG_BEATDOWNS" BREAK CASE CCDEBUG_DIALOGUE RETURN "CCDEBUG_DIALOGUE" BREAK CASE CCDEBUG_MISC RETURN "CCDEBUG_MISC" BREAK ENDSWITCH RETURN "no debug name" ENDFUNC #ENDIF FUNC STRING GET_CROWD_CONTROL_PED_DECOR_NAME( CROWD_CONTROL_PED_DECORATOR eDecor ) SWITCH eDecor CASE CCPDECOR_iState RETURN "CC_iState" BREAK CASE CCPDECOR_iStatePrev RETURN "CC_iStatePrev" BREAK CASE CCPDECOR_iBitSet RETURN "CC_iBitSet" BREAK CASE CCPDECOR_fInfluenceDirectThreat RETURN "CC_fInfluenceDirectThreat" BREAK CASE CCPDECOR_fInfluenceShouting RETURN "CC_fInfluenceShouting" BREAK CASE CCPDECOR_iBeatdownHitsRemaining RETURN "CC_iBeatdownHitsRemaining" BREAK CASE CCPDECOR_iBeatdownRounds RETURN "CC_iBeatdownRounds" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC INTERIOR_INSTANCE_INDEX GET_CROWD_CONTROL_HEIST_INTERIOR( CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_NORMAL RETURN NULL BREAK CASE CCHEIST_CUSTOM_FLEECA RETURN GET_INTERIOR_AT_COORDS_WITH_TYPE( <<-2962.8086, 482.2888, 14.7081>>, "hei_generic_bank_dlc" ) // v_genbank BREAK CASE CCHEIST_CUSTOM_ORNATE RETURN GET_INTERIOR_AT_COORDS_WITH_TYPE( <<235.9299, 216.6042, 105.2867>>, "hei_heist_ornate_bank" ) // v_bank BREAK ENDSWITCH RETURN NULL ENDFUNC FUNC BOOL HAS_PED_ENTERED_CROWD_CONTROL_TRIGGER_ZONE( PED_INDEX ped, CROWD_CONTROL_LOCAL_DATA &sLocalData, BOOL bSoftTrigger ) BOOL bInsideInterior = ( sLocalData.interiorHeist = GET_INTERIOR_FROM_ENTITY( ped ) ) IF NOT bSoftTrigger // HARD TRIGGER - the actual trigger we go off for triggering the crowd to kick off SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA // If inside the bank or near the bank doors IF bInsideInterior RETURN TRUE // In a car near the doors ELIF IS_PED_IN_ANY_VEHICLE( ped ) VEHICLE_INDEX veh veh = GET_VEHICLE_PED_IS_IN( ped ) IF HAS_ENTITY_COLLIDED_WITH_ANYTHING( veh ) AND IS_ENTITY_IN_ANGLED_AREA( ped, <<-2967.208496,481.097839,14.468699>>, <<-2967.038574,484.783356,17.786673>>, 3.062500 ) RETURN TRUE ENDIF ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE // Player is inside the interior and main bank room // Additional area check to make sure the player has fulled walked into the room IF bInsideInterior AND GET_ROOM_KEY_FROM_ENTITY( ped ) = HASH( "Bank_MainRm" ) // revised locate size for bug 2093267 AND IS_ENTITY_IN_ANGLED_AREA( ped, <<259.844116,215.006775,105.288048>>, <<237.827515,222.779510,109.395790>>, 11.500000 ) //AND IS_ENTITY_IN_ANGLED_AREA( ped, <<259.546387,214.301697,105.286835>>, <<238.274490,222.332184,109.029305>>, 10.687500 ) RETURN TRUE ENDIF BREAK ENDSWITCH ELSE // SOFT TRIGGER - just outside the hard trigger area, this is used to check for the player shouting SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA // Inside the bank IF bInsideInterior OR IS_ENTITY_IN_ANGLED_AREA( ped, <<-2965.820801,482.966461,14.635263>>, <<-2967.116699,483.018555,17.441607>>, 3.562500 ) RETURN TRUE ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE // Inside the bank in the main room, not the little area by the door IF bInsideInterior AND GET_ROOM_KEY_FROM_ENTITY( ped ) = HASH( "Bank_MainRm" ) RETURN TRUE ENDIF BREAK ENDSWITCH ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAS_TEAM_PASSED_CROWD_CONTROL_RULE( CROWD_CONTROL_LOCAL_DATA &sLocalData, INT &iCurrentHighestPriority, INT iTeam ) IF sLocalData.iCCRule[iTeam] != -1 AND sLocalData.iCCRule[iTeam] < FMMC_MAX_RULES AND iCurrentHighestPriority <= sLocalData.iCCRule[iTeam] RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAVE_ALL_PLAYERS_PASSED_CROWD_CONTROL_RULE( CROWD_CONTROL_LOCAL_DATA &sLocalData, INT &iCurrentHighestPriority[], INT iLocalPlayersTeam ) BOOL bAllPassedRule bAllPassedRule = TRUE INT iTeam FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 IF NOT IS_FAKE_MULTIPLAYER_MODE_SET() OR iTeam = iLocalPlayersTeam IF HAS_TEAM_PASSED_CROWD_CONTROL_RULE( sLocalData, iCurrentHighestPriority[iTeam], iTeam ) bAllPassedRule = FALSE ENDIF ENDIF ENDFOR RETURN bAllPassedRule ENDFUNC FUNC BOOL SHOULD_DISABLE_CROWD_CONTROL_FAIL( CROWD_CONTROL_LOCAL_DATA &sLocalData, INT &iCurrentHighestPriority[], INT iLocalPlayersTeam ) IF g_bMissionEnding RETURN TRUE ELSE SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA // Fleeca never disables the fail RETURN FALSE BREAK CASE CCHEIST_CUSTOM_ORNATE // If we have passed the crowd control objective for all teams, disable the fail RETURN HAVE_ALL_PLAYERS_PASSED_CROWD_CONTROL_RULE( sLocalData, iCurrentHighestPriority, iLocalPlayersTeam ) BREAK ENDSWITCH ENDIF RETURN FALSE ENDFUNC FUNC BOOL SHOULD_PLAYER_PLAY_CROWD_CONTROL_CUTSCENE( PED_INDEX pedPlayer, CROWD_CONTROL_LOCAL_DATA &sLocalData, INT &iCurrentHighestPriority[], INT iLocalPlayersTeam ) INT iTeam SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA IF NOT HAVE_ALL_PLAYERS_PASSED_CROWD_CONTROL_RULE( sLocalData, iCurrentHighestPriority, iLocalPlayersTeam ) IF GET_INTERIOR_FROM_ENTITY( pedPlayer ) = sLocalData.interiorHeist OR GET_DISTANCE_BETWEEN_ENTITY_AND_COORD( pedPlayer, <<-2962.8086, 482.2888, 14.7081>> ) < 50.0 RETURN TRUE ENDIF ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 // Before or while the crowd control rule is active IF sLocalData.iCCRule[iTeam] != -1 AND sLocalData.iCCRule[iTeam] < FMMC_MAX_RULES AND iCurrentHighestPriority[iTeam] <= sLocalData.iCCRule[iTeam] // Only those in the bank lobby area for ORNATE IF GET_INTERIOR_FROM_ENTITY( pedPlayer ) = sLocalData.interiorHeist INT iRoomHash iRoomHash = GET_ROOM_KEY_FROM_ENTITY( pedPlayer ) IF iRoomHash = HASH( "Bank_MainRm" ) OR iRoomHash = HASH( "Bank_CashierRm" ) OR iRoomHash = HASH( "Bank_Lobby" ) OR iRoomHash = HASH( "Bank_ATMS" ) OR iRoomHash = HASH( "Bank_Vestibule" ) OR iRoomHash = HASH( "Bank_Upperhall1" ) OR iRoomHash = HASH( "Bank_Upperhall2" ) RETURN TRUE ENDIF ENDIF ENDIF ENDFOR BREAK ENDSWITCH RETURN FALSE ENDFUNC FUNC INT GET_CROWD_CONTROL_NUMBER_OF_DEAD_PEDS_WITH_PED_ID( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_SERVER_DATA &sServerData, INT &iOptionalDeadPedID ) INT iCount iOptionalDeadPedID = -1 INT i FOR i = 0 TO sServerData.iNumCrowdControlPeds-1 // Count the number of dead peds IF IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_Dead ) AND NOT IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_KnockedOut ) IF iOptionalDeadPedID = -1 iOptionalDeadPedID = sServerData.iCrowdControlCloudIndex[i] ENDIF iCount++ ENDIF ENDFOR RETURN iCount ENDFUNC FUNC INT GET_CROWD_CONTROL_NUMBER_OF_DEAD_PEDS( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_SERVER_DATA &sServerData ) INT iDummy RETURN GET_CROWD_CONTROL_NUMBER_OF_DEAD_PEDS_WITH_PED_ID( sPedData, sServerData, iDummy ) ENDFUNC FUNC INT GET_CROWD_CONTROL_NUMBER_OF_KNOCKED_OUT_PEDS_WITH_PED_ID( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_SERVER_DATA &sServerData, INT &iOptionalKnockedOutPedID ) INT iCount iOptionalKnockedOutPedID = -1 INT i FOR i = 0 TO sServerData.iNumCrowdControlPeds-1 // Count the number of knocked out peds IF IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_KnockedOut ) IF iOptionalKnockedOutPedID = -1 iOptionalKnockedOutPedID = sServerData.iCrowdControlCloudIndex[i] ENDIF iCount++ ENDIF ENDFOR RETURN iCount ENDFUNC FUNC INT GET_CROWD_CONTROL_NUMBER_OF_KNOCKED_OUT_PEDS( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_SERVER_DATA &sServerData ) INT iDummy RETURN GET_CROWD_CONTROL_NUMBER_OF_KNOCKED_OUT_PEDS_WITH_PED_ID( sPedData, sServerData, iDummy ) ENDFUNC FUNC INT GET_CROWD_CONTROL_PED_DEAD_LIMIT( CROWD_CONTROL_HEIST_TYPE eHeistType ) INT iResult SWITCH eHeistType CASE CCHEIST_CUSTOM_ORNATE iResult = 1 BREAK DEFAULT iResult = 0 BREAK ENDSWITCH RETURN iResult ENDFUNC FUNC FLOAT GET_CROWD_CONTROL_PED_ESCAPED_DISTANCE( CROWD_CONTROL_HEIST_TYPE eHeistType ) UNUSED_PARAMETER( eHeistType ) RETURN 20.0 ENDFUNC FUNC INT GET_CROWD_CONTROL_FAIL_CUTSCENE( CROWD_CONTROL_HEIST_TYPE eHeistType, NETWORK_INDEX &niPeds[], INT &iCrowdCloudIndex[], CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[], INT iNumCrowdControlPeds, TEXT_LABEL_63 &tlCutsceneNameOut, CUTSCENE_SECTION &eCutsceneSectionOut ) INT i BOOL bDeadCashierA, bDeadCashierB FOR i = 0 TO iNumCrowdControlPeds-1 IF sLocalPedData[i].eCreatorAssignedPedID = CCPED_CASHIER_A OR sLocalPedData[i].eCreatorAssignedPedID = CCPED_CASHIER_B IF NOT NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPeds[iCrowdCloudIndex[i]] ) OR IS_PED_INJURED( NET_TO_PED( niPeds[iCrowdCloudIndex[i]] ) ) IF sLocalPedData[i].eCreatorAssignedPedID = CCPED_CASHIER_A bDeadCashierA = TRUE ELIF sLocalPedData[i].eCreatorAssignedPedID = CCPED_CASHIER_B bDeadCashierB = TRUE ENDIF ENDIF ENDIF ENDFOR SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA IF NOT bDeadCashierA tlCutsceneNameOut = "MPH_TUT_MCS1" eCutsceneSectionOut = INT_TO_ENUM( CUTSCENE_SECTION, -1 ) ELSE // cashier dead bail on cutscene tlCutsceneNameOut = "" ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE IF NOT bDeadCashierA tlCutsceneNameOut = "MPH_PAC_FIN_MCS2" eCutsceneSectionOut = CS_SECTION_1 ELIF NOT bDeadCashierB tlCutsceneNameOut = "MPH_PAC_FIN_MCS2" eCutsceneSectionOut = CS_SECTION_2 ELSE // both dead bail on cutscene tlCutsceneNameOut = "" ENDIF BREAK ENDSWITCH // Create hash for comparison TEXT_LABEL_63 tlTemp tlTemp = tlCutsceneNameOut tlTemp += ENUM_TO_INT( eCutsceneSectionOut ) RETURN GET_HASH_KEY( tlTemp ) ENDFUNC FUNC BOOL GET_CROWD_CONTROL_FAIL_CUTSCENE_FROM_HASH( INT iHashIn, TEXT_LABEL_63 &tlName, CUTSCENE_SECTION &eSection ) TEXT_LABEL_63 tlTemp tlTemp = "MPH_TUT_MCS1" tlTemp += -1 IF iHashIn = GET_HASH_KEY( tlTemp ) tlName = "MPH_TUT_MCS1" eSection = INT_TO_ENUM( CUTSCENE_SECTION, -1 ) RETURN TRUE ENDIF tlTemp = "MPH_PAC_FIN_MCS2" tlTemp += ENUM_TO_INT( CS_SECTION_1 ) IF iHashIn = GET_HASH_KEY( tlTemp ) tlName = "MPH_PAC_FIN_MCS2" eSection = CS_SECTION_1 RETURN TRUE ENDIF tlTemp = "MPH_PAC_FIN_MCS2" tlTemp += ENUM_TO_INT( CS_SECTION_2 ) IF iHashIn = GET_HASH_KEY( tlTemp ) tlName = "MPH_PAC_FIN_MCS2" eSection = CS_SECTION_2 RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL GET_CROWD_CONTROL_PED_DETAILS_FOR_FAIL_CUTSCENE_FROM_HASH( INT iHashIn, NETWORK_INDEX &niPeds[], INT &iCrowdCloudIndex[], CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[], INT iNumCrowdControlPeds, PED_INDEX &pedOut, TEXT_LABEL_63 &tlHandleOut, INT &iAnimEventHashAlarmOut ) TEXT_LABEL_63 tlCutsceneName CUTSCENE_SECTION eSection IF GET_CROWD_CONTROL_FAIL_CUTSCENE_FROM_HASH( iHashIn, tlCutsceneName, eSection ) TEXT_LABEL_63 tlHandleTemp INT iAnimEventHashAlarmTemp PED_INDEX pedTemp CROWD_CONTROL_PED_ENUM ePedWanted // Find the handle name and the ped enum IF ARE_STRINGS_EQUAL( tlCutsceneName, "MPH_TUT_MCS1" ) tlHandleTemp = "Cashier" ePedWanted = CCPED_CASHIER_A iAnimEventHashAlarmTemp = HASH( "GET_HYPE" ) ELIF ARE_STRINGS_EQUAL( tlCutsceneName, "MPH_PAC_FIN_MCS2" ) SWITCH eSection CASE CS_SECTION_1 ePedWanted = CCPED_CASHIER_A tlHandleTemp = "Bank_Teller_02" iAnimEventHashAlarmTemp = HASH( "GET_HYPE1" ) BREAK CASE CS_SECTION_2 ePedWanted = CCPED_CASHIER_B tlHandleTemp = "Bank_Teller_01" iAnimEventHashAlarmTemp = HASH( "GET_HYPE2" ) BREAK ENDSWITCH ENDIF // Find the ped ID INT i FOR i = 0 TO iNumCrowdControlPeds-1 IF sLocalPedData[i].eCreatorAssignedPedID = ePedWanted IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPeds[iCrowdCloudIndex[i]] ) pedTemp = NET_TO_PED( niPeds[iCrowdCloudIndex[i]] ) i = FMMC_MAX_CROWD_PEDS // break the loop ENDIF ENDIF ENDFOR IF NOT IS_STRING_NULL_OR_EMPTY( tlHandleTemp ) AND iAnimEventHashAlarmTemp != 0 AND DOES_ENTITY_EXIST( pedTemp ) tlHandleOut = tlHandleTemp iAnimEventHashAlarmOut = iAnimEventHashAlarmTemp pedOut = pedTemp RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC STRING GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType ) IF eHeistType = CCHEIST_CUSTOM_FLEECA SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A eCrowdControlAnimID = CCPED_CUSTOMER_D BREAK CASE CCPED_CUSTOMER_A eCrowdControlAnimID = CCPED_CUSTOMER_A BREAK CASE CCPED_CUSTOMER_B eCrowdControlAnimID = CCPED_CUSTOMER_E BREAK ENDSWITCH ENDIF // Common SWITCH eAnimType CASE CCPANIM_COWER_LOOP CASE CCPANIM_COWER_TO_FLINCH_INTRO CASE CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO CASE CCPANIM_FLINCH_LOOP CASE CCPANIM_FLINCH_TO_IDLE_OUTRO CASE CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO CASE CCPANIM_FLINCH_UNDERFIRE_LOOP CASE CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "anim@heists@ornate_bank@hostages@cashier_a@" BREAK CASE CCPED_CASHIER_B RETURN "anim@heists@ornate_bank@hostages@cashier_b@" BREAK CASE CCPED_CUSTOMER_A RETURN "anim@heists@ornate_bank@hostages@ped_a@" BREAK CASE CCPED_CUSTOMER_B RETURN "anim@heists@ornate_bank@hostages@ped_b@" BREAK CASE CCPED_CUSTOMER_C RETURN "anim@heists@ornate_bank@hostages@ped_c@" BREAK CASE CCPED_CUSTOMER_D IF eHeistType = CCHEIST_CUSTOM_FLEECA RETURN "anim@heists@fleeca_bank@hostages@ped_d@" ELSE RETURN "anim@heists@ornate_bank@hostages@ped_d@" ENDIF BREAK CASE CCPED_CUSTOMER_E RETURN "anim@heists@ornate_bank@hostages@ped_e@" BREAK CASE CCPED_CUSTOMER_F RETURN "anim@heists@ornate_bank@hostages@ped_f@" BREAK CASE CCPED_CUSTOMER_G RETURN "anim@heists@ornate_bank@hostages@ped_g@" BREAK CASE CCPED_CUSTOMER_H RETURN "anim@heists@ornate_bank@hostages@ped_h@" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_INTRO CASE CCPANIM_BEATDOWN_LOOP CASE CCPANIM_BEATDOWN_HIT_A CASE CCPANIM_BEATDOWN_HIT_B CASE CCPANIM_BEATDOWN_DIE CASE CCPANIM_BEATDOWN_DIE_LOOP CASE CCPANIM_BEATDOWN_OUTRO RETURN "anim@heists@ornate_bank@hostages@hit" BREAK ENDSWITCH // heist specific SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH eAnimType CASE CCPANIM_INTRO_LOOP CASE CCPANIM_INTRO RETURN "anim@heists@fleeca_bank@hostages@intro" BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH eAnimType CASE CCPANIM_INTRO_LOOP CASE CCPANIM_INTRO RETURN "anim@heists@ornate_bank@hostages@intro" BREAK CASE CCPANIM_HERO_START CASE CCPANIM_HERO_LOOP CASE CCPANIM_HERO_PASS CASE CCPANIM_HERO_FAIL SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "anim@heists@ornate_bank@hostages@cashier_a@" BREAK CASE CCPED_CUSTOMER_B RETURN "anim@heists@ornate_bank@hostages@ped_b@" BREAK CASE CCPED_CUSTOMER_C RETURN "anim@heists@ornate_bank@hostages@ped_c@" BREAK CASE CCPED_CUSTOMER_D RETURN "anim@heists@ornate_bank@hostages@ped_d@" BREAK CASE CCPED_CUSTOMER_G RETURN "anim@heists@ornate_bank@hostages@ped_g@" BREAK ENDSWITCH BREAK ENDSWITCH BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_PED_ANIM_NAME( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType ) IF eHeistType = CCHEIST_CUSTOM_FLEECA SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A eCrowdControlAnimID = CCPED_CUSTOMER_D BREAK CASE CCPED_CUSTOMER_A eCrowdControlAnimID = CCPED_CUSTOMER_A BREAK CASE CCPED_CUSTOMER_B eCrowdControlAnimID = CCPED_CUSTOMER_E BREAK ENDSWITCH ENDIF // Generic SWITCH eAnimType CASE CCPANIM_COWER_LOOP RETURN "idle" BREAK CASE CCPANIM_COWER_TO_FLINCH_INTRO RETURN "flinch_intro" BREAK CASE CCPANIM_FLINCH_LOOP RETURN "flinch_loop" BREAK CASE CCPANIM_FLINCH_TO_IDLE_OUTRO RETURN "flinch_outro" BREAK CASE CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO RETURN "flinch_under_fire_intro" BREAK CASE CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO SWITCH eCrowdControlAnimID CASE CCPED_CUSTOMER_B CASE CCPED_CUSTOMER_C CASE CCPED_CUSTOMER_D CASE CCPED_CUSTOMER_E CASE CCPED_CUSTOMER_F CASE CCPED_CUSTOMER_G CASE CCPED_CUSTOMER_H RETURN "flinch_to_underfire" BREAK ENDSWITCH BREAK CASE CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO SWITCH eCrowdControlAnimID CASE CCPED_CUSTOMER_B CASE CCPED_CUSTOMER_C CASE CCPED_CUSTOMER_D CASE CCPED_CUSTOMER_E CASE CCPED_CUSTOMER_F CASE CCPED_CUSTOMER_G CASE CCPED_CUSTOMER_H RETURN "flinch_under_fire_outro" BREAK ENDSWITCH BREAK CASE CCPANIM_FLINCH_UNDERFIRE_LOOP RETURN "flinch_loop_underfire" BREAK CASE CCPANIM_BEATDOWN_INTRO SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_intro_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_intro_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_intro_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_intro_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_intro_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_intro_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_intro_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_intro_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_intro_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_intro_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_LOOP SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_loop_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_loop_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_loop_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_loop_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_loop_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_loop_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_loop_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_loop_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_loop_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_loop_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_HIT_A SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_react_a_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_react_a_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_react_a_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_react_a_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_react_a_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_react_a_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_react_a_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_react_a_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_react_a_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_react_a_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_HIT_B SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_react_b_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_react_b_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_react_b_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_react_b_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_react_b_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_react_b_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_react_b_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_react_b_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_react_b_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_react_b_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_DIE SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_react_die_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_react_die_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_react_die_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_react_die_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_react_die_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_react_die_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_react_die_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_react_die_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_react_die_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_react_die_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_DIE_LOOP SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_react_die_loop_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_react_die_loop_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_react_die_loop_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_react_die_loop_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_react_die_loop_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_react_die_loop_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_react_die_loop_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_react_die_loop_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_react_die_loop_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_react_die_loop_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_BEATDOWN_OUTRO SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "hit_react_outro_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "hit_react_outro_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "hit_react_outro_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "hit_react_outro_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "hit_react_outro_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "hit_react_outro_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "hit_react_outro_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "hit_react_outro_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "hit_react_outro_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "hit_react_outro_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_HERO_START RETURN "reach" BREAK CASE CCPANIM_HERO_LOOP RETURN "reach_loop" BREAK CASE CCPANIM_HERO_PASS RETURN "pass" BREAK CASE CCPANIM_HERO_FAIL RETURN "fail" BREAK ENDSWITCH // Heist specific SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH eAnimType CASE CCPANIM_INTRO_LOOP SWITCH eCrowdControlAnimID CASE CCPED_CUSTOMER_D RETURN "intro_loop_ped_d" BREAK CASE CCPED_CUSTOMER_A RETURN "intro_loop_ped_a" BREAK CASE CCPED_CUSTOMER_E RETURN "intro_loop_ped_e" BREAK ENDSWITCH BREAK CASE CCPANIM_INTRO SWITCH eCrowdControlAnimID CASE CCPED_CUSTOMER_D RETURN "intro_standing_ped_d" BREAK // "intro_ped_d" CASE CCPED_CUSTOMER_A RETURN "intro_ped_a" BREAK CASE CCPED_CUSTOMER_E RETURN "intro_ped_e" BREAK ENDSWITCH BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH eAnimType CASE CCPANIM_INTRO_LOOP SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "intro_loop_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "intro_loop_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "intro_loop_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "intro_loop_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "intro_loop_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "intro_loop_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "intro_loop_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "intro_loop_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "intro_loop_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "intro_loop_ped_h" BREAK ENDSWITCH BREAK CASE CCPANIM_INTRO SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN "intro_cashier_a" BREAK CASE CCPED_CASHIER_B RETURN "intro_cashier_b" BREAK CASE CCPED_CUSTOMER_A RETURN "intro_ped_a" BREAK CASE CCPED_CUSTOMER_B RETURN "intro_ped_b" BREAK CASE CCPED_CUSTOMER_C RETURN "intro_ped_c" BREAK CASE CCPED_CUSTOMER_D RETURN "intro_ped_d" BREAK CASE CCPED_CUSTOMER_E RETURN "intro_ped_e" BREAK CASE CCPED_CUSTOMER_F RETURN "intro_ped_f" BREAK CASE CCPED_CUSTOMER_G RETURN "intro_ped_g" BREAK CASE CCPED_CUSTOMER_H RETURN "intro_ped_h" BREAK ENDSWITCH BREAK ENDSWITCH BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( CROWD_CONTROL_PLAYER_ANIM_TYPE eAnimType ) SWITCH eAnimType CASE CCPLAYERANIM_BEATDOWN_PISTOL_A CASE CCPLAYERANIM_BEATDOWN_PISTOL_B CASE CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A CASE CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B CASE CCPLAYERANIM_BEATDOWN_RIFLE_A CASE CCPLAYERANIM_BEATDOWN_RIFLE_B CASE CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A CASE CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B CASE CCPLAYERANIM_BEATDOWN_LONG_PISTOL_A CASE CCPLAYERANIM_BEATDOWN_LONG_PISTOL_KICK_A CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_A CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_B CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_A CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_B RETURN "anim@heists@ornate_bank@hostages@hit" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC STRING GET_CROWD_CONTROL_PLAYER_ANIM_NAME( CROWD_CONTROL_PLAYER_ANIM_TYPE eAnimType ) SWITCH eAnimType CASE CCPLAYERANIM_BEATDOWN_PISTOL_A RETURN "player_melee_pistol_a" BREAK CASE CCPLAYERANIM_BEATDOWN_PISTOL_B RETURN "player_melee_pistol_b" BREAK CASE CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A RETURN "player_melee_pistol_kick_a" BREAK CASE CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B RETURN "player_melee_pistol_kick_b" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_PISTOL_A RETURN "player_melee_long_pistol_a" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_PISTOL_KICK_A RETURN "player_melee_long_pistol_kick_a" BREAK CASE CCPLAYERANIM_BEATDOWN_RIFLE_A RETURN "player_melee_rifle_a" BREAK CASE CCPLAYERANIM_BEATDOWN_RIFLE_B RETURN "player_melee_rifle_b" BREAK CASE CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A RETURN "player_melee_rifle_kick_a" BREAK CASE CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B RETURN "player_melee_rifle_kick_b" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_A RETURN "player_melee_long_rifle_a" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_B RETURN "player_melee_long_rifle_b" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_A RETURN "player_melee_long_rifle_kick_a" BREAK CASE CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_B RETURN "player_melee_long_rifle_kick_b" BREAK ENDSWITCH RETURN "" ENDFUNC FUNC CROWD_CONTROL_PED_HERO_ACTION GET_CROWD_CONTROL_PED_HERO_ACTION_FOR_ANIMATED_PED( CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH eCrowdControlAnimID CASE CCPED_CASHIER_A RETURN CCHERO_ALARM BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH eCrowdControlAnimID // cashier A has a hero anim set CASE CCPED_CASHIER_A RETURN CCHERO_ALARM BREAK CASE CCPED_CUSTOMER_B RETURN CCHERO_GUN BREAK CASE CCPED_CUSTOMER_C RETURN CCHERO_PHONE BREAK CASE CCPED_CUSTOMER_D RETURN CCHERO_PHONE BREAK CASE CCPED_CUSTOMER_G RETURN CCHERO_GUN BREAK ENDSWITCH BREAK ENDSWITCH RETURN CCHERO_NONE ENDFUNC FUNC VECTOR GET_CROWD_CONTROL_PED_ANIM_SCENE_COORD( CROWD_CONTROL_HEIST_TYPE eHeistType, CROWD_CONTROL_PED_ANIM_TYPE eAnim ) SWITCH eHeistType // Fleeca uses an origin only for the intro loop and intro transition // after which the anims are played in place so no origin needed CASE CCHEIST_CUSTOM_FLEECA IF eAnim = CCPANIM_INTRO OR eAnim = CCPANIM_INTRO_LOOP RETURN << -2965.760, 484.220, 16.036 >> ENDIF BREAK // All ornate anims use the same origin CASE CCHEIST_CUSTOM_ORNATE IF eAnim = CCPANIM_INTRO OR eAnim = CCPANIM_INTRO_LOOP RETURN <<249.2121, 217.7811, 105.277>> ENDIF BREAK ENDSWITCH RETURN <<0,0,0>> ENDFUNC FUNC VECTOR GET_CROWD_CONTROL_PED_ANIM_SCENE_ROT( CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA RETURN <<0,0,-92.750>> BREAK CASE CCHEIST_CUSTOM_ORNATE RETURN <<0,0,-20>> BREAK ENDSWITCH RETURN <<0,0,0>> ENDFUNC FUNC BOOL DOES_CROWD_CONTROL_PED_HAVE_ANIM( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType ) IF NOT IS_STRING_NULL_OR_EMPTY( GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnimType, eCrowdControlAnimID, eHeistType ) ) AND NOT IS_STRING_NULL_OR_EMPTY( GET_CROWD_CONTROL_PED_ANIM_NAME( eAnimType, eCrowdControlAnimID, eHeistType ) ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_PED_PLAYING_ANIM( PED_INDEX ped, STRING strAnimDict, STRING strAnimName, BOOL bUseSyncSceneCheck = FALSE ) BOOL bRunning ANIM_TYPE eAnimType IF bUseSyncSceneCheck bRunning = IS_SCRIPT_TASK_RUNNING_OR_STARTING( ped, SCRIPT_TASK_SYNCHRONIZED_SCENE ) eAnimType = ANIM_SYNCED_SCENE ELSE bRunning = IS_SCRIPT_TASK_RUNNING_OR_STARTING( ped, SCRIPT_TASK_PLAY_ANIM ) OR IS_SCRIPT_TASK_RUNNING_OR_STARTING( ped, SCRIPT_TASK_PERFORM_SEQUENCE ) eAnimType = ANIM_DEFAULT ENDIF IF bRunning IF IS_ENTITY_PLAYING_ANIM( ped, strAnimDict, strAnimName, eAnimType ) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_PLAYING_ANIM( PED_INDEX ped, CROWD_CONTROL_PED_ANIM_TYPE eAnim, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType, BOOL bUseSyncSceneCheck = FALSE ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( eAnim, eCrowdControlAnimID, eHeistType ) STRING strAnimDict = GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, eCrowdControlAnimID, eHeistType ) STRING strAnimName = GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, eCrowdControlAnimID, eHeistType ) RETURN IS_PED_PLAYING_ANIM( ped, strAnimDict, strAnimName, bUseSyncSceneCheck ) ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( PED_INDEX ped, CROWD_CONTROL_PLAYER_ANIM_TYPE eAnim, BOOL bUseSyncSceneCheck = FALSE ) STRING strAnimDict = GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( eAnim ) STRING strAnimName = GET_CROWD_CONTROL_PLAYER_ANIM_NAME( eAnim ) RETURN IS_PED_PLAYING_ANIM( ped, strAnimDict, strAnimName, bUseSyncSceneCheck ) ENDFUNC FUNC BOOL HAS_PED_FINISHED_ANIM( PED_INDEX ped, STRING strAnimDict, STRING strAnimName, FLOAT fFinishPhase = 1.0, BOOL bUseSyncSceneCheck = FALSE, INT iNetSyncSceneID = -1, INT iAnimEndTagHash = 0 ) IF IS_PED_PLAYING_ANIM( ped, strAnimDict, strAnimName, bUseSyncSceneCheck ) BOOL bResult FLOAT fPhase IF bUseSyncSceneCheck IF iNetSyncSceneID = -1 SCRIPT_ASSERT( "HAS_PED_FINISHED_ANIM() - Invalid sync scene ID, iNetSyncSceneID = -1" ) ELSE INT iLocalSyncSceneID = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID( iNetSyncSceneID ) IF IS_SYNCHRONIZED_SCENE_RUNNING( iLocalSyncSceneID ) fPhase = GET_SYNCHRONIZED_SCENE_PHASE( iLocalSyncSceneID ) IF fPhase >= fFinishPhase bResult = TRUE ENDIF ENDIF ENDIF ELSE fPhase = GET_ENTITY_ANIM_CURRENT_TIME( ped, strAnimDict, strAnimName ) IF fPhase >= fFinishPhase bResult = TRUE ENDIF ENDIF IF iAnimEndTagHash != 0 AND HAS_ANIM_EVENT_FIRED( ped, iAnimEndTagHash ) CPRINTLN(DEBUG_NET_MINIGAME, "HAS_PED_FINISHED_ANIM() - ANIM EVENT \"", iAnimEndTagHash, "\" FIRED - PHASE = ", fPhase, " Dictionary = \"", strAnimDict, "\" AnimName = \"", strAnimName, "\"" ) bResult = TRUE ENDIF RETURN bResult ENDIF RETURN TRUE ENDFUNC FUNC BOOL HAS_CROWD_CONTROL_PED_FINISHED_ANIM( PED_INDEX ped, CROWD_CONTROL_PED_ANIM_TYPE eAnim, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID, CROWD_CONTROL_HEIST_TYPE eHeistType, FLOAT fFinishPhase = 1.0, BOOL bUseSyncSceneCheck = FALSE, INT iNetSyncSceneID = -1, INT iAnimEndTagHash = 0 ) RETURN HAS_PED_FINISHED_ANIM( ped, GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, eCrowdControlAnimID, eHeistType ), GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, eCrowdControlAnimID, eHeistType ), fFinishPhase, bUseSyncSceneCheck, iNetSyncSceneID, iAnimEndTagHash ) ENDFUNC FUNC BOOL HAS_CROWD_CONTROL_PLAYER_FINISHED_ANIM( PED_INDEX ped, CROWD_CONTROL_PLAYER_ANIM_TYPE eAnim, FLOAT fFinishPhase = 1.0, BOOL bUseSyncSceneCheck = FALSE, INT iNetSyncSceneID = -1, INT iAnimEndTagHash = 0 ) RETURN HAS_PED_FINISHED_ANIM( ped, GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( eAnim ), GET_CROWD_CONTROL_PLAYER_ANIM_NAME( eAnim ), fFinishPhase, bUseSyncSceneCheck, iNetSyncSceneID, iAnimEndTagHash ) ENDFUNC PROC REQUEST_CROWD_CONTROL_PED_ANIM( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( eAnimType, eCrowdControlAnimID, eHeist ) REQUEST_ANIM_DICT( GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnimType, eCrowdControlAnimID, eHeist ) ) ENDIF ENDPROC PROC RELEASE_CROWD_CONTROL_PED_ANIM( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( eAnimType, eCrowdControlAnimID, eHeist ) REMOVE_ANIM_DICT( GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnimType, eCrowdControlAnimID, eHeist ) ) ENDIF ENDPROC FUNC BOOL HAS_CROWD_CONTROL_PED_ANIM_LOADED( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_PED_ENUM eCrowdControlAnimID ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( eAnimType, eCrowdControlAnimID, eHeist ) IF HAS_ANIM_DICT_LOADED( GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnimType, eCrowdControlAnimID, eHeist ) ) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC PROC REQUEST_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_LOCAL_PED_DATA &sCrowdControlLocalPedData[], INT iNumCrowdPeds ) INT i FOR i = 0 TO iNumCrowdPeds IF i < FMMC_MAX_CROWD_PEDS REQUEST_CROWD_CONTROL_PED_ANIM( eAnimType, eHeist, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) ENDIF ENDFOR ENDPROC PROC RELEASE_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_LOCAL_PED_DATA &sCrowdControlLocalPedData[], INT iNumCrowdPeds ) INT i FOR i = 0 TO iNumCrowdPeds IF i < FMMC_MAX_CROWD_PEDS RELEASE_CROWD_CONTROL_PED_ANIM( eAnimType, eHeist, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) ENDIF ENDFOR ENDPROC FUNC BOOL HAVE_CROWD_CONTROL_PED_ANIMS_LOADED_FOR_SCENE( CROWD_CONTROL_PED_ANIM_TYPE eAnimType, CROWD_CONTROL_HEIST_TYPE eHeist, CROWD_CONTROL_LOCAL_PED_DATA &sCrowdControlLocalPedData[], INT iNumCrowdPeds ) BOOL bFinished = TRUE INT i FOR i = 0 TO iNumCrowdPeds IF i < FMMC_MAX_CROWD_PEDS IF NOT HAS_CROWD_CONTROL_PED_ANIM_LOADED( eAnimType, eHeist, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) bFinished = FALSE ENDIF ENDIF ENDFOR RETURN bFinished ENDFUNC PROC PLAY_CROWD_CONTROL_ANIM( PED_INDEX pedCrowd, CROWD_CONTROL_PED_ANIM_TYPE eAnim, CROWD_CONTROL_PED_ENUM eCreatorAssignedID, CROWD_CONTROL_HEIST_TYPE eHeistType, FLOAT fBlendInDelta = NORMAL_BLEND_IN, FLOAT fBlendOutDelta = NORMAL_BLEND_OUT, INT iAnimDuration = -1, ANIMATION_FLAGS eAnimFlags = AF_DEFAULT ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_ANIM() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( eCreatorAssignedID ), " | AnimType = ", GET_CROWD_CONTROL_PED_ANIM_ENUM_NAME( eAnim ), " | fBlendIn = ", fBlendInDelta, " | fBlendOut = ", fBlendOutDelta, " | iAnimDuration = ", iAnimDuration ) // Playing from where the ped is IF IS_VECTOR_ZERO( GET_CROWD_CONTROL_PED_ANIM_SCENE_COORD( eHeistType, eAnim ) ) TASK_PLAY_ANIM( pedCrowd, GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, eCreatorAssignedID, eHeistType ), GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, eCreatorAssignedID, eHeistType ), fBlendInDelta, fBlendOutDelta, iAnimDuration, eAnimFlags, DEFAULT, DEFAULT, AIK_DISABLE_LEG_IK ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_ANIM() Played with TASK_PLAY_ANIM" ) // Playing from an offset so use anim advanced and extract the initial offset ELSE TASK_PLAY_ANIM_ADVANCED( pedCrowd, GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, eCreatorAssignedID, eHeistType ), GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, eCreatorAssignedID, eHeistType ), GET_CROWD_CONTROL_PED_ANIM_SCENE_COORD( eHeistType, eAnim ), GET_CROWD_CONTROL_PED_ANIM_SCENE_ROT( eHeistType ), fBlendInDelta, fBlendOutDelta, iAnimDuration, eAnimFlags | AF_EXTRACT_INITIAL_OFFSET, DEFAULT, DEFAULT, AIK_DISABLE_LEG_IK ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_ANIM() Played with TASK_PLAY_ANIM_ADVANCED" ) ENDIF ENDPROC PROC PLAY_CROWD_CONTROL_SYNC_SCENE( INT &iSyncSceneID, NETWORK_INDEX &pedsGlobalArray[], INT &iCloudPedIDLookupArray[], CROWD_CONTROL_LOCAL_PED_DATA &sCrowdControlLocalPedData[], INT iNumCrowdPeds, CROWD_CONTROL_PED_ANIM_TYPE eAnim, CROWD_CONTROL_HEIST_TYPE eHeistType, FLOAT fBlendInDelta, FLOAT fBlendOutDelta, BOOL bLoop, BOOL bHoldLastFrame, SYNCED_SCENE_PLAYBACK_FLAGS eSyncSceneFlags, RAGDOLL_BLOCKING_FLAGS eRagdollBlockingFlags ) iSyncSceneID = NETWORK_CREATE_SYNCHRONISED_SCENE( GET_CROWD_CONTROL_PED_ANIM_SCENE_COORD( eHeistType, eAnim ), GET_CROWD_CONTROL_PED_ANIM_SCENE_ROT( eHeistType ), DEFAULT, bHoldLastFrame, bLoop ) IF bLoop eSyncSceneFlags = eSyncSceneFlags | SYNCED_SCENE_LOOP_WITHIN_SCENE ENDIF // Task all the peds with their intro loop anim INT i FOR i = 0 TO iNumCrowdPeds-1 IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( pedsGlobalArray[iCloudPedIDLookupArray[i]] ) AND NOT IS_PED_INJURED( NET_TO_PED( pedsGlobalArray[iCloudPedIDLookupArray[i]] ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_SYNC_SCENE() - TASKING ANIM dict: ", GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, sCrowdControlLocalPedData[i].eCreatorAssignedPedID, eHeistType ), " anim: ", GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, sCrowdControlLocalPedData[i].eCreatorAssignedPedID, eHeistType )) NETWORK_ADD_PED_TO_SYNCHRONISED_SCENE( NET_TO_PED( pedsGlobalArray[iCloudPedIDLookupArray[i]] ), iSyncSceneID, GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eAnim, sCrowdControlLocalPedData[i].eCreatorAssignedPedID, eHeistType ), GET_CROWD_CONTROL_PED_ANIM_NAME( eAnim, sCrowdControlLocalPedData[i].eCreatorAssignedPedID, eHeistType ), fBlendInDelta, fBlendOutDelta, eSyncSceneFlags, eRagdollBlockingFlags ) ENDIF ENDFOR CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_SYNC_SCENE() - START SCENE" ) NETWORK_START_SYNCHRONISED_SCENE( iSyncSceneID ) ENDPROC PROC SET_CROWD_CONTROL_PED_DECORATORS( PED_INDEX pedCrowd, CROWD_CONTROL_PED_DECORATOR_DATA &sPedNewDecorators ) DECOR_SET_INT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iState ), ENUM_TO_INT( sPedNewDecorators.eState ) ) DECOR_SET_INT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iStatePrev ), ENUM_TO_INT( sPedNewDecorators.eStatePrev ) ) DECOR_SET_INT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBitSet ), sPedNewDecorators.iBitSet ) DECOR_SET_FLOAT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_fInfluenceDirectThreat ), sPedNewDecorators.fInfluenceDirectThreat ) DECOR_SET_FLOAT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_fInfluenceShouting ), sPedNewDecorators.fInfluenceShouting ) DECOR_SET_INT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBeatdownHitsRemaining ), sPedNewDecorators.iBeatdownHitsRemaining ) DECOR_SET_INT( pedCrowd, GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBeatdownRounds ), sPedNewDecorators.iBeatdownRounds ) ENDPROC FUNC CROWD_CONTROL_PED_DECORATOR_DATA GET_CROWD_CONTROL_PED_DECORATOR_DATA( PED_INDEX pedCrowd ) CROWD_CONTROL_PED_DECORATOR_DATA sPedData STRING strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iState ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.eState = INT_TO_ENUM( CROWD_CONTROL_PED_STATE, DECOR_GET_INT( pedCrowd, strTemp ) ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iStatePrev ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.eStatePrev = INT_TO_ENUM( CROWD_CONTROL_PED_STATE, DECOR_GET_INT( pedCrowd, strTemp ) ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBitSet ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.iBitSet = DECOR_GET_INT( pedCrowd, strTemp ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_fInfluenceDirectThreat ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.fInfluenceDirectThreat = DECOR_GET_FLOAT( pedCrowd, strTemp ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_fInfluenceShouting ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.fInfluenceShouting = DECOR_GET_FLOAT( pedCrowd, strTemp ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBeatdownHitsRemaining ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.iBeatdownHitsRemaining = DECOR_GET_INT( pedCrowd, strTemp ) ENDIF strTemp = GET_CROWD_CONTROL_PED_DECOR_NAME( CCPDECOR_iBeatdownRounds ) IF DECOR_EXIST_ON( pedCrowd, strTemp ) sPedData.iBeatdownRounds = DECOR_GET_INT( pedCrowd, strTemp ) ENDIF RETURN sPedData ENDFUNC FUNC BOOL CAN_WE_UPDATE_CROWD_CONTROL_DATA( PED_INDEX pedCrowd, CROWD_CONTROL_PED_DECORATOR_DATA &sPedNewDecorators, INT iUpdateTimer ) CROWD_CONTROL_PED_DECORATOR_DATA sPedData = GET_CROWD_CONTROL_PED_DECORATOR_DATA( pedCrowd ) // Critical stuff, should update regardless of time IF sPedData.eState != sPedNewDecorators.eState OR sPedData.iBeatDownRounds != sPedNewDecorators.iBeatDownRounds OR sPedData.iBeatDownHitsRemaining != sPedNewDecorators.iBeatDownHitsRemaining OR sPedData.iBitSet != sPedNewDecorators.iBitSet RETURN TRUE ENDIF // Non critical stuff, should only update once enough time has passed IF iUpdateTimer > 20 // minimum of 20 frames IF sPedData.fInfluenceDirectThreat != sPedNewDecorators.fInfluenceDirectThreat OR sPedData.fInfluenceShouting != sPedNewDecorators.fInfluenceShouting RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_RESTRICTED( CROWD_CONTROL_PED_ENUM eAssignedCrowdID, CROWD_CONTROL_HEIST_TYPE eHeistType, CROWD_CONTROL_PED_STATE eState, BOOL bIsCrowdRestricted ) SWITCH eHeistType // Always restrict both cashiers CASE CCHEIST_NORMAL IF eAssignedCrowdID = CCPED_CASHIER_A OR eAssignedCrowdID = CCPED_CASHIER_B RETURN TRUE ENDIF BREAK CASE CCHEIST_CUSTOM_FLEECA SWITCH eState // Neither cashiers can attmped an hero action at any time CASE CCPS_HERO_ATTEMPT IF bIsCrowdRestricted IF eAssignedCrowdID = CCPED_CASHIER_A RETURN TRUE ENDIF ENDIF BREAK ENDSWITCH BREAK // Restrict the cashiers while waiting for the thermite to blow the door open objective CASE CCHEIST_CUSTOM_ORNATE SWITCH eState CASE CCPS_HERO_ATTEMPT // Cashier A cannot attempt a hero action until the crowd is unrestricted IF eAssignedCrowdID = CCPED_CASHIER_A IF bIsCrowdRestricted RETURN TRUE ENDIF ENDIF BREAK ENDSWITCH BREAK ENDSWITCH RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_A_VALID_HERO( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_HEIST_TYPE eHeistType, BOOL bIsPedRestricted ) // Ped doesn't have custom animation even though running anims IF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) AND NOT DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_START, ePed, eHeistType ) RETURN FALSE // Ped is not allowed to do a hero attempt at this stage ELIF IS_CROWD_CONTROL_PED_RESTRICTED( ePed, eHeistType, CCPS_HERO_ATTEMPT, bIsPedRestricted ) RETURN FALSE // Already attempted ELIF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroAttempted ) RETURN FALSE // Hero prop has been broken, can't perform hero task any more. ELIF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroBroken ) RETURN FALSE ELIF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroComplete ) RETURN FALSE ENDIF RETURN TRUE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_HERO_ALWAYS_ACTIVE( CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_CUSTOM_ORNATE SWITCH ePed CASE CCPED_CASHIER_A RETURN TRUE BREAK ENDSWITCH BREAK ENDSWITCH RETURN FALSE ENDFUNC FUNC BOOL SHOULD_CROWD_CONTROL_PED_DIRECT_THREAT_INFLUENCE_DECREASE( CROWD_CONTROL_THREAT_TYPE eThreat ) IF eThreat = CCTHREAT_SHOOTING_CLOSE OR eThreat = CCTHREAT_AIMED_AT RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC UPDATE_CROWD_CONTROL_PED_DIRECT_THREAT_INFLUENCE( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_THREAT_TYPE eThreat, FLOAT fInfluenceDeficitPerPed ) INT iChangeSign = 0 FLOAT fChangeRate = 0.0 // Decrease because there is an over powered threat IF SHOULD_CROWD_CONTROL_PED_DIRECT_THREAT_INFLUENCE_DECREASE( eThreat ) iChangeSign = -1 SWITCH eThreat CASE CCTHREAT_SHOOTING_CLOSE fChangeRate = 0.2 BREAK CASE CCTHREAT_AIMED_AT fChangeRate = 0.15 BREAK ENDSWITCH // Hold while a threat wears off unless theres a deficit ELIF fInfluenceDeficitPerPed <= 0.0 AND ( IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastShotAt, 8000 ) ) OR IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeStartThreaten, 5000 ) ) ) iChangeSign = 0 fChangeRate = 0 // Increase now all threats have worn off ELSE iChangeSign = 1 fChangeRate = 0.1 + fInfluenceDeficitPerPed ENDIF sPedData.fInfluenceDirectThreat = CLAMP( sPedData.fInfluenceDirectThreat + ( iChangeSign * fChangeRate * TIMESTEP() ), 0.0, 1.0 ) ENDPROC FUNC BOOL SHOULD_CROWD_CONTROL_PED_SHOUT_THREAT_INFLUENCE_DECREASE( CROWD_CONTROL_THREAT_TYPE eThreat ) IF eThreat = CCTHREAT_SHOUTING_CLOSE RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC UPDATE_CROWD_CONTROL_PED_SHOUT_THREAT_INFLUENCE( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_THREAT_TYPE eThreat, FLOAT fInfluenceDeficitPerPed ) INT iChangeSign = 0 FLOAT fChangeRate = 0.0 // Decrease because there is an over powered threat IF SHOULD_CROWD_CONTROL_PED_SHOUT_THREAT_INFLUENCE_DECREASE( eThreat ) iChangeSign = -1 SWITCH eThreat CASE CCTHREAT_SHOUTING_CLOSE fChangeRate = 0.15 BREAK ENDSWITCH // Hold while a threat wears off unless theres a deficit ELIF fInfluenceDeficitPerPed <= 0.0 AND IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeStartThreaten, 5000 ) ) iChangeSign = 0 fChangeRate = 0 // Increase now all threats have worn off ELSE iChangeSign = 1 fChangeRate = 0.1 fChangeRate += fInfluenceDeficitPerPed ENDIF sPedData.fInfluenceShouting = CLAMP( sPedData.fInfluenceShouting + ( iChangeSign * fChangeRate * TIMESTEP() ), 0.0, 1.0 ) ENDPROC FUNC FLOAT GET_CROWD_CONTROL_PED_FEAR_DELTA( CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, PED_INDEX pedPlayer, CROWD_CONTROL_THREAT_TYPE eThreat, INT iCrowdNum, INT iCrowdSize) // Initialise multipliers FLOAT fCrowdSizeMultiplier = FMMC_MAX_CROWD_PEDS / TO_FLOAT( iCrowdSize ) FLOAT fThreatMultiplier = 1.0 FLOAT fHeroMultiplier = 1.0 FLOAT fHeistMultiplier = 1.0 FLOAT fFearInfluence = 1.0 INT iChangeSign = 0 // Increase IF eThreat != CCTHREAT_NONE fFearInfluence = sPedData.fInfluenceDirectThreat * sPedData.fInfluenceShouting iChangeSign = 1 // Decide whether to apply a threat multipler SWITCH eThreat CASE CCTHREAT_PROXIMITY fThreatMultiplier = 0.25 BREAK CASE CCTHREAT_SHOUTING fThreatMultiplier = 0.25 BREAK CASE CCTHREAT_BEATING_NEIGHBOUR fThreatMultiplier = 1.5 BREAK CASE CCTHREAT_KILLED_OTHER fThreatMultiplier = 4.0 BREAK CASE CCTHREAT_BEATING fThreatMultiplier = 5.0 BREAK CASE CCTHREAT_SHOOTING fThreatMultiplier = 1.0 BREAK CASE CCTHREAT_SHOUTING_CLOSE fThreatMultiplier = 10.0 // has diminishing effect so start it strong BREAK CASE CCTHREAT_AIMED_AT fThreatMultiplier = 10.0 // has diminishing effect and only on 1 ped at a time so make it strong BREAK CASE CCTHREAT_SHOOTING_CLOSE // has diminishing effect so make it strong WEAPON_TYPE eWeap IF GET_CURRENT_PED_WEAPON( pedPlayer, eWeap ) // Weapon damage ( clamped between pistol and sawnoff ) FLOAT fWeaponDamageAlpha fWeaponDamageAlpha = CLAMP( GET_WEAPON_DAMAGE( eWeap, WEAPONCOMPONENT_INVALID ), 26.0, 40.0 ) fWeaponDamageAlpha -= 26.0 // minus lower boundry fWeaponDamageAlpha /= 14.0 // divide range // between 400% and 900% faster depending on weapon damage fThreatMultiplier = 5.0 + ( fWeaponDamageAlpha * 5.0 ) ENDIF BREAK CASE CCTHREAT_PROJECTILE_EXPLOSIVE fThreatMultiplier = 5.0 // 400% Faster BREAK ENDSWITCH // Decide whether to apply a hero multiplier IF IS_BIT_SET( sData.iCurrentActiveHeros, iCrowdNum ) fHeroMultiplier = 0.5 // 50% slower (halved) ENDIF // Decrease ELIF eThreat = CCTHREAT_NONE iChangeSign = -1 IF sLocalData.eHeistType = CCHEIST_CUSTOM_FLEECA // b* 2235971 - removed heist multiplier for Fleeca, was decreasing too fast // fHeistMultiplier = 2.0 // 100% faster (double) ENDIF IF IS_BIT_SET( sData.iCurrentActiveHeros, iCrowdNum ) fHeroMultiplier = 0.85 // 15% slower ENDIF ENDIF IF iChangeSign = 0 RETURN 0.0 ELSE RETURN iChangeSign * fFearInfluence * fThreatMultiplier * fHeroMultiplier * fHeistMultiplier * fCrowdSizeMultiplier ENDIF ENDFUNC FUNC FLOAT GET_CROWD_CONTROL_PED_CAPSULE_SIZE( CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_HEIST_TYPE eHeistType ) SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH ePed CASE CCPED_CUSTOMER_A RETURN 0.4 BREAK CASE CCPED_CUSTOMER_B RETURN 0.3 BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH ePed CASE CCPED_CUSTOMER_A RETURN 0.4 BREAK CASE CCPED_CUSTOMER_B RETURN 0.3 BREAK ENDSWITCH BREAK ENDSWITCH RETURN -1.0 ENDFUNC //PURPOSE: Return True if the Player is in front of the Ped FUNC BOOL IS_PLAYER_IN_FRONT_OF_PED(VECTOR vPlayerCoord, VECTOR vPedCoord, FLOAT fPedHeading) VECTOR posA // Player position VECTOR posB // Ped position VECTOR posC VECTOR vecBA // vector from Ped to Player VECTOR vecPed // unit vector pointing in the direction the Ped is facing FLOAT fTemp // get positions posA = vPlayerCoord posB = vPedCoord // get vec from Player to Ped vecBA = posA - posB // get unit vector pointing forwards from Ped posC = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPedCoord, fPedHeading, <<0.0, 7.0, 0.0>>) vecPed = posC - posB // calculate dot product of vecBA and vecPed fTemp = GET_ANGLE_BETWEEN_2D_VECTORS(vecPed.x,vecPed.y,vecBA.x,vecBA.y) IF (fTemp < 80.0) RETURN(TRUE) ENDIF RETURN(FALSE) ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PLAYER_ABLE_TO_THREATEN_FROM_CURRENT_LOCATION( PED_INDEX pedPlayer, CROWD_CONTROL_LOCAL_DATA sLocalData ) SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA IF GET_INTERIOR_FROM_ENTITY( pedPlayer ) = sLocalData.interiorHeist INT iRoomKey iRoomKey = GET_ROOM_KEY_FROM_ENTITY( pedPlayer ) IF iRoomKey = HASH("Bankvault") RETURN FALSE ENDIF ELSE // do not exempt the exterior of the bank as players can shoot through the glass front ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE IF GET_INTERIOR_FROM_ENTITY( pedPlayer ) = sLocalData.interiorHeist INT iRoomKey iRoomKey = GET_ROOM_KEY_FROM_ENTITY( pedPlayer ) IF iRoomKey = HASH("Bank_basementRm") OR iRoomKey = HASH("_") RETURN FALSE ENDIF // Not inside the bank, no possible way to threaten from outside this bank, return false ELSE RETURN FALSE ENDIF BREAK ENDSWITCH RETURN TRUE ENDFUNC FUNC BOOL IS_PLAYER_STARTING_CROWD_CONTROL_PED_REACTION( PED_INDEX playerPed, CROWD_CONTROL_LOCAL_DATA &sLocalData ) PLAYER_INDEX playerID = NETWORK_GET_PLAYER_INDEX_FROM_PED( playerPed ) IF playerID != INVALID_PLAYER_INDEX() AND IS_NET_PLAYER_OK( playerID ) BOOL bPlayerLooksHostile // ... with a gun WEAPON_TYPE CurrentWeapon IF GET_CURRENT_PED_WEAPON( playerPed, CurrentWeapon ) IF CurrentWeapon != WEAPONTYPE_UNARMED AND CurrentWeapon != WEAPONTYPE_OBJECT AND CurrentWeapon != WEAPONTYPE_FLARE bPlayerLooksHostile = TRUE ENDIF ENDIF // ... in a mask IF IS_PED_WEARING_A_MASK( playerPed ) bPlayerLooksHostile = TRUE ENDIF IF IS_PED_IN_ANY_VEHICLE( playerPed ) bPlayerLooksHostile = TRUE ENDIF // Looks hostile and can be seen IF bPlayerLooksHostile // 2068869, this check only works on peds you own which fucks things up //AND NETWORK_HAS_CONTROL_OF_ENTITY( crowdPed ) AND CAN_PED_SEE_HATED_PED( crowdPed, playerPed ) IF HAS_PED_ENTERED_CROWD_CONTROL_TRIGGER_ZONE( playerPed, sLocalData, FALSE ) RETURN TRUE ENDIF ENDIF // Player is shouting IF NETWORK_IS_PLAYER_TALKING( playerID ) AND NETWORK_GET_PLAYER_LOUDNESS( playerID ) > 0.75 IF HAS_PED_ENTERED_CROWD_CONTROL_TRIGGER_ZONE( playerPed, sLocalData, TRUE ) RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC CROWD_CONTROL_THREAT_TYPE IS_PLAYER_THREATENING_CROWD_CONTROL_PED( PLAYER_INDEX threateningPlayer, PED_INDEX threateningPed, PED_INDEX crowdPed, INT iCrowdNum, CROWD_CONTROL_SERVER_DATA &sServerData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[FMMC_MAX_CROWD_PEDS], CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[FMMC_MAX_CROWD_PEDS], PED_INDEX pedBeingBeat ) CONST_FLOAT cfCC_ShootingDistClose 2.0 CONST_FLOAT cfCC_ShootingDist 5.0 CONST_FLOAT cfCC_ProjectileDist 5.0 CONST_FLOAT cfCC_AimingDist 8.0 CONST_FLOAT cfCC_ShoutingDist 6.0 CONST_FLOAT cfCC_ShoutingDistClose 2.5 CONST_FLOAT cfCC_ProximityDistNormal 3.5 CONST_FLOAT cfCC_ProximityDistClose 2.0 CONST_FLOAT cfCC_BeatingNeighbourDist 5.0 CONST_FLOAT cfCC_DeadNeighbourDist 3.0 INT i BOOL bIsThreateningPedOk FLOAT fDistanceFromPed IF (threateningPlayer != INVALID_PLAYER_INDEX()) AND IS_NET_PLAYER_OK(threateningPlayer) fDistanceFromPed = GET_DISTANCE_BETWEEN_ENTITIES( threateningPed, crowdPed, FALSE ) bIsThreateningPedOk = TRUE ENDIF BOOL bIsArmed WEAPON_TYPE CurrentWeapon IF GET_CURRENT_PED_WEAPON(threateningPed, CurrentWeapon) IF CurrentWeapon != WEAPONTYPE_UNARMED bIsArmed = TRUE ENDIF ENDIF BOOL bIsPlayerFacingPed = IS_PED_FACING_PED(threateningPed, crowdPed, 60.0) BOOL bIsPedFacingPlayer = IS_PED_FACING_PED(crowdPed, threateningPed, 90.0) BOOL bIsPlayerShouting = NETWORK_IS_PLAYER_TALKING(threateningPlayer) AND NETWORK_GET_PLAYER_LOUDNESS(threateningPlayer) > cfCC_ShoutVolumeLevel VECTOR vPedCoord = GET_ENTITY_COORDS(crowdPed) REPEAT COUNT_OF(CROWD_CONTROL_THREAT_TYPE) i CROWD_CONTROL_THREAT_TYPE eThreatToTest = INT_TO_ENUM( CROWD_CONTROL_THREAT_TYPE, ( COUNT_OF(CROWD_CONTROL_THREAT_TYPE) - 1) - i ) SWITCH eThreatToTest CASE CCTHREAT_SHOOTING_CLOSE // Shooting Close // Bullet impacted near the ped // OR the player is within range of the ped and is shooting IF bIsThreateningPedOk IF IS_BULLET_IN_AREA(vPedCoord, cfCC_ShootingDistClose) // Bullet flew past them OR HAS_BULLET_IMPACTED_IN_AREA(vPedCoord, cfCC_ShootingDistClose) // Bullet hit near them OR ( fDistanceFromPed < cfCC_ShootingDistClose AND IS_PED_SHOOTING(threateningPed) ) // Shooting anywhere near them RETURN CCTHREAT_SHOOTING_CLOSE ENDIF ENDIF BREAK CASE CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB // Sticky Bomb // Ped not set to ignore sticky bombs // Sticky bomb in area near ped IF NOT IS_BIT_SET_ENUM( sPedData[iCrowdNum].iBitSet, CCPEDDATA_IgnoreStickyBombs ) AND IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_STICKYBOMB, cfCC_ProjectileDist ) RETURN CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB ENDIF BREAK CASE CCTHREAT_PROJECTILE_EXPLOSIVE // Projectile // Is an explosive projectile within range of the ped IF IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_GRENADE, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_GRENADELAUNCHER, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_RPG, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_BZGAS, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_SMOKEGRENADE, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_MOLOTOV, cfCC_ProjectileDist ) OR IS_PROJECTILE_TYPE_WITHIN_DISTANCE( vPedCoord, WEAPONTYPE_FLARE, cfCC_ProjectileDist ) RETURN CCTHREAT_PROJECTILE_EXPLOSIVE ENDIF BREAK CASE CCTHREAT_SHOOTING // Shooting // Bullet is near the ped // OR Bullet impacted near the ped // OR the player is within range of the ped and is shooting IF bIsThreateningPedOk AND bIsArmed IF IS_BULLET_IN_AREA(vPedCoord, cfCC_ShootingDist) // Bullet flew past them OR HAS_BULLET_IMPACTED_IN_AREA(vPedCoord, cfCC_ShootingDist) // Bullet hit near them OR ( fDistanceFromPed < cfCC_ShootingDist AND IS_PED_SHOOTING(threateningPed) ) // Shooting anywhere near them RETURN CCTHREAT_SHOOTING ENDIF ENDIF BREAK CASE CCTHREAT_BEATING // Local data says the player is beating this ped IF bIsThreateningPedOk AND bIsArmed IF sLocalData.iPlayerBeatingThisPed != -1 AND sLocalData.iPlayerBeatingThisPed = iCrowdNum RETURN CCTHREAT_BEATING ENDIF ENDIF BREAK CASE CCTHREAT_AIMED_AT // Aiming at ped // Is facing the player // Player not using the cellphone // Player is within aim range OR is shouting to prompt the ped IF bIsThreateningPedOk AND bIsArmed IF ( IS_PLAYER_FREE_AIMING_AT_ENTITY(threateningPlayer, crowdPed) OR IS_PLAYER_TARGETTING_ENTITY(threateningPlayer, crowdPed ) ) AND bIsPedFacingPlayer AND NOT IS_CELLPHONE_CAMERA_IN_USE() AND ( fDistanceFromPed < cfCC_AimingDist OR bIsPlayerShouting ) RETURN CCTHREAT_AIMED_AT ENDIF ENDIF BREAK CASE CCTHREAT_KILLED_OTHER // Killed someone // Player has killed someone near by IF bIsThreateningPedOk INT j FOR j = 0 TO sServerData.iNumCrowdControlPeds-1 // exclude this ped from being checked IF j != iCrowdNum //IF IS_BIT_SET_ENUM( sPedData[j].iBitSet, CCPEDDATA_Dead ) //OR IS_BIT_SET_ENUM( sPedData[j].iBitSet, CCPEDDATA_KnockedOut ) IF IS_BIT_SET_ENUM( sPedData[j].iBitSet, CCPEDDATA_Dead ) IF IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData[j].timeDied, 3000 ) ) RETURN CCTHREAT_KILLED_OTHER ENDIF ENDIF ENDIF ENDFOR ENDIF BREAK CASE CCTHREAT_BEATING_NEIGHBOUR // Beating someone // Player is beating someone near by IF bIsThreateningPedOk AND bIsArmed IF sLocalData.iPlayerBeatingThisPed != -1 AND GET_DISTANCE_BETWEEN_ENTITIES( pedBeingBeat, crowdPed ) < cfCC_BeatingNeighbourDist RETURN CCTHREAT_BEATING_NEIGHBOUR ENDIF ENDIF BREAK CASE CCTHREAT_SHOUTING_CLOSE // Shouting close // Within shout close range IF bIsThreateningPedOk IF bIsPlayerShouting AND fDistanceFromPed < cfCC_ShoutingDistClose RETURN CCTHREAT_SHOUTING_CLOSE ENDIF ENDIF BREAK CASE CCTHREAT_SHOUTING // Shouting // Within shout range IF bIsThreateningPedOk IF bIsPlayerShouting AND fDistanceFromPed < cfCC_ShoutingDist RETURN CCTHREAT_SHOUTING ENDIF ENDIF BREAK CASE CCTHREAT_PROXIMITY // Proximity // Player is within normal range both the ped and the player are facing // OR player is within close range IF bIsThreateningPedOk IF ( fDistanceFromPed < cfCC_ProximityDistNormal AND bIsPlayerFacingPed AND bIsPedFacingPlayer ) OR fDistanceFromPed < cfCC_ProximityDistClose RETURN CCTHREAT_PROXIMITY ENDIF ENDIF BREAK ENDSWITCH ENDREPEAT RETURN CCTHREAT_NONE ENDFUNC FUNC INT CREATE_CROWD_CONTROL_PED_SEQUENCES( CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData ) INT iSeqCount // Hero fail -> Cower IF sLocalPedData.seqs[CCSEQ_HERO_FAIL] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_FAIL, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_FAIL] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_HERO_FAIL, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_FAIL] ) iSeqCount++ ENDIF // Flinch -> Cower IF sLocalPedData.seqs[CCSEQ_FLINCH_TO_COWER] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_TO_COWER] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_TO_COWER] ) iSeqCount++ ENDIF // Cower -> Flinch IF sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH] ) iSeqCount++ ENDIF // Cower -> Flinch underfire IF sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH_UNDERFIRE] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH_UNDERFIRE] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_COWER_TO_FLINCH_UNDERFIRE_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_COWER_TO_FLINCH_UNDERFIRE] ) iSeqCount++ ENDIF FLOAT fLoopBlendIn // Flinch -> Flinch underfire IF sLocalPedData.seqs[CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE] ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) ENDIF PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE] ) iSeqCount++ ENDIF // Flinch underfire -> Flinch IF sLocalPedData.seqs[CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH] ) fLoopBlendIn = REALLY_SLOW_BLEND_IN IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) fLoopBlendIn = SLOW_BLEND_IN ENDIF PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, fLoopBlendIn, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH] ) iSeqCount++ ENDIF // Beatdown -> Flinch IF sLocalPedData.seqs[CCSEQ_BEATDOWN_TO_FLINCH] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_BEATDOWN_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_BEATDOWN_TO_FLINCH] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_BEATDOWN_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_BEATDOWN_TO_FLINCH] ) iSeqCount++ ENDIF // Cower -> Hero start -> Hero loop IF sLocalPedData.seqs[CCSEQ_HERO_START] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_START] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, 0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_HERO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_START] ) iSeqCount++ ENDIF // Hero loop -> Hero pass -> Cower IF sLocalPedData.seqs[CCSEQ_HERO_PASS] = NULL AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OPEN_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_PASS] ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, eCrowdControlAnimFlags ) PLAY_CROWD_CONTROL_ANIM( NULL, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) CLOSE_SEQUENCE_TASK( sLocalPedData.seqs[CCSEQ_HERO_PASS] ) iSeqCount++ ENDIF RETURN iSeqCount ENDFUNC PROC PLAY_CROWD_CONTROL_SEQUENCE( PED_INDEX ped, CROWD_CONTROL_SEQUENCES eSeq, INT iCrowdNum, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData ) TASK_PERFORM_SEQUENCE( ped, sLocalPedData.seqs[eSeq] ) #IF NOT IS_DEBUG_BUILD UNUSED_PARAMETER( iCrowdNum ) #ENDIF #IF IS_DEBUG_BUILD CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_SEQUENCE() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), "[", iCrowdNum, "] - Seq = ", GET_CROWD_CONTROL_SEQUENCE_NAME( eSeq ) ) #ENDIF ENDPROC PROC CACHE_CROWD_CONTROL_LOCAL_DATA( CROWD_CONTROL_LOCAL_DATA &sLocalData ) // Cache which rule is the crowd control rule for each team INT iTeam INT iPed FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 sLocalData.iCCRule[iTeam] = -1 FOR iPed = 0 TO FMMC_MAX_PEDS-1 IF g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iRule[iTeam] = FMMC_OBJECTIVE_LOGIC_CROWD_CONTROL AND g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iPriority[iTeam] < FMMC_MAX_RULES sLocalData.iCCRule[iTeam] = g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iPriority[iTeam] ENDIF ENDFOR ENDFOR FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 FOR iPed = 0 TO FMMC_MAX_PEDS-1 IF INT_TO_ENUM( CROWD_CONTROL_PED_ENUM, g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iCrowdControlID ) = CCPED_CASHIER_A OR INT_TO_ENUM( CROWD_CONTROL_PED_ENUM, g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iCrowdControlID ) = CCPED_CASHIER_B sLocalData.iCashierPed = iPed ENDIF ENDFOR ENDFOR // Determine which heist we are on FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 IF sLocalData.iCCRule[iTeam] > -1 AND sLocalData.iCCRule[iTeam] < FMMC_MAX_RULES IF IS_BIT_SET(g_FMMC_STRUCT.sFMMCEndConditions[iTeam].iRuleBitset[sLocalData.iCCRule[iTeam]],ciBS_RULE_CUSTOM_CROWD_CONTROL_FLEECA) sLocalData.eHeistType = CCHEIST_CUSTOM_FLEECA ELIF IS_BIT_SET(g_FMMC_STRUCT.sFMMCEndConditions[iTeam].iRuleBitset[sLocalData.iCCRule[iTeam]],ciBS_RULE_CUSTOM_CROWD_CONTROL_ORNATE) sLocalData.eHeistType = CCHEIST_CUSTOM_ORNATE ENDIF ENDIF ENDFOR // Cache which rule is the thermite rule and which team has it IF sLocalData.iThermiteTeam = -1 OR sLocalData.iThermiteRule = -1 INT iObj FOR iTeam = 0 TO FMMC_MAX_TEAMS-1 FOR iObj = 0 TO FMMC_MAX_NUM_OBJECTS-1 IF g_FMMC_STRUCT_ENTITIES.sPlacedObject[iObj].iRule[iTeam] = FMMC_OBJECTIVE_LOGIC_MINIGAME AND g_FMMC_STRUCT_ENTITIES.sPlacedObject[iObj].iPriority[iTeam] < FMMC_MAX_RULES AND IS_BIT_SET( g_FMMC_STRUCT_ENTITIES.sPlacedObject[iObj].iLegacyMiniGameBitSet, cibsLEGACY_FMMC_MINI_GAME_USE_THERMAL_CHARGE ) sLocalData.iThermiteTeam = iTeam sLocalData.iThermiteRule = g_FMMC_STRUCT_ENTITIES.sPlacedObject[iObj].iPriority[iTeam] // Break loop iTeam = FMMC_MAX_TEAMS iObj = FMMC_MAX_NUM_OBJECTS ENDIF ENDFOR ENDFOR ENDIF // 2221150 - Cache the interior, too many calls per frame on per ped checks to fetching the interior (EXPENSIVE) IF sLocalData.interiorHeist = NULL sLocalData.interiorHeist = GET_CROWD_CONTROL_HEIST_INTERIOR( sLocalData.eHeistType ) ENDIF ENDPROC PROC CACHE_CROWD_CONTROL_LOCAL_PED_DATA( CROWD_CONTROL_LOCAL_PED_DATA &sPedData, INT iPlacedPedID ) sPedData.eCreatorAssignedPedID = INT_TO_ENUM( CROWD_CONTROL_PED_ENUM, g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPlacedPedID].iCrowdControlID ) ENDPROC PROC SET_CROWD_CONTROL_PED_STATE( CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_PED_STATE eNewState, INT iCrowdID, CROWD_CONTROL_PED_ENUM eCreatorAssignedPedID) DEBUG_PRINTCALLSTACK() CPRINTLN( DEBUG_NET_MINIGAME, "SET_CROWD_CONTROL_PED_STATE() - [", iCrowdID, "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( eCreatorAssignedPedID ), " - State: ", GET_CROWD_CONTROL_PED_STATE_STRING( sPedData.eState ), " -> ", GET_CROWD_CONTROL_PED_STATE_STRING( eNewState ) ) sPedData.eStatePrev = sPedData.eState sPedData.eState = eNewState ENDPROC FUNC BOOL SETUP_CROWD_CONTROL_PED_DATA( PED_INDEX ped, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_HEIST_TYPE eHeistType ) BOOL bReady = TRUE // Hero struff CROWD_CONTROL_PED_HERO_ACTION eHeroAction IF eHeistType != CCHEIST_NORMAL eHeroAction = GET_CROWD_CONTROL_PED_HERO_ACTION_FOR_ANIMATED_PED( sLocalPedData.eCreatorAssignedPedID, eHeistType ) ELSE eHeroAction = INT_TO_ENUM( CROWD_CONTROL_PED_HERO_ACTION, sLocalPedData.eCreatorAssignedPedID ) IF eHeroAction = CCHERO_ALARM eHeroAction = CCHERO_NONE ENDIF ENDIF // Give gun hero a their gun IF eHeroAction = CCHERO_GUN GIVE_WEAPON_TO_PED( ped, WEAPONTYPE_PISTOL, INFINITE_AMMO, FALSE, FALSE ) ENDIF IF bReady // Initialise struct SET_CROWD_CONTROL_PED_STATE( sPedData, CCPS_INTRO, -1, sLocalPedData.eCreatorAssignedPedID ) sPedData.iBeatdownHitsRemaining = ciCC_MaxBeatdownHits sPedData.fInfluenceDirectThreat = 1.0 sPedData.fInfluenceShouting = 1.0 IF eHeistType != CCHEIST_NORMAL SET_BIT_ENUM( sPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) // Has alt anims, set ped to initially use them // IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_COWER_LOOP_ALT, sLocalPedData.eCreatorAssignedPedID, eHeistType ) // SET_BIT( sPedData.iBitSet, CCPEDDATA_UseAlternativeAnims ) // ENDIF ENDIF // Initialise ped SET_PED_COMBAT_ATTRIBUTES(ped, CA_ALWAYS_FLEE, FALSE) SET_PED_FLEE_ATTRIBUTES(ped, FA_DISABLE_COWER,TRUE) SET_PED_FLEE_ATTRIBUTES(ped, FA_DISABLE_FLEE_FROM_INDIRECT_THREATS,TRUE) SET_PED_FLEE_ATTRIBUTES(ped, FA_COWER_INSTEAD_OF_FLEE,TRUE) SET_RAGDOLL_BLOCKING_FLAGS(ped, RBF_PLAYER_BUMP | RBF_PLAYER_IMPACT | RBF_PLAYER_RAGDOLL_BUMP ) SET_PED_CAN_BE_TARGETTED(ped, FALSE) // 2048337 SET_PED_CONFIG_FLAG(ped, PCF_DisableExplosionReactions, TRUE) SET_PED_CONFIG_FLAG(ped, PCF_DontActivateRagdollFromExplosions, TRUE) SET_PED_CONFIG_FLAG(ped, PCF_AvoidTearGas, TRUE ) // FALSE) SET_ENTITY_HEALTH(ped, 101) CLEAR_PED_PROP( ped, ANCHOR_LEFT_HAND ) CLEAR_PED_PROP( ped, ANCHOR_RIGHT_HAND ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL SETUP_CROWD_CONTROL_PED_LOCAL_PROPS( PED_INDEX ped, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_HEIST_TYPE eHeistType ) BOOL bReady = TRUE CROWD_CONTROL_PED_HERO_ACTION eHeroAction IF eHeistType != CCHEIST_NORMAL eHeroAction = GET_CROWD_CONTROL_PED_HERO_ACTION_FOR_ANIMATED_PED( sLocalPedData.eCreatorAssignedPedID, eHeistType ) ELSE eHeroAction = INT_TO_ENUM( CROWD_CONTROL_PED_HERO_ACTION, sLocalPedData.eCreatorAssignedPedID ) IF eHeroAction = CCHERO_ALARM eHeroAction = CCHERO_NONE ENDIF ENDIF CPRINTLN( DEBUG_NET_MINIGAME, "SETUP_CROWD_CONTROL_PED_LOCAL_PROPS() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), " - eHeroAction = ", GET_CROWD_CONTROL_HERO_ACTION( eHeroAction ), " - eHeistType = ", GET_CROWD_CONTROL_HEIST_TYPE_STRING( eHeistType ) ) IF NOT DOES_ENTITY_EXIST( sLocalPedData.objProp ) // Need to spawn a phone for the ped IF eHeroAction = CCHERO_PHONE CPRINTLN( DEBUG_NET_MINIGAME, "SETUP_CROWD_CONTROL_PED_LOCAL_PROPS() - Spawning phone for phone hero ped..." ) IF HAS_MODEL_LOADED( PROP_PHONE_ING ) CPRINTLN( DEBUG_NET_MINIGAME, "SETUP_CROWD_CONTROL_PED_LOCAL_PROPS() - ... phone created." ) sLocalPedData.objProp = CREATE_OBJECT( PROP_PHONE_ING, GET_ENTITY_COORDS( ped ), FALSE ) ATTACH_ENTITY_TO_ENTITY( sLocalPedData.objProp, ped, GET_PED_BONE_INDEX( ped, BONETAG_PH_R_HAND ), <<0,0,0>>, <<0,0,0>>, TRUE, FALSE ) ELSE bReady = FALSE ENDIF ENDIF ENDIF RETURN bReady ENDFUNC FUNC CROWD_CONTROL_DIALOGUE_CONTEXT GET_CROWD_CONTROL_DIALOGUE_CONTEXT_TIMER( CROWD_CONTROL_DIALOGUE eDialogue ) SWITCH eDialogue CASE CCDIA_SHOT_DIRECTLY_AT RETURN CCDIACONTEXT_SCARED_HIGH BREAK CASE CCDIA_SHOT_NEAR RETURN CCDIACONTEXT_SCARED_MEDIUM BREAK CASE CCDIA_INITIAL_PANIC CASE CCDIA_RECEIVES_SCARE RETURN CCDIACONTEXT_SCARED_LOW BREAK CASE CCDIA_SEES_OTHER_KILLED CASE CCDIA_STICKS_UP_FOR_OTHER RETURN CCDIACONTEXT_SCARED_SECOND_HAND BREAK CASE CCDIA_COWER_LOW_FEAR CASE CCDIA_COWER_HIGH_FEAR CASE CCDIA_ALARM_GOES_OFF RETURN CCDIACONTEXT_AMBIENT BREAK ENDSWITCH RETURN CCDIACONTEXT_NUM_CONTEXTS ENDFUNC FUNC BOOL RESET_CROWD_CONTROL_GLOBAL_DIALOGUE_CONTEXT_TIMER( CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_LOCAL_DATA &sLocalData ) CROWD_CONTROL_DIALOGUE_CONTEXT eContext = GET_CROWD_CONTROL_DIALOGUE_CONTEXT_TIMER( eDialogue ) IF eContext != CCDIACONTEXT_NUM_CONTEXTS INT iDelay SWITCH eContext CASE CCDIACONTEXT_SCARED_HIGH iDelay = 500 + ( GET_RANDOM_INT_IN_RANGE( 0, 6 ) * 100 ) /* 0.5 -> 1 secs */ BREAK CASE CCDIACONTEXT_SCARED_MEDIUM iDelay = 1000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 500 ) /* 1 -> 3 secs */ BREAK CASE CCDIACONTEXT_SCARED_LOW iDelay = 2000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 500 ) /* 2 -> 4 secs */ BREAK CASE CCDIACONTEXT_SCARED_SECOND_HAND iDelay = 2000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 500 ) /* 2 -> 4 secs */ BREAK CASE CCDIACONTEXT_AMBIENT iDelay = 5000 + ( GET_RANDOM_INT_IN_RANGE( 0, 6 ) * 1000 ) /* 5 -> 10 secs */ BREAK ENDSWITCH sLocalData.timeDialogueGlobalContextTimers[eContext] = GET_TIME_OFFSET( GET_NETWORK_TIME(), iDelay ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAS_CROWD_CONTROL_GLOBAL_DIALOGUE_CONTEXT_TIMER_EXPIRED( CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_LOCAL_DATA &sLocalData ) CROWD_CONTROL_DIALOGUE_CONTEXT eContext = GET_CROWD_CONTROL_DIALOGUE_CONTEXT_TIMER( eDialogue ) // No context timer exists, ignore timer and return TRUE // Context exists, check its timer IF eContext = CCDIACONTEXT_NUM_CONTEXTS OR IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalData.timeDialogueGlobalContextTimers[eContext] ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL RESET_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_TIMER( CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData ) CROWD_CONTROL_DIALOGUE_CONTEXT eContext = GET_CROWD_CONTROL_DIALOGUE_CONTEXT_TIMER( eDialogue ) IF eContext != CCDIACONTEXT_NUM_CONTEXTS INT iDelay SWITCH eContext CASE CCDIACONTEXT_SCARED_HIGH iDelay = 1000 + ( GET_RANDOM_INT_IN_RANGE( 0, 3 ) * 500 ) /* 1 -> 2 secs */ BREAK CASE CCDIACONTEXT_SCARED_MEDIUM iDelay = 3000 + ( GET_RANDOM_INT_IN_RANGE( 0, 3 ) * 500 ) /* 3 -> 4 secs */ BREAK CASE CCDIACONTEXT_SCARED_LOW iDelay = 5000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 500 ) /* 5 -> 7 secs */ BREAK CASE CCDIACONTEXT_SCARED_SECOND_HAND iDelay = 5000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 500 ) /* 5 -> 7 secs */ BREAK CASE CCDIACONTEXT_AMBIENT iDelay = 12000 + ( GET_RANDOM_INT_IN_RANGE( 0, 6 ) * 1000 ) /* 12 -> 17 secs */ BREAK ENDSWITCH sLocalPedData.timeDialogueContextTimers[eContext] = GET_TIME_OFFSET( GET_NETWORK_TIME(), iDelay ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAS_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_TIMER_EXPIRED( CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData ) CROWD_CONTROL_DIALOGUE_CONTEXT eContext = GET_CROWD_CONTROL_DIALOGUE_CONTEXT_TIMER( eDialogue ) // No context timer exists, ignore timer and return TRUE // Context exists, check its timer IF eContext = CCDIACONTEXT_NUM_CONTEXTS OR IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalPedData.timeDialogueContextTimers[eContext] ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( CROWD_CONTROL_DIALOGUE eDialogueNew, CROWD_CONTROL_DIALOGUE eDialogueOld ) IF eDialogueNew != CCDIA_NONE AND eDialogueNew > eDialogueOld RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( CROWD_CONTROL_DIALOGUE eDialogue ) IF eDialogue = CCDIA_HERO_ALARM_START OR eDialogue = CCDIA_HERO_ALARM_CAUGHT OR eDialogue = CCDIA_HERO_ALARM_COMPLETE OR eDialogue = CCDIA_HERO_GUN_START OR eDialogue = CCDIA_HERO_GUN_CAUGHT OR eDialogue = CCDIA_HERO_GUN_COMPLETE OR eDialogue = CCDIA_HERO_PHONE_START OR eDialogue = CCDIA_HERO_PHONE_CAUGHT OR eDialogue = CCDIA_HERO_PHONE_COMPLETE OR eDialogue = CCDIA_ALARM_GOES_OFF_INITIAL RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL CHECK_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_RANDOM_CHANCE( CROWD_CONTROL_DIALOGUE eDialogue ) SWITCH eDialogue CASE CCDIA_SHOT_DIRECTLY_AT RETURN GET_RANDOM_FLOAT_IN_RANGE(0, 1.0) <= 0.3 // 30% chance of playing BREAK ENDSWITCH RETURN TRUE ENDFUNC FUNC BOOL GET_CROWD_CONTROL_VOICE_RACE_GENDER_PREFIX( CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_HEIST_TYPE eHeistType, TEXT_LABEL_15 &tlRaceGenderPrefix, TEXT_LABEL_23 &tlVoiceName ) BOOL bIsPedMale BOOL bIsPedBlack INT iPedNumber SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH ePed CASE CCPED_CASHIER_A bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_A bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_B bIsPedMale = FALSE bIsPedBlack = FALSE iPedNumber = 1 BREAK DEFAULT RETURN FALSE BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH ePed CASE CCPED_CASHIER_A bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 1 BREAK CASE CCPED_CASHIER_B bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 2 BREAK CASE CCPED_CUSTOMER_A bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 2 BREAK CASE CCPED_CUSTOMER_B bIsPedMale = TRUE bIsPedBlack = TRUE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_C bIsPedMale = FALSE bIsPedBlack = FALSE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_D bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 2 BREAK CASE CCPED_CUSTOMER_E bIsPedMale = FALSE bIsPedBlack = TRUE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_F bIsPedMale = FALSE bIsPedBlack = FALSE iPedNumber = 2 BREAK CASE CCPED_CUSTOMER_G bIsPedMale = TRUE bIsPedBlack = FALSE iPedNumber = 1 BREAK CASE CCPED_CUSTOMER_H bIsPedMale = FALSE bIsPedBlack = FALSE iPedNumber = 1 BREAK DEFAULT RETURN FALSE BREAK ENDSWITCH BREAK DEFAULT RETURN FALSE BREAK ENDSWITCH // Add hostages prefix IF ePed = CCPED_CASHIER_A OR ePed = CCPED_CASHIER_B tlRaceGenderPrefix += "B" tlVoiceName += "BANK" ELSE tlRaceGenderPrefix += "H" tlVoiceName += "HOSTAGE" ENDIF // Add ethnicity prefix IF bIsPedBlack tlRaceGenderPrefix += "B" tlVoiceName += "B" ELSE tlRaceGenderPrefix += "W" tlVoiceName += "W" ENDIF // Add gender prefix IF bIsPedMale tlRaceGenderPrefix += "M" tlVoiceName += "M" ELSE tlRaceGenderPrefix += "F" tlVoiceName += "F" ENDIF // Add optional id number IF iPedNumber != -1 tlRaceGenderPrefix += iPedNumber tlVoiceName += iPedNumber ENDIF RETURN TRUE ENDFUNC FUNC BOOL GET_CROWD_CONTROL_PED_DIALOGUE_CONVO_SUFFIX( CROWD_CONTROL_DIALOGUE eDialogue, TEXT_LABEL_15 &tlConvoSuffix, INT &iLineNumber ) SWITCH eDialogue // Generic, everyone should have these CASE CCDIA_INITIAL_PANIC tlConvoSuffix += "C" BREAK CASE CCDIA_COWER_LOW_FEAR tlConvoSuffix += "RE" BREAK CASE CCDIA_COWER_HIGH_FEAR tlConvoSuffix += "SC" BREAK CASE CCDIA_RECEIVES_SCARE tlConvoSuffix += "RS" BREAK CASE CCDIA_STICKS_UP_FOR_OTHER tlConvoSuffix += "SF" BREAK CASE CCDIA_SEES_OTHER_KILLED tlConvoSuffix += "HK" BREAK CASE CCDIA_SHOT_NEAR tlConvoSuffix += "SN" BREAK CASE CCDIA_SHOT_DIRECTLY_AT tlConvoSuffix += "SA" BREAK CASE CCDIA_ALARM_GOES_OFF tlConvoSuffix += "AL" BREAK CASE CCDIA_ALARM_GOES_OFF_INITIAL tlConvoSuffix += "GO" BREAK // Hero stuff, specific peds will have these CASE CCDIA_HERO_ALARM_START tlConvoSuffix += "GP" iLineNumber = 1 BREAK CASE CCDIA_HERO_ALARM_CAUGHT tlConvoSuffix += "DPA" iLineNumber = 1 BREAK CASE CCDIA_HERO_ALARM_COMPLETE tlConvoSuffix += "PA" iLineNumber = 1 BREAK CASE CCDIA_HERO_PHONE_START tlConvoSuffix += "DP" iLineNumber = 1 BREAK CASE CCDIA_HERO_PHONE_CAUGHT tlConvoSuffix += "PA" iLineNumber = 1 BREAK CASE CCDIA_HERO_PHONE_COMPLETE tlConvoSuffix += "CC" iLineNumber = 1 BREAK CASE CCDIA_HERO_PHONE_APOLOGISE tlConvoSuffix += "SS" iLineNumber = 1 BREAK CASE CCDIA_HERO_GUN_START tlConvoSuffix += "DG" iLineNumber = 1 BREAK CASE CCDIA_HERO_GUN_CAUGHT tlConvoSuffix += "GA" iLineNumber = 1 BREAK CASE CCDIA_HERO_GUN_COMPLETE tlConvoSuffix += "A" iLineNumber = 1 BREAK DEFAULT RETURN FALSE BREAK ENDSWITCH RETURN TRUE ENDFUNC FUNC BOOL GET_CROWD_CONTROL_PED_DIALOGUE_ROOT_LABEL( CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_HEIST_TYPE eHeistType, TEXT_LABEL_23 &tlRootLabel, TEXT_LABEL_23 &tlVoiceName, INT &iLineNumber ) TEXT_LABEL_15 tlRaceGenderPrefix IF GET_CROWD_CONTROL_VOICE_RACE_GENDER_PREFIX( ePed, eHeistType, tlRaceGenderPrefix, tlVoiceName ) TEXT_LABEL_15 tlConvoSuffix IF GET_CROWD_CONTROL_PED_DIALOGUE_CONVO_SUFFIX( eDialogue, tlConvoSuffix, iLineNumber ) tlRootLabel = "OBHF_" tlRootLabel += tlRaceGenderPrefix tlRootLabel += tlConvoSuffix RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC PROC PLAY_CROWD_CONTROL_AMBIENT_SPEECH( PED_INDEX pedCrowd, CROWD_CONTROL_PED_ENUM ePed, CROWD_CONTROL_DIALOGUE eDialogueToPlay, CROWD_CONTROL_HEIST_TYPE eHeistType, BOOL bNeedsToInterrupt, BOOL bSyncOverNetwork = FALSE ) TEXT_LABEL_23 tlConvo TEXT_LABEL_23 tlVoiceName INT iLineNumber = -1 IF GET_CROWD_CONTROL_PED_DIALOGUE_ROOT_LABEL( ePed, eDialogueToPlay, eHeistType, tlConvo, tlVoiceName, iLineNumber ) SPEECH_PARAMS eParams // IF bNeedsToInterrupt // eParams = SPEECH_PARAMS_INTERRUPT_SHOUTED_CRITICAL // ELSE // eParams = SPEECH_PARAMS_FORCE_SHOUTED_CRITICAL // ENDIF UNUSED_PARAMETER(bNeedsToInterrupt) eParams = SPEECH_PARAMS_FORCE_SHOUTED_CRITICAL PLAY_AMBIENT_SPEECH_USING_LINE_FROM_CONVERSATION( pedCrowd, tlConvo, tlVoiceName, iLineNumber, eParams, bSyncOverNetwork ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_AMBIENT_SPEECH() - Conversation Root = ", tlConvo, " Voice Name = ", tlVoiceName, " iLineNumber = ", iLineNumber, " Params = ", AUDIO_SPEECH_GET_PARAM_STRING_FROM_ENUM( eParams ) ) ENDIF ENDPROC FUNC AUD_DAMAGE_REASON GET_CROWD_CONTROL_PED_ALTERNATIVE_PAIN_DIALOGUE( CROWD_CONTROL_DIALOGUE eDialogue ) /* For screams only use the following: SCREAM_PANIC_SHORT = really short "huh" SCREAM_PANIC = longer "huh" SCREAM_SHOCKED = quick "aaahh" SCREAM_TERROR = longer "ahhhh" Other screams may or may not be present on a per ped basis */ SWITCH eDialogue CASE CCDIA_APPROACH RETURN AUD_DAMAGE_REASON_SCREAM_PANIC_SHORT BREAK CASE CCDIA_COWER_HIGH_FEAR CASE CCDIA_COWER_LOW_FEAR CASE CCDIA_ALARM_GOES_OFF CASE CCDIA_ALARM_GOES_OFF_INITIAL SWITCH GET_RANDOM_INT_IN_RANGE( 0, 2 ) CASE 0 RETURN AUD_DAMAGE_REASON_WHIMPER BREAK CASE 1 RETURN AUD_DAMAGE_REASON_COWER BREAK ENDSWITCH BREAK CASE CCDIA_STICKS_UP_FOR_OTHER RETURN AUD_DAMAGE_REASON_SCREAM_PANIC BREAK CASE CCDIA_INITIAL_PANIC SWITCH GET_RANDOM_INT_IN_RANGE( 0, 2 ) CASE 0 RETURN AUD_DAMAGE_REASON_SCREAM_SHOCKED BREAK CASE 1 RETURN AUD_DAMAGE_REASON_SCREAM_PANIC BREAK ENDSWITCH BREAK CASE CCDIA_SHOT_DIRECTLY_AT RETURN AUD_DAMAGE_REASON_SCREAM_TERROR BREAK CASE CCDIA_SHOT_NEAR CASE CCDIA_SEES_OTHER_KILLED RETURN AUD_DAMAGE_REASON_SCREAM_SHOCKED BREAK CASE CCDIA_RECEIVES_SCARE SWITCH GET_RANDOM_INT_IN_RANGE( 0, 2 ) CASE 0 RETURN AUD_DAMAGE_REASON_SCREAM_SHOCKED BREAK CASE 1 RETURN AUD_DAMAGE_REASON_SCREAM_PANIC BREAK ENDSWITCH BREAK ENDSWITCH RETURN AUD_DAMAGE_REASON_DEFAULT ENDFUNC ENUM CROWD_CONTROL_DIALOGUE_PLAYBACK_FLAGS CCDIAPLAYBACK_NONE = 0 ,CCDIAPLAYBACK_FORCE_PAIN = 1 ,CCDIAPLAYBACK_FORCE_CRITICAL = 2 ENDENUM /// PURPOSE: /// Queues up a conversation locally and priority checks against what is already stored. Keeps this local ready to be packed and sent to the host later. /// PARAMS: /// sLocalPedData - peds local data where the info will be stored /// eDialogue - the dialogue you want to queue up /// bIsCritical - is it critical? this will affect if this conversation ignores timers, max number of speakers, interrupts, etc. PROC QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_DIALOGUE eDialogue, CROWD_CONTROL_DIALOGUE_PLAYBACK_FLAGS eFlags = CCDIAPLAYBACK_NONE ) #IF NOT IS_DEBUG_BUILD UNUSED_PARAMETER( sLocalData ) #ENDIF IF IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( eDialogue, sLocalPedData.eDialogueClientToHost ) OR IS_BITMASK_ENUM_AS_ENUM_SET( eFlags, CCDIAPLAYBACK_FORCE_CRITICAL ) // Update the local ped owners local ped data, this is needed for case we attempt to play more than 1 convo on 1 ped in the same update // we would decide here which takes priority for this ped sLocalPedData.eDialogueClientToHost = eDialogue IF IS_BITMASK_ENUM_AS_ENUM_SET( eFlags, CCDIAPLAYBACK_FORCE_PAIN ) SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) ELSE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET( eFlags, CCDIAPLAYBACK_FORCE_CRITICAL ) SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) ELSE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) ENDIF #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CDEBUG1LN( DEBUG_NET_MINIGAME, "QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), " - Conversation queued = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueClientToHost ), " - Force Pain = ", BOOL_TO_STRING( IS_BITMASK_ENUM_AS_ENUM_SET( eFlags, CCDIAPLAYBACK_FORCE_PAIN ) ), " - Force Critical = ", BOOL_TO_STRING( IS_BITMASK_ENUM_AS_ENUM_SET( eFlags, CCDIAPLAYBACK_FORCE_CRITICAL ) ) ) ENDIF #ENDIF ENDIF ENDPROC /// PURPOSE: /// Collects all the conversations on peds this machine owns and sends them on to the host /// PARAMS: /// sLocalPedData - local ped data which will have all the /// iNumCrowdPeds - number of crowd control peds PROC PROCESS_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST_QUEUE( INT iCrowdPed, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, INT &iPackedDialogueConversations[], INT &iPackedDialoguePainFlags, INT &iPackedDialogueCriticalFlags ) BOOL bDiscardDialogue bDiscardDialogue = FALSE // Theres something to send, add it to the packed data // To avoid spamming IF sLocalPedData.eDialogueClientToHost != CCDIA_NONE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitset, CCLOCALDATA_DebugLogDialogue ) CDEBUG1LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST_QUEUE() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueClientToHost ) ) ENDIF #ENDIF #IF NOT IS_DEBUG_BUILD UNUSED_PARAMETER(sLocalData) #ENDIF IF IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalPedData.timeDialogueLastBroadcast ) OR IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( sLocalPedData.eDialogueClientToHost ) OR IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) SET_PACKED_BITFIELD_VALUE_IN_ARRAY( iPackedDialogueConversations, iCrowdPed, ciCC_DialogueDataBitWidth, ENUM_TO_INT( sLocalPedData.eDialogueClientToHost ) ) IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) SET_BIT( iPackedDialoguePainFlags, iCrowdPed ) ELSE CLEAR_BIT( iPackedDialoguePainFlags, iCrowdPed ) ENDIF IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) SET_BIT( iPackedDialogueCriticalFlags, iCrowdPed ) ELSE CLEAR_BIT( iPackedDialogueCriticalFlags, iCrowdPed ) ENDIF #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitset, CCLOCALDATA_DebugLogDialogue ) CDEBUG1LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST_QUEUE() packed for broadcast" ) ENDIF #ENDIF sLocalPedData.timeDialogueLastBroadcast = GET_TIME_OFFSET( GET_NETWORK_TIME(), 1000 + ( GET_RANDOM_INT_IN_RANGE( 0, 5 ) * 250 ) ) // 1 -> 2 seconds (250ms intervals) ELSE bDiscardDialogue = TRUE ENDIF // Reset this machines local dialogue data if not the host (leave alone for the host unless bDiscardDialogue = TRUE) IF bDiscardDialogue OR NOT NETWORK_IS_HOST_OF_THIS_SCRIPT() sLocalPedData.eDialogueClientToHost = CCDIA_NONE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitset, CCLOCALDATA_DebugLogDialogue ) IF NOT NETWORK_IS_HOST_OF_THIS_SCRIPT() CDEBUG1LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST_QUEUE() discarded(not host)" ) ELSE CDEBUG1LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST_QUEUE() discarded(timer not ready)" ) ENDIF ENDIF #ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Processes the queue of conversations that have come in from other clients (and itself) to decide who is allowed to speak (and who to ignore). /// PARAMS: /// niPed - array of mission controller peds /// sLocalData - local data /// sLocalPedData - local ped data (this will have the received CLIENT to HOST conversations stored ) /// iCrowdControlCloudIndex - lookup indices for crowd control peds /// iNumCrowdControlPeds - number of crowd control peds in this crowd PROC PROCESS_CROWD_CONTROL_DIALOGUE_SELECTION( NETWORK_INDEX &niPed[], CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[], INT &iCrowdControlCloudIndex[], INT iNumCrowdControlPeds ) INT i // INITIAL PASS - Last time talking timer & number of current speakers //------------------------------------------------------------------------------ INT iNumberOfPedsCurrentlySpeaking INT iNumberOfPedsCurrentlyPlayingPain PED_INDEX pedsTemp[FMMC_MAX_CROWD_PEDS] BOOL bPedInjured[FMMC_MAX_CROWD_PEDS] BOOL bIsAmbientSpeechPlaying[FMMC_MAX_CROWD_PEDS] BOOL bIsAnySpeechPlaying[FMMC_MAX_CROWD_PEDS] FOR i = 0 TO iNumCrowdControlPeds-1 INT iPed = iCrowdControlCloudIndex[i] IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPed[iPed] ) pedsTemp[i] = NET_TO_PED( niPed[iPed] ) bPedInjured[i] = IS_PED_INJURED( pedsTemp[i] ) IF NOT bPedInjured[i] bIsAnySpeechPlaying[i] = IS_ANY_SPEECH_PLAYING( pedsTemp[i] ) bIsAmbientSpeechPlaying[i] = IS_AMBIENT_SPEECH_PLAYING( pedsTemp[i] ) ELSE bIsAnySpeechPlaying[i] = FALSE bIsAmbientSpeechPlaying[i] = FALSE ENDIF IF NOT bPedInjured[i] IF bIsAmbientSpeechPlaying[i] iNumberOfPedsCurrentlySpeaking++ ELIF bIsAnySpeechPlaying[i] iNumberOfPedsCurrentlyPlayingPain++ ENDIF ENDIF ENDIF ENDFOR #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() <1st PASS> - Count the speakers - Total speakers = ", iNumberOfPedsCurrentlySpeaking + iNumberOfPedsCurrentlyPlayingPain, "/", ciCC_MaxNumberOfSpeakers, " Dialogue = ", iNumberOfPedsCurrentlySpeaking, "/", ciCC_MaxNumberOfAmbientDialogue, " Pain = ", iNumberOfPedsCurrentlyPlayingPain, "/", ciCC_MaxNumberOfPain ) CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) ENDIF #ENDIF // 2nd PASS - Find the highest priority dialogues to play //------------------------------------------------------------------------------ #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() <2nd PASS> - Populating the queue.") CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) ENDIF #ENDIF // Create random look up table to mix up the queue INT iRnd[FMMC_MAX_CROWD_PEDS] FOR i = 0 TO iNumCrowdControlPeds-1 // Initialise numbers iRnd[i] = i ENDFOR FOR i = 0 TO iNumCrowdControlPeds-1 // Randomise numbers INT iRndIndex = GET_RANDOM_INT_IN_RANGE( 0, iNumCrowdControlPeds ) INT iTemp = iRnd[i] iRnd[i] = iRnd[iRndIndex] iRnd[iRndIndex] = iTemp ENDFOR // Initialise priority queue to -1 INT iCrowdNumSpeakerPriorityQueue[FMMC_MAX_CROWD_PEDS] FOR i = 0 TO COUNT_OF( iCrowdNumSpeakerPriorityQueue ) - 1 iCrowdNumSpeakerPriorityQueue[i] = -1 ENDFOR // Go through each ped wanting to speak and check them against the priority queue FOR i = 0 TO iNumCrowdControlPeds-1 INT iCrowdPed = iRnd[i] // randomises the IF sLocalPedData[iCrowdPed].eDialogueClientToHost != CCDIA_NONE IF pedsTemp[iCrowdPed] != NULL IF NOT bPedInjured[iCrowdPed] AND ( NOT bIsAnySpeechPlaying[iCrowdPed] //OR IS_BIT_SET_ENUM( sLocalPedData[iCrowdPed].iBitset, CCLOCALPEDDATA_DialogueClientToHostCritical ) ) OR IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalPedData[iCrowdPed].eDialogueCurrentlyPlaying ) ) BOOL bConvoStored INT j // Run through the queue comparing with whats already stored FOR j = 0 TO COUNT_OF( iCrowdNumSpeakerPriorityQueue ) - 1 // Can store this, is higher priority IF iCrowdNumSpeakerPriorityQueue[j] = -1 OR IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalPedData[iCrowdNumSpeakerPriorityQueue[j]].eDialogueClientToHost ) // Push everything down 1 entry INT k k = COUNT_OF( iCrowdNumSpeakerPriorityQueue ) - 1 // If theres anything currently stored in the bottom of the queue, get rid of it as we're not going to use it IF iCrowdNumSpeakerPriorityQueue[k] != -1 #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - [", iCrowdNumSpeakerPriorityQueue[k], "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdNumSpeakerPriorityQueue[k]].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdNumSpeakerPriorityQueue[k]].eDialogueClientToHost ), " discared from SLOT[", k, "]" ) ENDIF #ENDIF sLocalPedData[k].eDialogueClientToHost = CCDIA_NONE CLEAR_BIT_ENUM( sLocalPedData[k].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) ENDIF WHILE k >= j IF k = j iCrowdNumSpeakerPriorityQueue[k] = iCrowdPed ELSE iCrowdNumSpeakerPriorityQueue[k] = iCrowdNumSpeakerPriorityQueue[k-1] ENDIF k-- ENDWHILE bConvoStored = TRUE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - [", iCrowdPed, "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdPed].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdPed].eDialogueClientToHost ), " inserted into queue SLOT[", j, "]" ) ENDIF #ENDIF j = COUNT_OF( iCrowdNumSpeakerPriorityQueue ) // break loop ENDIF ENDFOR // Convo wasn't high enough priority to beat other conversations, erase IF NOT bConvoStored #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdPed].eDialogueClientToHost ), " not high enough priority, cleared dialogue" ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - [", iCrowdPed, "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdPed].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdPed].eDialogueClientToHost ), " discarded, priority not high enough" ) ENDIF #ENDIF sLocalPedData[iCrowdPed].eDialogueClientToHost = CCDIA_NONE CLEAR_BIT_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CDEBUG1LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - [", iCrowdPed, "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdPed].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdPed].eDialogueClientToHost ), " - Unable to start queue up of this dialogue, ped already speaking " ) ENDIF #ENDIF ENDIF ENDIF ENDIF ENDFOR // FINAL(3rd) PASS - Play the dialogue we have queued //------------------------------------------------------------------------------ #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - <3rd PASS> Processing the queue." ) CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - Queue Snapshop" ) ENDIF #ENDIF // Print the queue FOR i = 0 TO COUNT_OF( iCrowdNumSpeakerPriorityQueue ) - 1 IF iCrowdNumSpeakerPriorityQueue[i] != -1 #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() SLOT[", i, "] = ", "[", iCrowdNumSpeakerPriorityQueue[i], "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdNumSpeakerPriorityQueue[i]].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdNumSpeakerPriorityQueue[i]].eDialogueClientToHost ) ) ENDIF #ENDIF ENDIF ENDFOR #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "\n" ) ENDIF #ENDIF INT iPackedDialogueConversations[2] INT iPackedDialogueIsPainFlags FOR i = 0 TO COUNT_OF( iCrowdNumSpeakerPriorityQueue )-1 #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - Processing SLOT[", i, "]" ) ENDIF #ENDIF // Ped queued IF iCrowdNumSpeakerPriorityQueue[i] != -1 #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() [", iCrowdNumSpeakerPriorityQueue[i], "] ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iCrowdNumSpeakerPriorityQueue[i]].eCreatorAssignedPedID ), " - Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData[iCrowdNumSpeakerPriorityQueue[i]].eDialogueClientToHost ) ) ENDIF #ENDIF INT iCrowdPed = iCrowdNumSpeakerPriorityQueue[i] IF sLocalPedData[iCrowdPed].eDialogueClientToHost != CCDIA_NONE IF pedsTemp[iCrowdPed] != NULL IF NOT bPedInjured[iCrowdPed] // Ped is not already speaking AND ( NOT bIsAnySpeechPlaying[iCrowdPed] // OR the new dialogue is a higher priority than what is already being said // AND is critical OR ( ( IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( sLocalPedData[iCrowdPed].eDialogueClientToHost ) OR IS_BIT_SET_ENUM( sLocalPedDAta[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) ) AND IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalPedData[iCrowdPed].eDialogueCurrentlyPlaying ) ) ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Attempting dialogue - Speakers(Total) = ", iNumberOfPedsCurrentlySpeaking + iNumberOfPedsCurrentlyPlayingPain, "/", ciCC_MaxNumberOfSpeakers, " Dialogue = ", iNumberOfPedsCurrentlySpeaking, "/", ciCC_MaxNumberOfAmbientDialogue, " Pain = ", iNumberOfPedsCurrentlyPlayingPain, "/", ciCC_MaxNumberOfPain ) ENDIF #ENDIF BOOL bCanPlayThisDialogue TEXT_LABEL_23 tlConvo = "" TEXT_LABEL_23 tlDummy = "" INT iLine = -1 IF GET_CROWD_CONTROL_PED_DIALOGUE_ROOT_LABEL( sLocalPedData[iCrowdPed].eCreatorAssignedPedID, sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalData.eHeistType, tlConvo, tlDummy, iLine ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - Found Root Label \"", tlConvo, "\" iLine = ", iLine ) ENDIF #ENDIF TEXT_LABEL_23 tlConvoFilename = GET_CONVERSATION_LINE_FILENAME_FROM_CONVERSATION_ROOT( tlConvo, iLine ) IF NOT IS_STRING_NULL_OR_EMPTY( tlConvoFilename ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - Convo Filename \"", tlConvoFilename, "\" does exist!" ) ENDIF #ENDIF bCanPlayThisDialogue = TRUE ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() - Convo Filename \"", tlConvoFilename, "\" does not exist" ) ENDIF #ENDIF ENDIF ENDIF // SELECT - PLAY AMBIENT SPEECH //---------------------------------------------------------------- // IF this dialogue context exists // AND we don't specifically want to play pain // AND we've checked the random chance for this context IF bCanPlayThisDialogue AND NOT IS_BIT_SET_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) AND CHECK_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_RANDOM_CHANCE( sLocalPedData[iCrowdPed].eDialogueClientToHost ) // Only ever have CCDIA_ALARM_GOES_OFF_INITIAL said once // by a ped that definitely has the dialogue AND ( sLocalPedData[iCrowdPed].eDialogueClientToHost != CCDIA_ALARM_GOES_OFF_INITIAL OR NOT IS_BIT_SET_ENUM( sData.iBitSet, CCDATA_RaiseAlarmDiagloue ) ) // AND is this a critical line of dialogue (actual or forced) AND ( ( IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( sLocalPedData[iCrowdPed].eDialogueClientToHost ) OR IS_BIT_SET_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) ) // OR context timer for this dialogue has expired and there is room for another speaker OR ( iNumberOfPedsCurrentlySpeaking < ciCC_MaxNumberOfAmbientDialogue AND HAS_CROWD_CONTROL_GLOBAL_DIALOGUE_CONTEXT_TIMER_EXPIRED( sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalData ) AND HAS_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_TIMER_EXPIRED( sLocalPedData[iCrowdPed].eDialogueClientToHost, sLocalPedData[iCrowdPed] ) ) ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() HOST wants to play ambient speech." ) ENDIF #ENDIF // Already speaking/playing pain IF bIsAnySpeechPlaying[iCrowdPed] // Was playing dialogue, counters not change IF NOT bIsAmbientSpeechPlaying[iCrowdPed] iNumberOfPedsCurrentlyPlayingPain-- iNumberOfPedsCurrentlySpeaking++ ENDIF #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Ambient speech already playing - OVERRIDING" ) ENDIF #ENDIF // Wasn't playing anything ELSE iNumberOfPedsCurrentlySpeaking++ ENDIF IF sLocalPedData[iCrowdPed].eDialogueClientToHost = CCDIA_ALARM_GOES_OFF_INITIAL SET_BIT_ENUM( sData.iBitSet, CCDATA_RaiseAlarmDiagloue ) ENDIF // Store ready to be played (for this machine) sLocalPedData[iCrowdPed].eDialogueHostToClient = sLocalPedData[iCrowdPed].eDialogueClientToHost CLEAR_BIT_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueHostToClientPain ) // Host resets the context timer and sends it to the remote players too as it uses a random delay // (if done on each machine the delay would be different for each machine) RESET_CROWD_CONTROL_PED_DIALOGUE_CONTEXT_TIMER( sLocalPedData[iCrowdPed].eDialogueHostToClient, sLocalPedData[iCrowdPed] ) RESET_CROWD_CONTROL_GLOBAL_DIALOGUE_CONTEXT_TIMER( sLocalPedData[iCrowdPed].eDialogueHostToClient, sLocalData ) // Also pack ready for broadcast (to all other remote machines) SET_PACKED_BITFIELD_VALUE_IN_ARRAY_FROM_ENUM( iPackedDialogueConversations, iCrowdPed, ciCC_DialogueDataBitWidth, sLocalPedData[iCrowdPed].eDialogueClientToHost ) CLEAR_BIT( iPackedDialogueIsPainFlags, iCrowdPed ) // SELECT - PLAY PAIN //---------------------------------------------------------------- ELIF NOT bIsAnySpeechPlaying[iCrowdPed] OR IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( sLocalPedData[iCrowdPed].eDialogueClientToHost ) OR IS_BIT_SET_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) // ... Check if the ped has an alternative Pain based dialogue // Force through critical pain IF iNumberOfPedsCurrentlyPlayingPain < ciCC_MaxNumberOfPain OR sLocalPedData[iCrowdPed].eDialogueClientToHost = CCDIA_INITIAL_PANIC OR IS_BIT_SET_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) IF GET_CROWD_CONTROL_PED_ALTERNATIVE_PAIN_DIALOGUE( sLocalPedData[iCrowdPed].eDialogueClientToHost ) != AUD_DAMAGE_REASON_DEFAULT #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() HOST wants to play pain audio" ) ENDIF #ENDIF // Store ready to be played sLocalPedData[iCrowdPed].eDialogueHostToClient = sLocalPedData[iCrowdPed].eDialogueClientToHost SET_BIT_ENUM( sLocalPedData[iCrowdPed].iBitSet, CCLOCALPEDDATA_DialogueHostToClientPain ) // Also pack ready for broadcast SET_PACKED_BITFIELD_VALUE_IN_ARRAY_FROM_ENUM( iPackedDialogueConversations, iCrowdPed, ciCC_DialogueDataBitWidth, sLocalPedData[iCrowdPed].eDialogueClientToHost ) SET_BIT( iPackedDialogueIsPainFlags, iCrowdPed ) // Already speaking/playing pain IF bIsAnySpeechPlaying[iCrowdPed] // Was playing dialogue, counters not change IF NOT bIsAmbientSpeechPlaying[iCrowdPed] iNumberOfPedsCurrentlyPlayingPain++ iNumberOfPedsCurrentlySpeaking-- ENDIF ELSE iNumberOfPedsCurrentlyPlayingPain++ ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() No alt pain version of this dialogue" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Too many speakers, can't play pain audio" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Ped already speaking, cant play pain audio" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Ped is dead" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() Net id invalid" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() No dialogue stored" ) ENDIF #ENDIF ENDIF ELSE #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_DIALOGUE_QUEUE() SLOT empty" ) ENDIF #ENDIF ENDIF ENDFOR // Broadcast dialogue to be played to all clients, if there is something to play IF iPackedDialogueConversations[0] != 0 OR iPackedDialogueConversations[1] != 0 BROADCAST_FMMC_CC_DIALOGUE_HOST_TO_CLIENTS( iPackedDialogueConversations, iPackedDialogueIsPainFlags ) ENDIF // Reset client to host data (DO NOT ERASE HostToClient data, otherwise this machine won't play any dialogue locally) FOR i = 0 TO iNumCrowdControlPeds-1 sLocalPedData[i].eDialogueClientToHost = CCDIA_NONE CLEAR_BIT_ENUM( sLocalPedData[i].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForcePain ) CLEAR_BIT_ENUM( sLocalPedData[i].iBitSet, CCLOCALPEDDATA_DialogueClientToHostForceCritical ) ENDFOR ENDPROC /// PURPOSE: /// Dialogue for each ped that has come in from the host and now needs to be player is played here locally on this machine. Each machine will need to call this in order to process playing the dialogue locally. /// PARAMS: /// niPeds - array of mission controller peds /// iCrowdPedCloudIndex - lookup array used to index crowd control peds /// iNumCrowdPeds - number of crowd control peds available /// sLocalPedData - local ped data (this will have the received HOST to CLIENT conversations stored ) /// sLocalData - other local cached data PROC PROCESS_CROWD_CONTROL_DIALOGUE_HOST_TO_CLIENT_QUEUE( PED_INDEX ped, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_LOCAL_DATA &sLocalData ) IF sLocalPedData.eDialogueHostToClient != CCDIA_NONE BOOL bIsAnySpeechPlaying = IS_ANY_SPEECH_PLAYING( ped ) BOOL bInterrupt IF bIsAnySpeechPlaying // Only interrupt if higher priority and its either critical or is we are interrupting dialogue with pain audio IF IS_CROWD_CONTROL_PED_DIALOGUE_PRIORITY( sLocalPedData.eDialogueHostToClient, sLocalPedData.eDialogueCurrentlyPlaying ) AND ( IS_CROWD_CONTROL_PED_DIALOGUE_CRITICAL( sLocalPedData.eDialogueHostToClient ) OR ( IS_AMBIENT_SPEECH_PLAYING( ped ) AND IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueHostToClientPain ) ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PLAYING_LOCAL_DIALOGUE() - IS_ANY_SPEECH_PLAYING() = true, Calling STOP_CURRENT_PLAYING_SPEECH()" ) STOP_CURRENT_PLAYING_SPEECH( ped ) bInterrupt = TRUE ENDIF ELSE CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PLAYING_LOCAL_DIALOGUE() - IS_ANY_SPEECH_PLAYING() = false, nothing to stop." ) ENDIF IF NOT bIsAnySpeechPlaying OR bInterrupt IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueHostToClientPain ) PLAY_CROWD_CONTROL_AMBIENT_SPEECH( ped, sLocalPedData.eCreatorAssignedPedID, sLocalPedData.eDialogueHostToClient, sLocalData.eHeistType, bInterrupt ) #IF IS_DEBUG_BUILD IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DebugLogDialogue ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PLAYING_LOCAL_DIALOGUE() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), " - Played Ambient Speech = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueHostToClient ) ) ENDIF #ENDIF ELSE AUD_DAMAGE_REASON ePainAudio = GET_CROWD_CONTROL_PED_ALTERNATIVE_PAIN_DIALOGUE( sLocalPedData.eDialogueHostToClient ) PLAY_PAIN( ped, ePainAudio, 0, FALSE ) #IF IS_DEBUG_BUILD CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PLAYING_LOCAL_DIALOGUE() - ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ), " - Played Pain Dialogue = ", GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueHostToClient ), " - Pain Audio = ", ePainAudio ) #ENDIF ENDIF sLocalPedData.eDialogueCurrentlyPlaying = sLocalPedData.eDialogueHostToClient // Reset peds local dialogue data sLocalPedData.eDialogueHostToClient = CCDIA_NONE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_DialogueHostToClientPain ) ELSE // Keep dialogue until the ped is no longer speaking ENDIF ENDIF ENDPROC PROC PROCESS_CROWD_CONTROL_FEAR( CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, NETWORK_INDEX &niPeds[], CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[], BOOL bRestrictCrowdPed ) INT i BOOL bBlockFearDrop // Do not update fear if fear is currently blocked for that rule IF IS_BIT_SET_ENUM( sData.iBitSet, CCDATA_FearFailsBlocked ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearUnblocked ) EXIT ELSE // 2184755 // also do not update the fear for fleeca for the first 5 seconds of the fear becoming unblocked IF sLocalData.eHeistType = CCHEIST_CUSTOM_FLEECA IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearUnblocked ) sLocalData.timeFearFailsUnblocked = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearUnblocked ) ENDIF IF IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalData.timeFearFailsUnblocked, 5000 ) ) bBlockFearDrop = TRUE ENDIF ENDIF ENDIF PED_INDEX pedsTemp[FMMC_MAX_CROWD_PEDS] BOOL bPedInjured[FMMC_MAX_CROWD_PEDS] BOOL bHasControl[FMMC_MAX_CROWD_PEDS] // Pre-update //---------------------------------------------------------------------------------------------------- // Count the number of peds alive left to influence the fear level INT iCrowdSize FLOAT fInfluenceDirectThreatTotal, fInfluenceShoutingTotal FOR i = 0 TO sData.iNumCrowdControlPeds-1 INT iPed = sData.iCrowdControlCloudIndex[i] IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPeds[iPed] ) pedsTemp[i] = NET_TO_PED( niPeds[iPed] ) bPedInjured[i] = IS_PED_INJURED( pedsTemp[i] ) bHasControl[i] = NETWORK_HAS_CONTROL_OF_NETWORK_ID( niPeds[iPed] ) IF NOT bPedInjured[i] iCrowdSize++ fInfluenceDirectThreatTotal += sPedData[i].fInfluenceDirectThreat fInfluenceShoutingTotal += sPedData[i].fInfluenceShouting ENDIF ELSE pedsTemp[i] = NULL bPedInjured[i] = FALSE ENDIF ENDFOR // Work out the deficit of fear and redistribute it to other peds that are no currently being intimidated FLOAT fLowerInfluenceThreshold = 0.5 * iCrowdSize FLOAT fInfluenceDirectThreatDeficit = FMAX( fLowerInfluenceThreshold - fInfluenceDirectThreatTotal, 0.0 ) FLOAT fInfluenceShoutingDeficit = FMAX( fLowerInfluenceThreshold - fInfluenceShoutingTotal, 0.0 ) // Find the threat we want to use for fear //---------------------------------------------------------------------------------------------------- CROWD_CONTROL_THREAT_TYPE eThreatUsedForFear[FMMC_MAX_CROWD_PEDS] INT iRedistibuteDirectThreatDeficitCount, iRedistributeShoutDeficitCount BOOL bShouldUpdateFear[FMMC_MAX_CROWD_PEDS] FOR i = 0 TO sData.iNumCrowdControlPeds-1 IF pedsTemp[i] != NULL IF NOT bPedInjured[i] // HOST & OWNER ONLY: Work out this peds contribution to fear change IF NETWORK_IS_HOST_OF_THIS_SCRIPT() OR bHasControl[i] eThreatUsedForFear[i] = sLocalPedData[i].eBiggestThreat BOOL bPlayingIntro IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedsTemp[i], CCPANIM_INTRO_LOOP, sLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedsTemp[i], CCPANIM_INTRO, sLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) bPlayingIntro = TRUE ENDIF // Don't update this ped's fear while they are forcibly restricted IF NOT IS_CROWD_CONTROL_PED_RESTRICTED( sLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, CCPS_HERO_ATTEMPT, bRestrictCrowdPed ) // and not until the intro scene has finished AND NOT bPlayingIntro AND sPedData[i].eState != CCPS_COMBAT AND IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCDATA_Active ) bShouldUpdateFear[i] = TRUE IF IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) CLEAR_BIT_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) ENDIF // Update ped's fear level // Use threat type overrides for different states SWITCH sPedData[i].eState CASE CCPS_INVALID CASE CCPS_INTRO CASE CCPS_HERO // NO FEAR! eThreatUsedForFear[i] = CCTHREAT_NONE BREAK CASE CCPS_COWER // no override BREAK CASE CCPS_FLINCH IF eThreatUsedForFear[i] < CCTHREAT_PROXIMITY eThreatUsedForFear[i] = CCTHREAT_PROXIMITY ENDIF BREAK CASE CCPS_BEATDOWN // If in the beat down state force the fear to be at least the beating fear IF eThreatUsedForFear[i] < CCTHREAT_BEATING eThreatUsedForFear[i] = CCTHREAT_BEATING ENDIF BREAK CASE CCPS_HERO_ATTEMPT // Only decrease the fear at this point as we will snap their fear when caught instead eThreatUsedForFear[i] = CCTHREAT_NONE BREAK ENDSWITCH // OWNER ONLY: Count the number of peds whos influence should increase IF bHasControl[i] IF NOT SHOULD_CROWD_CONTROL_PED_DIRECT_THREAT_INFLUENCE_DECREASE( eThreatUsedForFear[i] ) iRedistibuteDirectThreatDeficitCount++ ENDIF IF NOT SHOULD_CROWD_CONTROL_PED_SHOUT_THREAT_INFLUENCE_DECREASE( eThreatUsedForFear[i] ) iRedistributeShoutDeficitCount++ ENDIF ENDIF ELSE // Only mark as locked while not playing the intro IF NOT bPlayingIntro IF NOT IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) SET_BIT_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) ENDIF ELSE IF IS_BIT_SET_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) CLEAR_BIT_ENUM( sPedData[i].iBitSet, CCPEDDATA_FearLocked ) ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDFOR // Redistribute any deficit of influence and update the peds fear //---------------------------------------------------------------------------------------------------- FLOAT fFearDelta FLOAT fInfluenceDirectThreatDeficitPerPed = fInfluenceDirectThreatDeficit / iRedistibuteDirectThreatDeficitCount FLOAT fInfluenceShoutingDeficitPerPed = fInfluenceShoutingDeficit / iRedistributeShoutDeficitCount FOR i = 0 TO sData.iNumCrowdControlPeds-1 IF bShouldUpdateFear[i] IF pedsTemp[i] != NULL IF NOT bPedInjured[i] // OWNER ONLY: Update the influence IF bHasControl[i] UPDATE_CROWD_CONTROL_PED_DIRECT_THREAT_INFLUENCE( sPedData[i], sLocalPedData[i], eThreatUsedForFear[i], fInfluenceDirectThreatDeficitPerPed ) UPDATE_CROWD_CONTROL_PED_SHOUT_THREAT_INFLUENCE( sPedData[i], sLocalPedData[i], eThreatUsedForFear[i], fInfluenceShoutingDeficitPerPed ) ENDIF // HOST ONLY: Take fear contribution IF NETWORK_IS_HOST_OF_THIS_SCRIPT() fFearDelta += GET_CROWD_CONTROL_PED_FEAR_DELTA( sData, sLocalData, sPedData[i], sLocalPedData[i].pedBiggestThreat, eThreatUsedForFear[i], i, iCrowdSize ) ENDIF ENDIF ENDIF ENDIF ENDFOR // HOST ONLY: calculate new fear value and update broadcast data when possible //---------------------------------------------------------------------------------------------------- IF NETWORK_IS_HOST_OF_THIS_SCRIPT() IF fFearDelta != 0 AND ( NOT bBlockFearDrop OR fFearDelta > 0 ) FLOAT fChangeRate IF fFearDelta > 0.0 // Adjust the change rate in the ranges 0.0 -> 75.0 FLOAT fRange = 100.0 - cfCC_PedBreakoutCowerThreshold FLOAT fAlpha = CLAMP( FMIN( sLocalData.fFear / fRange, 100.0 ), 0.0, 1.0 ) // As the fear increases, make the increase rate decrease fChangeRate = INTERP_FLOAT( cfCC_FearIncreaseRateMax, cfCC_FearIncreaseRateMin, fAlpha ) ELIF fFearDelta < 0.0 // Adjust the change rate in the ranges 25.0 -> 100.0 FLOAT fRange = 100.0 - cfCC_PedBreakoutCowerThreshold FLOAT fAlpha = CLAMP( FMAX( sLocalData.fFear - cfCC_PedBreakoutCowerThreshold, 0.0 ) / fRange, 0.0, 1.0 ) // As the fear decreases, make the decrease rate decrease fChangeRate = INTERP_FLOAT( cfCC_FearDecreaseRateMin, cfCC_FearDecreaseRateMax, fAlpha ) ENDIF // Adjust for ACCEL/DECEL fFearDelta *= fChangeRate // Adjust for framerate fFearDelta *= TIMESTEP() // Apply the fear change sLocalData.fFear = CLAMP( sLocalData.fFear + fFearDelta, 0.0, 100.0 ) ENDIF ENDIF // HOST BOOL bFearUpdated IF NETWORK_IS_HOST_OF_THIS_SCRIPT() // Check if we can update the server fear value IF ( sLocalData.fFear != sData.fFear AND sLocalData.iUpdateTimer >= 10 ) // values are different but wait for at least 10 frames to have elapsed since previous update OR ABSF( sData.fFear - sLocalData.fFear ) >= 3.0 // difference is greater than 3%, update now // Update the server fear value sData.fFear = sLocalData.fFear bFearUpdated = TRUE sLocalData.iUpdateTimer = 0 // reset the timer ELSE sLocalData.iUpdateTimer++ // increment timer ENDIF // REMOTE ELSE // Server value differs to ours IF sData.fFear != sLocalData.fFear // pull the updated value from the server sLocalData.fFear = sData.fFear bFearUpdated = TRUE ENDIF ENDIF // An update has occurred on the host or a remote player, update interpolation rate IF bFearUpdated sLocalData.fIntimidationBarInterpRate = ABSF( sLocalData.fIntimidationBar - sLocalData.fFear ) ENDIF ENDPROC PROC PROCESS_CROWD_CONTROL_PED_AI( PED_INDEX pedCrowd, CROWD_CONTROL_SERVER_DATA &sCrowdControlData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sCrowdControlPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, INT iPed, INT iCrowdStructID, BOOL bRestrictCrowdPed, BOOL bIsInjured ) IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HasBeenInitialised ) CROWD_CONTROL_THREAT_TYPE eThreatActual = sLocalPedData.eBiggestThreat CROWD_CONTROL_THREAT_TYPE eThreatFelt = sLocalPedData.eBiggestThreat // Ped state //------------------------------------------------ // Ped has been killed IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_Dead ) OR ( DOES_ENTITY_EXIST( pedCrowd ) AND bIsInjured ) IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_KnockedOut ) IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_Dead ) sLocalPedData.timeDied = GET_NETWORK_TIME() SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_Dead ) ENDIF IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_DeadProcessed ) IF NETWORK_IS_HOST_OF_THIS_SCRIPT() sCrowdControlData.iNumHitsRemaining -= ciCC_BeatdownHitsLostOnPedDeath ELSE BROADCAST_FMMC_CC_PED_BEATDOWN_HIT( -ciCC_BeatdownHitsLostOnPedDeath ) ENDIF SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_DeadProcessed ) ENDIF ENDIF ENDIF // Hero details //------------------------------------------------ CROWD_CONTROL_PED_HERO_ACTION eHeroAction = CCHERO_NONE // Animated hero //IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) eHeroAction = GET_CROWD_CONTROL_PED_HERO_ACTION_FOR_ANIMATED_PED( sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // None anim hero (set by content creators) ELSE eHeroAction = INT_TO_ENUM( CROWD_CONTROL_PED_HERO_ACTION, g_FMMC_STRUCT_ENTITIES.sPlacedPed[iPed].iCrowdControlAction ) IF eHeroAction = CCHERO_ALARM eHeroAction = CCHERO_NONE ENDIF ENDIF // Reset hero attempted flag if this ped is no longer a hero IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroAttempted ) IF NOT IS_BIT_SET( sCrowdControlData.iCurrentActiveHeros, iCrowdStructID ) CLEAR_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroAttempted ) ENDIF ENDIF // Fail checks //------------------------------------------------ // While crowd control is active and no other fail has already occured // Also don't fail if we have already passed IF IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) AND NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Failed ) AND NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_FailDisabled ) AND sLocalData.eFailReason = CCFAIL_NONE IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroComplete ) IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_Dead ) IF eHeroAction = CCHERO_GUN sLocalData.eFailReason = CCFAIL_PEDHEROGUN sLocalData.iFailCausedByPed = iPed sLocalData.timeFailDelay = GET_TIME_OFFSET( GET_NETWORK_TIME(), 5000 ) ENDIF ELSE SWITCH eHeroAction CASE CCHERO_PHONE sLocalData.eFailReason = CCFAIL_PEDHEROPHONE sLocalData.iFailCausedByPed = iPed sLocalData.timeFailDelay = GET_TIME_OFFSET( GET_NETWORK_TIME(), 5000 ) BREAK CASE CCHERO_ALARM sLocalData.eFailReason = CCFAIL_PEDHEROALARM sLocalData.iFailCausedByPed = sLocalData.iCashierPed sLocalData.timeFailDelay = GET_NETWORK_TIME() // no delay BREAK ENDSWITCH CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] FAIL CHECKS - HeroComplete = ", GET_CROWD_CONTROL_HERO_ACTION( eHeroAction ) ) ENDIF ENDIF // A fail has been set locally & broadcast it IF sLocalData.eFailReason != CCFAIL_NONE // If we are the server set the server data to indicate a fail IF NETWORK_IS_HOST_OF_THIS_SCRIPT() SET_BIT_ENUM( sCrowdControlData.iBitSet, CCDATA_Failed ) ENDIF CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] FAIL DETECTED - Fail Reason = ", GET_CROWD_CONTROL_FAIL_REASON_STRING( sLocalData.eFailReason ) ) BROADCAST_FMMC_CC_FAIL( ENUM_TO_INT( sLocalData.eFailReason ), sLocalData.iFailCausedByPed, sLocalData.timeFailDelay ) ENDIF ENDIF // Check to see if the a hero peds prop(phone) has been broken // IF NOT IS_BIT_SET( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroBroken ) // IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( sCrowdControlPedData.niProp ) // IF HAS_ENTITY_BEEN_DAMAGED_BY_ANY_PED( NET_TO_OBJ( sCrowdControlPedData.niProp ) ) // SET_BIT( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroBroken ) // ENDIF // ENDIF // ENDIF // Update Ped //------------------------------------------------ IF DOES_ENTITY_EXIST( pedCrowd ) AND NOT bIsInjured FLOAT fCapSize fCapSize = GET_CROWD_CONTROL_PED_CAPSULE_SIZE( sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) IF fCapSize != -1 SET_PED_CAPSULE( pedCrowd, fCapSize ) ENDIF // Check here if the ped should get knocked out of the animated state and go to AI logic IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) SET_PED_RESET_FLAG( pedCrowd, PRF_PreventAllMeleeTakedowns, TRUE ) SET_PED_RESET_FLAG( pedCrowd, PRF_DisableMeleeHitReactions, TRUE ) // Any ped has shot or hurt the ped to kick them out of their anim. IF HAS_ENTITY_BEEN_DAMAGED_BY_ANY_PED( pedCrowd ) CLEAR_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) //sCrowdControlPedData.eState = CCPS_COWER SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COWER, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) IF NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( pedCrowd, WEAPONTYPE_SMOKEGRENADE ) AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON( pedCrowd, WEAPONTYPE_BZGAS ) CLEAR_PED_TASKS( pedCrowd ) ENDIF ENDIF ENDIF // Threat //-------------------------------------------------------------------------------------------- // Update last time shot at IF eThreatActual != CCTHREAT_SHOOTING AND eThreatActual != CCTHREAT_SHOOTING_CLOSE IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) sLocalPedData.timeLastShotAt = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) ENDIF ELSE IF eThreatActual = CCTHREAT_SHOOTING CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_ShotAtFearWasClose ) ELIF eThreatActual = CCTHREAT_SHOOTING_CLOSE SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_ShotAtFearWasClose ) ENDIF CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) ENDIF // Update projectile fear timer // Don't start the timer if the threat is a sticky bomb and this ped is set to ignore sticky bombs IF ( NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_IgnoreStickyBombs ) AND eThreatActual = CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB ) OR eThreatActual = CCTHREAT_PROJECTILE_EXPLOSIVE IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartFearProjectile ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] Projectile fear time stored" ) SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartFearProjectile ) sLocalPedData.timeStartProjectileFear = GET_NETWORK_TIME() ENDIF ENDIF // Update proxmity fear timer IF eThreatActual = CCTHREAT_PROXIMITY IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartProximityThreat ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] Proximity fear time stored" ) sLocalPedData.timeStartProximityThreat = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartProximityThreat ) ENDIF ELSE IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartProximityThreat ) CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartProximityThreat ) ENDIF ENDIF // Fear overrides IF IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) // Shooting fear adjustments // IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_ShotAtFearWasClose ) // // IF eThreatFelt < CCTHREAT_SHOOTING_CLOSE // // IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) // OR IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastShotAt, ciCC_PedShotAtCoolOffDurationClose ) ) // // eThreatFelt = CCTHREAT_SHOOTING_CLOSE // // ENDIF // // ENDIF // // ELSE IF eThreatFelt < CCTHREAT_SHOOTING IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) OR IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastShotAt, ciCC_PedShotAtCoolOffDuration ) ) eThreatFelt = CCTHREAT_SHOOTING ENDIF ENDIF // ENDIF // Projectile fear adjustments IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartFearProjectile ) // Keep the ped scared of the projectile for a period of time IF IS_TIME_LESS_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeStartProjectileFear, ciCC_ProjectileCoolOffDuration ) ) IF eThreatFelt <= CCTHREAT_PROJECTILE_EXPLOSIVE eThreatFelt = CCTHREAT_PROJECTILE_EXPLOSIVE ENDIF // Timer has run out and the threat was a sticky bomb, set this ped to ignore them from now on ELSE IF eThreatFelt = CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_IgnoreStickyBombs ) ENDIF // only reset the timer if theres no longer a projectile threat IF eThreatFelt != CCTHREAT_PROJECTILE_EXPLOSIVE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartFearProjectile ) ENDIF ENDIF ENDIF // Proximity fear adjustment IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartProximityThreat ) IF IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeStartProximityThreat, ciCC_ProximityCoolOffDuration ) ) IF eThreatFelt = CCTHREAT_PROXIMITY eThreatFelt = CCTHREAT_NONE ENDIF ENDIF ENDIF ENDIF // Update last time threatened IF eThreatFelt = CCTHREAT_NONE //AND sCrowdControlPedData.eState != CCPS_FLINCH AND sCrowdControlPedData.eState != CCPS_BEATDOWN IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastThreatenedSet ) sLocalPedData.timeLastThreatened = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastThreatenedSet ) ENDIF ELSE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastThreatenedSet ) ENDIF #IF IS_DEBUG_BUILD // Store out for debug rendering sLocalPedData.eDebugThreatFelt = eThreatFelt #ENDIF // Brain //------------------------------------------------ // Cancel look at while flinching or being beat IF sCrowdControlPedData.eState = CCPS_FLINCH OR sCrowdControlPedData.eState = CCPS_FLINCH_UNDERFIRE OR sCrowdControlPedData.eState = CCPS_BEATDOWN TASK_CLEAR_LOOK_AT( pedCrowd ) // Look at potential threat regardless of wheather they are threatening at the time ELIF sCrowdControlPedData.eState != CCPS_INTRO IF NOT IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_LOOK_AT_ENTITY ) TASK_LOOK_AT_ENTITY( pedCrowd, sLocalPedData.pedBiggestThreat, -1, SLF_WHILE_NOT_IN_FOV | SLF_NARROWEST_YAW_LIMIT ) ENDIF ENDIF BOOL bSafeToTransition // Start beating IF sCrowdControlPedData.eState != CCPS_BEATDOWN IF IS_BIT_SET_ENUM( sLocalPedData.iBitset, CCLOCALPEDDATA_BeatdownFired ) // Set the number of hits this ped can take this round sCrowdControlPedData.iBeatdownHitsRemaining = CLAMP_INT( ciCC_MaxBeatdownHits - sCrowdControlPedData.iBeatdownRounds, 1, ciCC_MaxBeatdownHits ) sCrowdControlPedData.iBeatdownRounds++ // Take 1 off for the first hit sCrowdControlPedData.iBeatdownHitsRemaining-- BROADCAST_FMMC_CC_PED_BEATDOWN_CLEAR( iCrowdStructID ) CLEAR_BIT_ENUM( sLocalPedData.iBitset, CCLOCALPEDDATA_BeatdownFired ) SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_BEATDOWN, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF // Already in beating ELSE IF IS_BIT_SET_ENUM( sLocalPedData.iBitset, CCLOCALPEDDATA_BeatdownFired ) #IF IS_DEBUG_BUILD IF NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_DebugUnlimitedBeatings ) #ENDIF // Beatdown loop -> Beatdown hit a/b -> Beatdown loop IF sCrowdControlPedData.iBeatdownHitsRemaining > 0 sCrowdControlPedData.iBeatdownHitsRemaining-- // Beatdown loop -> Beatdown die -> Beatdown die loop ELSE SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_KnockedOut ) sLocalPedData.timeDied = GET_NETWORK_TIME() sCrowdControlPedData.iBeatdownHitsRemaining = 0 ENDIF #IF IS_DEBUG_BUILD ENDIF #ENDIF BROADCAST_FMMC_CC_PED_BEATDOWN_CLEAR( iCrowdStructID ) CLEAR_BIT_ENUM( sLocalPedData.iBitset, CCLOCALPEDDATA_BeatdownFired ) // Playing the loop, wait until the threat has finished then start the timer ELIF eThreatFelt = CCTHREAT_NONE AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastBeatSet ) sLocalPedData.timeLastBeat = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastBeatSet ) ENDIF IF IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastBeatSet ) AND IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastBeat, 3000 ) ) //sCrowdControlPedData.eState = CCPS_FLINCH SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_FLINCH, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF ELSE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastBeatSet ) ENDIF ENDIF SWITCH sCrowdControlPedData.eState CASE CCPS_INTRO // Crowd has been activated IF IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) // this ped has been threatened OR eThreatActual != CCTHREAT_NONE // this ped has been attacked OR HAS_ENTITY_BEEN_DAMAGED_BY_ANY_PED( pedCrowd ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_INTRO going to CCPS_COWER - CCDATA_Active: ", BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) ), " WasThreatened?: ", BOOL_TO_STRING( eThreatActual != CCTHREAT_NONE ) ) CPRINTLN( DEBUG_NET_MINIGAME, " - Threat felt = ", GET_CROWD_CONTROL_THREAT_TYPE_STRING( eThreatActual ), "\n" ) // Set a random start delay for broadcasting dialogue, this is to help avoid synchronised screaming and dialogue // by stopping all the dialogue kicking off in the same frame. sLocalPedData.timeDialogueLastBroadcast = GET_TIME_OFFSET( GET_NETWORK_TIME(), ( GET_RANDOM_INT_IN_RANGE( 0, 11 ) * 50 ) ) // 0 -> 0.5 seconds (50ms intervals) //sCrowdControlPedData.eState = CCPS_COWER SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COWER, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF BREAK CASE CCPS_COWER IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitset, CCPEDDATA_RunningBespokeAnims ) //IF HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, DEFAULT, TRUE, sCrowdControlData.iSyncScene, HASH( "Event" ) ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) bSafeToTransition = TRUE ENDIF ELSE bSafeToTransition = TRUE ENDIF IF bSafeToTransition // Use a timer to make sure the player has aimed at a ped and not just moved their aim past them IF eThreatActual = CCTHREAT_AIMED_AT IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartThreaten ) // 250ms + random 0-250ms increments of 50ms sLocalPedData.timeStartThreaten = GET_TIME_OFFSET( GET_NETWORK_TIME(), 250 + ( GET_RANDOM_INT_IN_RANGE(0, 6 ) * 50 ) ) SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartThreaten ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] Escape/Hero attempt threat react timer started" ) ENDIF ELSE CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartThreaten ) ENDIF // Every threat is instant apart from aiming at, this is so the player can't just spin or weave there aim over peds quickly to keep their fear up IF eThreatFelt != CCTHREAT_NONE IF ( eThreatFelt != CCTHREAT_AIMED_AT OR ( eThreatFelt = CCTHREAT_AIMED_AT AND IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartThreaten ) AND IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalPedData.timeStartThreaten ) ) ) SWITCH eThreatFelt CASE CCTHREAT_SHOOTING_CLOSE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SHOT_DIRECTLY_AT, CCDIAPLAYBACK_FORCE_PAIN | CCDIAPLAYBACK_FORCE_CRITICAL ) BREAK CASE CCTHREAT_SHOOTING QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SHOT_NEAR, CCDIAPLAYBACK_FORCE_PAIN | CCDIAPLAYBACK_FORCE_CRITICAL ) BREAK CASE CCTHREAT_AIMED_AT CASE CCTHREAT_PROJECTILE_EXPLOSIVE CASE CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_RECEIVES_SCARE, CCDIAPLAYBACK_FORCE_PAIN | CCDIAPLAYBACK_FORCE_CRITICAL ) BREAK DEFAULT QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_APPROACH, CCDIAPLAYBACK_FORCE_PAIN | CCDIAPLAYBACK_FORCE_CRITICAL ) BREAK ENDSWITCH IF eThreatFelt = CCTHREAT_SHOOTING_CLOSE SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_FLINCH_UNDERFIRE, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetShootingCloseFlinching ) ELSE SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_FLINCH, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetStartThreaten ) ENDIF // Fear level dropped, attempt to escape ELIF sLocalData.fIntimidationBar < cfCC_PedBreakoutCowerThreshold AND eThreatActual = CCTHREAT_NONE AND IS_BIT_SET_ENUM( sCrowdControlPedData.iBitset, CCPEDDATA_RunningBespokeAnims ) // can only transition to this if ped is playing anims // Is a valid hero & the minigame's not failed IF eHeroAction != CCHERO_NONE AND IS_BIT_SET( sCrowdControlData.iCurrentActiveHeros, iCrowdStructID ) AND IS_CROWD_CONTROL_PED_A_VALID_HERO( sCrowdControlPedData, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, bRestrictCrowdPed ) AND NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Failed ) SWITCH eHeroAction CASE CCHERO_ALARM QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_ALARM_START ) BREAK CASE CCHERO_PHONE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_PHONE_START ) BREAK CASE CCHERO_GUN QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_GUN_START ) BREAK ENDSWITCH CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_COWER going to CCPS_HERO_ATTEMPT") SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroAttempted ) //sCrowdControlPedData.eState = CCPS_HERO_ATTEMPT SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_HERO_ATTEMPT, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF ENDIF ENDIF BREAK CASE CCPS_FLINCH // Is it safe to transition out of this state? IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitset, CCPEDDATA_RunningBespokeAnims ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) bSafeToTransition = TRUE ENDIF ELSE bSafeToTransition = TRUE ENDIF IF eThreatFelt = CCTHREAT_SHOOTING_CLOSE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SHOT_DIRECTLY_AT, CCDIAPLAYBACK_FORCE_PAIN | CCDIAPLAYBACK_FORCE_CRITICAL ) SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_FLINCH_UNDERFIRE, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetShootingCloseFlinching ) // No threat, go back to regular cower ELIF bSafeToTransition IF eThreatFelt = CCTHREAT_NONE // 2121009 - removed as part of this bug in order to get a more immediate response. // UNDONE now we have new anims to go in AND ( NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastThreatenedSet ) OR IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastThreatened, 5000 ) ) ) AND ( NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeLastShotAtSet ) OR IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastShotAt, 8000 ) ) ) SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COWER, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF ENDIF BREAK CASE CCPS_FLINCH_UNDERFIRE // Is it safe to transition out of this state? IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitset, CCPEDDATA_RunningBespokeAnims ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetShootingCloseFlinching ) sLocalPedData.timeShootingCloseFlinchingStarted = GET_NETWORK_TIME() SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetShootingCloseFlinching ) ENDIF // Minimum 1 second of frantic flinching IF IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeShootingCloseFlinchingStarted, 1000 ) ) bSafeToTransition = TRUE ENDIF ENDIF ELSE bSafeToTransition = TRUE ENDIF IF bSafeToTransition IF eThreatFelt != CCTHREAT_SHOOTING_CLOSE SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_FLINCH, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) CLEAR_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_TimeSetShootingCloseFlinching ) ENDIF ENDIF BREAK CASE CCPS_BEATDOWN // see top of switch for this logic BREAK CASE CCPS_HERO_ATTEMPT // Any threat to the ped, instant response IF eThreatFelt != CCTHREAT_NONE // Hero prop damaged OR IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroBroken ) CLEAR_BIT_ENUM( sCrowdControlPedData.iBitSet, CCLOCALPEDDATA_TimeSetHoldBeforeEscape ) SWITCH eHeroAction CASE CCHERO_ALARM QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_ALARM_CAUGHT ) BREAK CASE CCHERO_PHONE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_PHONE_CAUGHT ) BREAK CASE CCHERO_GUN QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_GUN_CAUGHT ) BREAK ENDSWITCH // Ped has become too scared to finish the escape, return to cower CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_HERO_ATTEMPT going to CCPS_COWER") //sCrowdControlPedData.eState = CCPS_COWER SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COWER, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ELSE BOOL bReadyToTransition // Animated version can only transition once it reaches the Escape/Hero loop IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) bReadyToTransition = TRUE ENDIF // Non animated version can go straight away (may add additional conditions, i.e. a timer) ELSE bReadyToTransition = TRUE ENDIF IF bReadyToTransition // Go to combat IF eHeroAction = CCHERO_GUN QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_GUN_COMPLETE ) CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_HERO_ATTEMPT going to CCPS_COMBAT") SET_PED_CAN_BE_TARGETTED( pedCrowd, TRUE ) // 2048337 // Rob - 2167482 - make sure all teams can target the hero combat ped INT iRepeat FOR iRepeat = 0 TO (FMMC_MAX_TEAMS-1) SET_PED_CAN_BE_TARGETTED_BY_TEAM(pedCrowd, iRepeat, TRUE) ENDFOR //sCrowdControlPedData.eState = CCPS_COMBAT SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COMBAT, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) // go to special hero state ELIF eHeroAction = CCHERO_ALARM OR eHeroAction = CCHERO_PHONE SWITCH eHeroAction CASE CCHERO_ALARM QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_ALARM_COMPLETE ) BREAK CASE CCHERO_PHONE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_HERO_PHONE_COMPLETE ) BREAK ENDSWITCH CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_HERO_ATTEMPT going to CCPS_HERO") SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_HERO, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF ENDIF ENDIF BREAK // For successful heros with a non violent action (phone call or button press) CASE CCPS_HERO IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) BOOL bReadyToTransition IF eHeroAction = CCHERO_ALARM // Alarm guy signals a hero complete fail immediately // and then waits to move on until the fail has been processed SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroComplete ) IF IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_FailProcessed ) QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_ALARM_GOES_OFF ) bReadyToTransition = TRUE ENDIF ELSE IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroComplete ) bReadyToTransition = TRUE ENDIF ENDIF IF bReadyToTransition CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - [", iCrowdStructID,"] CCPS_HERO going to CCPS_COWER") SET_CROWD_CONTROL_PED_STATE( sCrowdControlPedData, CCPS_COWER, iCrowdStructID, sLocalPedData.eCreatorAssignedPedID ) ENDIF ENDIF BREAK CASE CCPS_COMBAT BREAK ENDSWITCH // Body - Animated state logic ONLY //------------------------------------------------ IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) AND IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RecievedSyncedScene ) SWITCH sCrowdControlPedData.eState CASE CCPS_COWER // Hero start/loop -> Hero fail -> Cower loop IF sCrowdControlPedData.eStatePrev = CCPS_HERO_ATTEMPT AND ( ( IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, 0.5 ) ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_HERO_FAIL, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_HERO_FAIL, iCrowdStructID, sLocalPedData ) ENDIF // Flinch loop -> Flinch outro -> Cower loop ELIF sCrowdControlPedData.eStatePrev = CCPS_FLINCH AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_FLINCH_TO_COWER, iCrowdStructID, sLocalPedData ) ENDIF // X -> Cower loop ELIF NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // Make sure we don't interupt any flinching or transitions back into the cower // Has finished intro IF ( sCrowdControlPedData.eStatePrev = CCPS_INTRO AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_INTRO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, DEFAULT, TRUE, sLocalData.iSyncSceneIntroLoop ) AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, DEFAULT, TRUE, sCrowdControlData.iSyncScene, HASH( "blendout" ) ) ) // Has finished hero attempt fail OR ( sCrowdControlPedData.eStatePrev = CCPS_HERO_ATTEMPT AND ( NOT DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_FAIL, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_HERO_FAIL, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, DEFAULT ) ) ) // Has finished flinch OR ( sCrowdControlPedData.eStatePrev = CCPS_FLINCH AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_COWER_LOOP, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, AF_LOOPING | eCrowdControlAnimFlags ) ENDIF ENDIF ENDIF BREAK CASE CCPS_FLINCH // Cower loop -> Flinch intro -> Flinch loop IF ( sCrowdControlPedData.eStatePrev = CCPS_COWER AND ( IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_COWER_TO_FLINCH_INTRO, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_COWER_TO_FLINCH, iCrowdStructID, sLocalPedData ) ENDIF // Flinch underfire -> Flinch loop ELIF ( sCrowdControlPedData.eStatePrev = CCPS_FLINCH_UNDERFIRE AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_FLINCH_LOOP, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_FLINCH_UNDERFIRE_TO_FLINCH, iCrowdStructID, sLocalPedData ) // PLAY_CROWD_CONTROL_ANIM( pedCrowd, // CCPANIM_FLINCH_LOOP, // sLocalPedData.eCreatorAssignedPedID, // sLocalData.eHeistType, // REALLY_SLOW_BLEND_IN, -0.1, -1, // AF_LOOPING | eCrowdControlAnimFlags ) ENDIF // Beatdown loop -> Beatdown outro -> Flinch loop ELIF ( sCrowdControlPedData.eStatePrev = CCPS_BEATDOWN AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_BEATDOWN_OUTRO, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_BEATDOWN_TO_FLINCH, iCrowdStructID, sLocalPedData ) ENDIF // // bugs 2114141 & 2123699 // // trying to avoid bug where peds are standing doing nothing, this will task them with the flinch anims // // always seem to be in the flinch state but no idea how they go here, looks like a migration problem // ELIF NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // // IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_COWER_TO_FLINCH_INTRO, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) // // CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_AI() - EMERGENCY SEQUENCE TASK, PED HAS LOST ANIMATION TASK" ) // PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_COWER_TO_FLINCH, iCrowdStructID, sLocalPedData ) // // ENDIF // ENDIF BREAK CASE CCPS_FLINCH_UNDERFIRE // Cower loop /Flinch outro -> Flinch intro -> Flinch loop shot at IF ( sCrowdControlPedData.eStatePrev = CCPS_COWER AND ( IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_TO_IDLE_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_COWER_TO_FLINCH_INTRO, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_COWER_TO_FLINCH_UNDERFIRE, iCrowdStructID, sLocalPedData ) ENDIF // Flinch loop -> Flinch underfire ELIF ( sCrowdControlPedData.eStatePrev = CCPS_FLINCH AND ( IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_UNDERFIRE_TO_FLINCH_OUTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_TO_FLINCH_UNDERFIRE_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_FLINCH_UNDERFIRE_LOOP, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_FLINCH_TO_FLINCH_UNDERFIRE, iCrowdStructID, sLocalPedData ) // PLAY_CROWD_CONTROL_ANIM( pedCrowd, // CCPANIM_FLINCH_UNDERFIRE_LOOP, // sLocalPedData.eCreatorAssignedPedID, // sLocalData.eHeistType, // SLOW_BLEND_IN, -0.1, -1, // AF_LOOPING | eCrowdControlAnimFlags ) ENDIF ENDIF BREAK CASE CCPS_BEATDOWN SET_PED_RESET_FLAG( pedCrowd, PRF_UseKinematicPhysics, TRUE ) IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_BeatdownSyncSceneStarted ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_A, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_B, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_DIE, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_BeatdownSyncSceneStarted ) ENDIF ELSE IF NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_A, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_B, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_DIE, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_DIE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, FALSE ) AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, FALSE ) IF IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_KnockedOut ) PLAY_CROWD_CONTROL_ANIM( pedCrowd, CCPANIM_BEATDOWN_DIE_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_ENDS_IN_DEAD_POSE | eCrowdControlAnimFlags ) ELSE PLAY_CROWD_CONTROL_ANIM( pedCrowd, CCPANIM_BEATDOWN_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING | eCrowdControlAnimFlags ) ENDIF CLEAR_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_BeatdownSyncSceneStarted ) ENDIF ENDIF BREAK CASE CCPS_HERO_ATTEMPT // Cower loop -> Hero start -> Hero loop IF ( sCrowdControlPedData.eStatePrev = CCPS_COWER AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // playing cower? AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) // not playing escape start? IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_HERO_START, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_HERO_START, iCrowdStructID, sLocalPedData ) ENDIF ENDIF BREAK CASE CCPS_HERO // Hero loop -> Hero pass -> Cower IF sCrowdControlPedData.eStatePrev = CCPS_HERO_ATTEMPT AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // playing hero start? AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // not playing hero pass? IF eHeroAction = CCHERO_ALARM IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_HERO_FAIL, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_HERO_FAIL, iCrowdStructID, sLocalPedData ) ENDIF ELSE IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_HERO_PASS, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) PLAY_CROWD_CONTROL_SEQUENCE( pedCrowd, CCSEQ_HERO_PASS, iCrowdStructID, sLocalPedData ) ENDIF ENDIF ENDIF BREAK CASE CCPS_COMBAT // Hero loop -> Hero Pass IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_LOOP, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // playing escape loop? AND NOT IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // not playing escape pass? IF HAS_CROWD_CONTROL_PED_ANIM_LOADED( CCPANIM_HERO_PASS, sLocalData.eHeistType, sLocalPedData.eCreatorAssignedPedID ) WEAPON_TYPE eWeap GET_CURRENT_PED_WEAPON( pedCrowd, eWeap ) IF eWeap != WEAPONTYPE_PISTOL SET_CURRENT_PED_WEAPON( pedCrowd, WEAPONTYPE_PISTOL, TRUE ) ENDIF PLAY_CROWD_CONTROL_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, -1, AF_HOLD_LAST_FRAME | eCrowdControlAnimFlags ) SET_PED_USING_ACTION_MODE( pedCrowd, TRUE, -1, "DEFAULT_ACTION" ) ENDIF // Hero pass -> AI combat ELIF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // playing escape pass? AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) // finished escape pass? // TRANSFER TO AI COMBAT //SET_PED_RESET_FLAG( pedCrowd, PRF_InstantBlendToAim, TRUE ) CLEAR_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) SET_BIT_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_HeroComplete ) ENDIF BREAK ENDSWITCH ENDIF // Body - AI driven logic ONLY //------------------------------------------------ IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) // Run AI state machine SWITCH sCrowdControlPedData.eState // Idle, unalert to player's prescence CASE CCPS_INTRO BREAK CASE CCPS_COWER CASE CCPS_FLINCH IF NOT IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_HANDS_UP ) AND NOT IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_COWER ) SET_PED_COMBAT_ATTRIBUTES( pedCrowd, CA_ALWAYS_FLEE, FALSE ) SET_PED_FLEE_ATTRIBUTES( pedCrowd, FA_DISABLE_COWER, TRUE ) SET_PED_FLEE_ATTRIBUTES( pedCrowd, FA_DISABLE_FLEE_FROM_INDIRECT_THREATS, TRUE ) SET_PED_FLEE_ATTRIBUTES( pedCrowd, FA_COWER_INSTEAD_OF_FLEE, TRUE ) TASK_HANDS_UP( pedCrowd,-1, sLocalPedData.pedBiggestThreat, -1, HANDS_UP_NOTHING ) sLocalPedData.timeLastThreatened = GET_NETWORK_TIME() ELIF IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_HANDS_UP ) AND NOT IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_COWER ) AND eThreatFelt = CCTHREAT_NONE AND IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalPedData.timeLastThreatened, 5000 ) ) TASK_COWER( pedCrowd, -1 ) ENDIF BREAK CASE CCPS_COMBAT WEAPON_TYPE eWeap GET_CURRENT_PED_WEAPON( pedCrowd, eWeap ) IF eWeap != WEAPONTYPE_PISTOL SET_CURRENT_PED_WEAPON( pedCrowd, WEAPONTYPE_PISTOL, FALSE ) ENDIF IF NOT IS_SCRIPT_TASK_RUNNING_OR_STARTING( pedCrowd, SCRIPT_TASK_COMBAT ) SET_PED_COMBAT_ATTRIBUTES(pedCrowd, CA_ALWAYS_FLEE, FALSE) TASK_COMBAT_PED( pedCrowd, sLocalPedData.pedBiggestThreat ) ENDIF BREAK ENDSWITCH ENDIF // Other dialogue which plays based on threats and/or state //----------------------------------------------------------------------- IF IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) AND NOT IS_PED_IN_COMBAT( pedCrowd ) AND sCrowdControlPedData.eState != CCPS_COMBAT AND sCrowdControlPedData.eState != CCPS_HERO_ATTEMPT AND sCrowdControlPedData.eState != CCPS_HERO BOOL bPassedInitialScreaming = IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalData.timeCrowdKickedOff, 4000 ) ) // THREAT BASED IF eThreatFelt != CCTHREAT_NONE AND bPassedInitialScreaming SWITCH eThreatFelt CASE CCTHREAT_PROXIMITY QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_COWER_HIGH_FEAR ) BREAK CASE CCTHREAT_BEATING_NEIGHBOUR QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_STICKS_UP_FOR_OTHER ) BREAK CASE CCTHREAT_KILLED_OTHER QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SEES_OTHER_KILLED ) BREAK CASE CCTHREAT_AIMED_AT CASE CCTHREAT_PROJECTILE_EXPLOSIVE CASE CCTHREAT_PROJECTILE_EXPLOSIVE_STICKY_BOMB QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_RECEIVES_SCARE ) BREAK CASE CCTHREAT_SHOOTING QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SHOT_NEAR ) BREAK CASE CCTHREAT_SHOOTING_CLOSE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_SHOT_DIRECTLY_AT ) BREAK ENDSWITCH ENDIF // STATE BASED SWITCH sCrowdControlPedData.eState // While CASE CCPS_COWER IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) // Initially only allow the peds crowd to scream IF NOT bPassedInitialScreaming QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_INITIAL_PANIC, CCDIAPLAYBACK_FORCE_PAIN ) ELSE QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, CCDIA_INITIAL_PANIC ) ENDIF ENDIF BREAK ENDSWITCH // AMBIENT BOOL bCanPlayLowFearAmbientDialogue = IS_TIME_MORE_THAN( GET_NETWORK_TIME(), GET_TIME_OFFSET( sLocalData.timeCrowdKickedOff, 20000 ) ) CROWD_CONTROL_DIALOGUE eAmbientRandomDialogue // Alarm has just gone off IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RaiseAlarms ) AND NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_RaiseAlarmDiagloue ) AND NOT IS_CUTSCENE_PLAYING() // dnt try and fire off this line behind a cutscene as it might get missed eAmbientRandomDialogue = CCDIA_ALARM_GOES_OFF_INITIAL // Otherwise select a line based off fear level ELSE // Fear low IF sLocalData.fIntimidationBar < 40.0 AND sCrowdControlPedData.eState != CCPS_FLINCH AND sCrowdControlPedData.eState != CCPS_BEATDOWN AND bCanPlayLowFearAmbientDialogue // Once the alarm has gone off theres a random chance of hearing alarm/cops are coming related dialogue IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RaiseAlarms ) AND GET_RANDOM_BOOL() eAmbientRandomDialogue = CCDIA_ALARM_GOES_OFF ELSE eAmbientRandomDialogue = CCDIA_COWER_LOW_FEAR ENDIF // Fear high ELSE eAmbientRandomDialogue = CCDIA_COWER_HIGH_FEAR ENDIF ENDIF // Play ambient context QUEUE_CROWD_CONTROL_DIALOGUE_CLIENT_TO_HOST( sLocalData, sLocalPedData, eAmbientRandomDialogue ) ENDIF ENDIF ENDIF ENDPROC PROC PROCESS_CROWD_CONTROL_PED_LOCAL( PED_INDEX pedCrowd, INT iCrowdID, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, CROWD_CONTROL_SERVER_DATA &sServerData, CROWD_CONTROL_LOCAL_DATA &sLocalData ) #IF NOT IS_DEBUG_BUILD UNUSED_PARAMETER( iCrowdID ) #ENDIF CROWD_CONTROL_PED_HERO_ACTION eHeroAction = CCHERO_NONE IF DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_HERO_START, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) eHeroAction = GET_CROWD_CONTROL_PED_HERO_ACTION_FOR_ANIMATED_PED( sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) ENDIF IF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) SWITCH eHeroAction CASE CCHERO_PHONE SWITCH sPedData.eState CASE CCPS_COWER // Detach the phone IF DOES_ENTITY_EXIST( sLocalPedData.objProp ) IF IS_ENTITY_ATTACHED( sLocalPedData.objProp ) IF sServerData.iSyncScene != -1 AND IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, TRUE ) AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_INTRO, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, DEFAULT, TRUE, sServerData.iSyncScene, HASH( "drop" ) ) CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_LOCAL() - [", iCrowdID,"] Detatched phone for CCPANIM_INTRO") DETACH_ENTITY( sLocalPedData.objProp ) FREEZE_ENTITY_POSITION( sLocalPedData.objProp, TRUE ) ENDIF ENDIF ENDIF BREAK CASE CCPS_HERO IF DOES_ENTITY_EXIST( sLocalPedData.objProp ) // Attach the phone, as they start playing the hero anim IF NOT IS_ENTITY_ATTACHED( sLocalPedData.objProp ) IF NOT IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_HeroPropDetatchedForLastTime ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_LOCAL() - [", iCrowdID,"] Attached phone for CCPANIM_HERO_PASS") FREEZE_ENTITY_POSITION( sLocalPedData.objProp, FALSE ) ATTACH_ENTITY_TO_ENTITY( sLocalPedData.objProp, pedCrowd, GET_PED_BONE_INDEX( pedCrowd, BONETAG_PH_R_HAND ), <<0,0,0>>, <<0,0,0>>, TRUE, FALSE ) ENDIF ENDIF ELSE // Detach phone during hero pass IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType ) AND HAS_CROWD_CONTROL_PED_FINISHED_ANIM( pedCrowd, CCPANIM_HERO_PASS, sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, 0.9 ) // During the HERO PASS anim CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_PED_LOCAL() - [", iCrowdID,"] Detatched phone for CCPANIM_HERO_PASS") DETACH_ENTITY( sLocalPedData.objProp ) FREEZE_ENTITY_POSITION( sLocalPedData.objProp, TRUE ) SET_BIT_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_HeroPropDetatchedForLastTime ) ENDIF ENDIF ENDIF BREAK ENDSWITCH BREAK ENDSWITCH ENDIF ENDPROC FUNC BOOL IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_1H( WEAPON_TYPE eWeapType, BOOL bIncludeHit = FALSE ) IF IS_WEAPON_A_PISTOL( eWeapType ) OR eWeapType = WEAPONTYPE_STUNGUN OR eWeapType = WEAPONTYPE_MICROSMG OR eWeapType = WEAPONTYPE_DLC_FLAREGUN // 2183699 OR eWeapType = WEAPONTYPE_KNIFE OR eWeapType = WEAPONTYPE_DLC_BOTTLE OR eWeapType = WEAPONTYPE_DLC_DAGGER RETURN TRUE // kick only - 1H weapons that we want to only allow kicking // 2183699 ELIF eWeapType = WEAPONTYPE_CROWBAR OR eWeapType = WEAPONTYPE_UNARMED OR eWeapType = WEAPONTYPE_HAMMER OR eWeapType = WEAPONTYPE_NIGHTSTICK OR eWeapType = WEAPONTYPE_DLC_KNUCKLE OR eWeapType = WEAPONTYPE_DLC_HATCHET IF NOT bIncludeHit RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_2H( WEAPON_TYPE eWeapType, BOOL bIncludeHit = FALSE ) IF IS_WEAPON_SUITABLE_FOR_TWO_HANDED_ANIMS( eWeapType ) OR eWeapType = WEAPONTYPE_SMG OR eWeapType = WEAPONTYPE_MG OR eWeapType = WEAPONTYPE_COMBATMG OR eWeapType = WEAPONTYPE_GRENADELAUNCHER OR eWeapType = WEAPONTYPE_DLC_ASSAULTMG OR eWeapType = WEAPONTYPE_DLC_ASSAULTSMG RETURN TRUE // kick only ELIF eWeapType = WEAPONTYPE_RPG OR eWeapType = WEAPONTYPE_DLC_FIREWORK IF NOT bIncludeHit RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PLAYER_MELEE_ANIM_A_KICK( CROWD_CONTROL_PLAYER_ANIM_TYPE eAnim ) IF eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A OR eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B OR eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A OR eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PLAYER_PERFORMING_A_BEATDOWN( PED_INDEX pedPlayer ) IF IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_PISTOL_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_PISTOL_B, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_RIFLE_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_RIFLE_B, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_PISTOL_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_PISTOL_KICK_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_B, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_A, TRUE ) OR IS_CROWD_CONTROL_PLAYER_PLAYING_ANIM( pedPlayer, CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_B, TRUE ) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_CROWD_CONTROL_PLAYER_PERFORM_A_BEATDOWN( PLAYER_INDEX playerID, PED_INDEX pedPlayer ) IF NOT IS_PED_INJURED( pedPlayer ) AND NOT IS_PED_RELOADING( pedPlayer ) AND NOT IS_PLAYER_FREE_AIMING( playerID ) AND NOT IS_PLAYER_TARGETTING_ANYTHING( playerID ) WEAPON_TYPE eWeapType GET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), eWeapType ) IF IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_1H( eWeapType ) CDEBUG2LN( DEBUG_NET_MINIGAME, "CAN_CROWD_CONTROL_PLAYER_PERFORM_A_BEATDOWN() - Player armed with a 1 handed weapon" ) RETURN TRUE ELIF IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_2H( eWeapType ) CDEBUG2LN( DEBUG_NET_MINIGAME, "CAN_CROWD_CONTROL_PLAYER_PERFORM_A_BEATDOWN() - Player armed with a 2 handed weapon" ) RETURN TRUE ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "CAN_CROWD_CONTROL_PLAYER_PERFORM_A_BEATDOWN() - Player is aiming/reloading" ) ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_CROWD_CONTROL_PED_BE_BEATDOWN( PED_INDEX pedCrowd, CROWD_CONTROL_PED_DECORATOR_DATA &sPedDecorData, CROWD_CONTROL_PED_ENUM eAssignedPedID, CROWD_CONTROL_HEIST_TYPE eHeistType ) IF NOT IS_BIT_SET_ENUM( sPedDecorData.iBitSet, CCPEDDATA_Dead ) AND NOT IS_BIT_SET_ENUM( sPedDecorData.iBitSet, CCPEDDATA_KnockedOut ) AND DOES_CROWD_CONTROL_PED_HAVE_ANIM( CCPANIM_BEATDOWN_INTRO, eAssignedPedID, eHeistType ) IF IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_LOOP, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_COWER_TO_FLINCH_INTRO, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_LOOP, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_FLINCH_TO_IDLE_OUTRO, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_LOOP, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_OUTRO, eAssignedPedID, eHeistType ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_INTRO, eAssignedPedID, eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_A, eAssignedPedID, eHeistType, TRUE ) OR IS_CROWD_CONTROL_PED_PLAYING_ANIM( pedCrowd, CCPANIM_BEATDOWN_HIT_B, eAssignedPedID, eHeistType, TRUE ) RETURN TRUE ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "CAN_CROWD_CONTROL_PED_BE_BEATDOWN() - Not playing a suitable anim to hit in from" ) ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "CAN_CROWD_CONTROL_PED_BE_BEATDOWN() - Cannot beat dead/knockedout ped OR does not have animation" ) ENDIF RETURN FALSE ENDFUNC FUNC BOOL GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET_MIN_MAX( CROWD_CONTROL_PED_ENUM ePedCrowd, CROWD_CONTROL_HEIST_TYPE eHeistType, VECTOR &vMin, VECTOR &vMax ) SWITCH eHeistType CASE CCHEIST_CUSTOM_FLEECA SWITCH ePedCrowd CASE CCPED_CUSTOMER_A vMin = <<0,0,0>> vMax = <<0,0.5,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_B vMin = <<0,0,0>> vMax = <<0,0.4,0>> RETURN TRUE BREAK ENDSWITCH BREAK CASE CCHEIST_CUSTOM_ORNATE SWITCH ePedCrowd CASE CCPED_CASHIER_A vMin = <<0,-0.25,0>> vMax = <<0,0.25,0>> RETURN TRUE BREAK CASE CCPED_CASHIER_B vMin = <<0,-0.25,0>> vMax = <<0,0.25,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_A vMin = <<0,0,0>> vMax = <<0,0.5,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_B vMin = <<0,0,0>> vMax = <<0,0.4,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_D vMin = <<0,-0.1,0>> vMax = <<0,0.4,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_G vMin = <<0,0,0>> vMax = <<0,0.25,0>> RETURN TRUE BREAK CASE CCPED_CUSTOMER_H vMin = <<0,-0.25,0>> vMax = <<0,0.25,0>> RETURN TRUE BREAK ENDSWITCH BREAK ENDSWITCH // no custom mover offsets for this ped, return false RETURN FALSE ENDFUNC FUNC VECTOR GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET( PED_INDEX pedCrowd, CROWD_CONTROL_PED_ENUM ePedCrowd, VECTOR vPlayerCoord, CROWD_CONTROL_HEIST_TYPE eHeistType ) VECTOR vMin VECTOR vMax IF GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET_MIN_MAX( ePedCrowd, eHeistType, vMin, vMax ) vMin = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS( pedCrowd, vMin ) vMax = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS( pedCrowd, vMax ) RETURN GET_CLOSEST_POINT_ON_LINE( vPlayerCoord, vMin, vMax, TRUE ) ENDIF RETURN GET_ENTITY_COORDS( pedCrowd, FALSE ) ENDFUNC /// PURPOSE: /// Obtains the angular range based on the probe's distance from the target ped's coords. /// PARAMS: /// vProbeCoord - The coord we're using to query (usually the players coord) /// vPedCoord - The coord we're queryng against (usually the victims coord) /// RETURNS: /// FLOAT angular range, this is the range that is acceptable for the probes facing direction against the ped queried FUNC FLOAT GET_CROWD_CONTROL_PED_BEATDOWN_FACING_ANGLE_RANGE( VECTOR vProbeCoord, VECTOR vPedCoord ) FLOAT fDist = GET_DISTANCE_BETWEEN_COORDS( vProbeCoord, vPedCoord, FALSE ) FLOAT fDistanceAlpha = CLAMP( ( fDist - cfCC_BeatdownFacingAngleChangeDistMin ) / ( cfCC_BeatdownFacingAngleChangeDistMax - cfCC_BeatdownFacingAngleChangeDistMin ), 0.0, 1.0 ) RETURN LERP_FLOAT( cfCC_BeatdownFacingAngleRangeMax, cfCC_BeatdownFacingAngleRangeMin, fDistanceAlpha ) ENDFUNC FUNC BOOL IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE( PED_INDEX pedCrowd, PED_INDEX pedPlayer, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData ) BOOL bResult VECTOR vPlayerCoord = GET_ENTITY_COORDS( pedPlayer ) VECTOR vPedMoverOffset = GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET( pedCrowd, sLocalPedData.eCreatorAssignedPedID, vPlayerCoord, sLocalData.eHeistType ) FLOAT fCurrentFacingAngleRange = cfCC_BeatdownFacingAngleRangeMin IF GET_INTERIOR_FROM_ENTITY( pedPlayer ) = GET_INTERIOR_FROM_ENTITY( pedCrowd ) IF ABSF( vPlayerCoord.z - vPedMoverOffset.z ) <= 1.0 FLOAT fDist = GET_DISTANCE_BETWEEN_COORDS( vPlayerCoord, vPedMoverOffset, FALSE ) IF fDist <= cfCC_BeatdownDistMax // is player facing ped within an angular range fCurrentFacingAngleRange = GET_CROWD_CONTROL_PED_BEATDOWN_FACING_ANGLE_RANGE( vPlayerCoord, vPedMoverOffset ) IF IS_ENTITY_FACING_COORD_WITHIN_RANGE( PLAYER_PED_ID(), vPedMoverOffset, fCurrentFacingAngleRange ) bResult = TRUE ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE() - not within the facing limits for the ped" ) ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE() - not close enough to the ped" ) ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE() - z difference is too big" ) ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE() - not in the same interior, cannot hit ped" ) ENDIF RETURN bResult ENDFUNC FUNC BOOL PLAY_CROWD_CONTROL_BEATDOWN( NETWORK_INDEX niPed, INT iCrowd, WEAPON_TYPE eWeapType, CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sPedLocalData ) BOOL bCanUseWeaponButt BOOL bCanUseKick // First time, force gun butt IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownFirst ) bCanUseWeaponButt = TRUE bCanUseKick = FALSE // no follow up, start on a random ELIF sLocalData.eLastBeatdown = CCPLAYERANIM_INVALID bCanUseWeaponButt = TRUE bCanUseKick = TRUE // follow up kick ELIF IS_CROWD_CONTROL_PLAYER_MELEE_ANIM_A_KICK( sLocalData.eLastBeatdown ) bCanUseWeaponButt = FALSE bCanUseKick = TRUE // follow up gun butt ELSE bCanUseWeaponButt = TRUE bCanUseKick = FALSE ENDIF PED_INDEX pedCrowd = NET_TO_PED( niPed ) BOOL bUseLongAnim = GET_DISTANCE_BETWEEN_ENTITIES( PLAYER_PED_ID(), pedCrowd ) >= cfCC_BeatdownLongAnimDistThreshold // Select anim CROWD_CONTROL_PLAYER_ANIM_TYPE eAnim INT iStart INT iEnd IF IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_1H( eWeapType ) IF NOT IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_1H( eWeapType, TRUE ) bCanUseWeaponButt = FALSE bCanUseKick = TRUE ELSE // Disabled long kicks - player slides on planted leg, looks bad IF bUseLongAnim bCanUseKick = FALSE ENDIF ENDIF IF bUseLongAnim IF bCanUseWeaponButt iStart = 0 ELSE iStart = 1 ENDIF IF bCanUseKick iEnd = 2 ELSE iEnd = 1 ENDIF IF iStart >= iEnd SCRIPT_ASSERT( "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 1H PISTOL LONG melee broken, iStart >= iEnd, see logs for details, bug Michael Wadelin" ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 1H PISTOL LONG melee broken, iStart >= iEnd. iStart = ", iStart, " iEnd = ", iEnd ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseWeaponButt = ", BOOL_TO_STRING( bCanUseWeaponButt ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseKick = ", BOOL_TO_STRING( bCanUseKick ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bUseLongAnim = ", BOOL_TO_STRING( bUseLongAnim ) ) ENDIF SWITCH GET_RANDOM_INT_IN_RANGE( iStart, iEnd ) CASE 0 eAnim = CCPLAYERANIM_BEATDOWN_LONG_PISTOL_A BREAK CASE 1 eAnim = CCPLAYERANIM_BEATDOWN_LONG_PISTOL_KICK_A BREAK ENDSWITCH ELSE IF bCanUseWeaponButt iStart = 0 ELSE iStart = 2 ENDIF IF bCanUseKick iEnd = 4 ELSE iEnd = 2 ENDIF IF iStart >= iEnd SCRIPT_ASSERT( "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 1H PISTOL NORMAL melee broken, iStart >= iEnd, see logs for details, bug Michael Wadelin" ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 1H PISTOL NORMAL melee broken, iStart >= iEnd. iStart = ", iStart, " iEnd = ", iEnd ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseWeaponButt = ", BOOL_TO_STRING( bCanUseWeaponButt ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseKick = ", BOOL_TO_STRING( bCanUseKick ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bUseLongAnim = ", BOOL_TO_STRING( bUseLongAnim ) ) ENDIF SWITCH GET_RANDOM_INT_IN_RANGE( iStart, iEnd ) CASE 0 eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_A BREAK CASE 1 eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_B BREAK CASE 2 eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_KICK_A BREAK CASE 3 eAnim = CCPLAYERANIM_BEATDOWN_PISTOL_KICK_B BREAK ENDSWITCH ENDIF ELIF IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_2H( eWeapType ) // only kicks allowed for weapons such as RPGs IF NOT IS_WEAPON_SUITABLE_FOR_CROWD_CONTROL_BEATDOWN_2H( eWeapType, TRUE ) bCanUseWeaponButt = FALSE bCanUseKick = TRUE ELSE // Disabled long kicks - player slides on planted leg, looks bad IF bUseLongAnim bCanUseKick = FALSE ENDIF ENDIF IF bCanUseWeaponButt iStart = 0 ELSE iStart = 2 ENDIF IF bCanUseKick iEnd = 4 ELSE iEnd = 2 ENDIF IF iStart >= iEnd SCRIPT_ASSERT( "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 2H RIFLE melee broken, iStart >= iEnd, see logs for details, bug Michael Wadelin" ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - random anim selection for 2H RIFLE melee broken, iStart >= iEnd. iStart = ", iStart, " iEnd = ", iEnd ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseWeaponButt = ", BOOL_TO_STRING( bCanUseWeaponButt ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bCanUseKick = ", BOOL_TO_STRING( bCanUseKick ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() bUseLongAnim = ", BOOL_TO_STRING( bUseLongAnim ) ) ENDIF IF bUseLongAnim SWITCH GET_RANDOM_INT_IN_RANGE( iStart, iEnd ) CASE 0 eAnim = CCPLAYERANIM_BEATDOWN_LONG_RIFLE_A BREAK CASE 1 eAnim = CCPLAYERANIM_BEATDOWN_LONG_RIFLE_B BREAK CASE 2 eAnim = CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_A BREAK CASE 3 eAnim = CCPLAYERANIM_BEATDOWN_LONG_RIFLE_KICK_B BREAK ENDSWITCH ELSE SWITCH GET_RANDOM_INT_IN_RANGE( iStart, iEnd ) CASE 0 eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_A BREAK CASE 1 eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_B BREAK CASE 2 eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_KICK_A BREAK CASE 3 eAnim = CCPLAYERANIM_BEATDOWN_RIFLE_KICK_B BREAK ENDSWITCH ENDIF ENDIF CROWD_CONTROL_PED_ANIM_TYPE eVictimAnim IF sPedData.iBeatdownHitsRemaining <= 0 eVictimAnim = CCPANIM_BEATDOWN_DIE ELIF sPedData.eState != CCPS_BEATDOWN eVictimAnim = CCPANIM_BEATDOWN_INTRO ELSE IF GET_RANDOM_BOOL() eVictimAnim = CCPANIM_BEATDOWN_HIT_A ELSE eVictimAnim = CCPANIM_BEATDOWN_HIT_B ENDIF ENDIF IF HAS_ANIM_DICT_LOADED( GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( eAnim ) ) AND HAS_ANIM_DICT_LOADED( GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eVictimAnim, sPedLocalData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) // Calculate position and orientation we want to play the anim at VECTOR vPlayerCoord = GET_ENTITY_COORDS( PLAYER_PED_ID() ) //VECTOR vVictimCoord = GET_ENTITY_COORDS( pedCrowd ) // Get the peds mover coord, this is the coord we will offset the animation from // We don't just use the mover directly as some peds need their mover adjusting depending on the player's angle of approach VECTOR vMoverCoord = GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET( pedCrowd, sPedLocalData.eCreatorAssignedPedID, vPlayerCoord, sLocalData.eHeistType ) // Calculate a distance that means the ped capsules won't intersect FLOAT fOffsetDistance = cfCC_BeatdownDistMin //= FMAX( cfCC_BeatdownDistMin, cfCC_PlayerPedCapsuleRadiusStationary + GET_CROWD_CONTROL_PED_CAPSULE_SIZE( sPedLocalData.eCreatorAssignedPedID, sLocalData.eHeistType ) ) VECTOR vPos = ( NORMALISE_VECTOR( vPlayerCoord - vMoverCoord ) * fOffsetDistance ) + vMoverCoord FLOAT fRot = ATAN2( -(vMoverCoord.X - vPlayerCoord.X), vMoverCoord.Y - vPlayerCoord.Y ) // VECTOR vPos = ( NORMALISE_VECTOR( vPlayerCoord - vVictimCoord ) * fOffsetDistance ) + vVictimCoord // FLOAT fRot = ATAN2( -(vVictimCoord.X - vPlayerCoord.X), vVictimCoord.Y - vPlayerCoord.Y ) sLocalData.iSyncSceneBeatdown = NETWORK_CREATE_SYNCHRONISED_SCENE( vPos, <<0,0,fRot>>, DEFAULT, FALSE, FALSE ) // Player NETWORK_ADD_PED_TO_SYNCHRONISED_SCENE( PLAYER_PED_ID(), sLocalData.iSyncSceneBeatdown, GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( eAnim ), GET_CROWD_CONTROL_PLAYER_ANIM_NAME( eAnim ), WALK_BLEND_IN, NORMAL_BLEND_OUT, DEFAULT, RBF_PLAYER_BUMP | RBF_PLAYER_IMPACT | RBF_PLAYER_RAGDOLL_BUMP | RBF_PED_RAGDOLL_BUMP, WALK_BLEND_IN ) // Victim NETWORK_ADD_PED_TO_SYNCHRONISED_SCENE( pedCrowd, sLocalData.iSyncSceneBeatdown, GET_CROWD_CONTROL_PED_ANIM_DICTIONARY( eVictimAnim, sPedLocalData.eCreatorAssignedPedID, sLocalData.eHeistType ), GET_CROWD_CONTROL_PED_ANIM_NAME( eVictimAnim, sPedLocalData.eCreatorAssignedPedID, sLocalData.eHeistType ), WALK_BLEND_IN, -0.1, SYNCED_SCENE_BLOCK_MOVER_UPDATE, RBF_PLAYER_BUMP | RBF_PLAYER_IMPACT | RBF_PLAYER_RAGDOLL_BUMP | RBF_PED_RAGDOLL_BUMP, DEFAULT ) NETWORK_START_SYNCHRONISED_SCENE( sLocalData.iSyncSceneBeatdown ) sLocalData.iPlayerBeatingThisPed = iCrowd sLocalData.eLastBeatdown = eAnim SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownFirst ) CLEAR_BIT_ENUM( sLocalData.iBitset, CCLOCALDATA_BeatdownInterrupt ) // REMOVED: causes animations to look strange, bent necks, etc // Make them look at the ped for a short while when kicking them //TASK_LOOK_AT_ENTITY( PLAYER_PED_ID(), pedCrowd, 5000, DEFAULT, SLF_LOOKAT_VERY_HIGH ) // Mark ped as being hit // If we own the ped update it directly IF NETWORK_HAS_CONTROL_OF_NETWORK_ID( niPed ) SET_BIT_ENUM( sPedLocalData.iBitset, CCLOCALPEDDATA_BeatdownFired ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - Setting ped flag CCPEDDATA_BeatdownFired" ) // Otherwise broadcast event ELSE BROADCAST_FMMC_CC_PED_BEATDOWN( iCrowd ) CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - broadcasting ped flag CCPEDDATA_BeatdownFired" ) ENDIF // Decrement hits remaining IF NETWORK_IS_HOST_OF_THIS_SCRIPT() sData.iNumHitsRemaining-- ELSE BROADCAST_FMMC_CC_PED_BEATDOWN_HIT() ENDIF RETURN TRUE ELSE CPRINTLN( DEBUG_NET_MINIGAME, "PLAY_CROWD_CONTROL_BEATDOWN() - Anims not loaded" ) ENDIF RETURN FALSE ENDFUNC PROC PROCESS_CROWD_CONTROL_BEATDOWNS( NETWORK_INDEX &niPeds[], CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData[], CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData[] ) // Weapon Blocking //------------------------------------------------------------- BOOL bPlayerCurrentlyPerformingBeatdown = IS_CROWD_CONTROL_PLAYER_PERFORMING_A_BEATDOWN( PLAYER_PED_ID() ) // While in a beatdown IF bPlayerCurrentlyPerformingBeatdown // Don't allow player to change weapon while doing 1 of the beat down anims DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_SELECT_WEAPON ) IF HAS_ANIM_EVENT_FIRED( PLAYER_PED_ID(), HASH( "vibrate" ) ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Melee impact vibration triggered" ) SET_CONTROL_SHAKE( PLAYER_CONTROL, 150, 255 ) // 150, 200 ENDIF // Break out of the anim early IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInterrupt ) OR HAS_ANIM_EVENT_FIRED( PLAYER_PED_ID(), HASH( "breakout" ) ) IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInterrupt ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInterrupt ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Beatdown interrupt hit" ) ENDIF IF IS_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_MOVE_UD ) OR IS_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_MOVE_LR ) OR IS_CONTROL_PRESSED( PLAYER_CONTROL, INPUT_AIM ) CLEAR_PED_TASKS( PLAYER_PED_ID() ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInputTaken ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Beatdown has been interrupted by player input" ) ENDIF ENDIF ELSE // Reset the ped being hit and last anim sLocalData.iPlayerBeatingThisPed = -1 sLocalData.eLastBeatdown = CCPLAYERANIM_INVALID ENDIF // Check if the player can beat the ped, no anim playing or anim ready to interrupt and player has suitible weapon and in suitible state BOOL bCanPlayerBeat IF NOT bPlayerCurrentlyPerformingBeatdown OR IS_BIT_SET_ENUM( sLocalData.iBitset, CCLOCALDATA_BeatdownInterrupt ) IF CAN_CROWD_CONTROL_PLAYER_PERFORM_A_BEATDOWN( PLAYER_ID(), PLAYER_PED_ID() ) bCanPlayerBeat = TRUE ENDIF ENDIF // Take input - we can detect this earlier than the interrupt window so that it doesn't feel unresponsive. BOOL bNeedsAReload WEAPON_TYPE eWeaponCurrent IF GET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), eWeaponCurrent ) INT iAmmoInClip IF GET_AMMO_IN_CLIP( PLAYER_PED_ID(), eWeaponCurrent, iAmmoInClip ) INT iAmmoInClipMax, iWeaponAmmo iWeaponAmmo = GET_AMMO_IN_PED_WEAPON( PLAYER_PED_ID(), eWeaponCurrent ) iAmmoInClipMax = GET_MAX_AMMO_IN_CLIP( PLAYER_PED_ID(), eWeaponCurrent ) IF iAmmoInClip < iWeaponAmmo AND iAmmoInClip < iAmmoInClipMax bNeedsAReload = TRUE ENDIF ENDIF ENDIF // If control is pressed or early input is made BOOL bMeleePressed IF NOT bNeedsAReload AND ( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInputTaken ) OR IS_CONTROL_JUST_PRESSED( PLAYER_CONTROL, INPUT_MELEE_ATTACK_LIGHT ) OR IS_DISABLED_CONTROL_JUST_PRESSED( PLAYER_CONTROL, INPUT_MELEE_ATTACK_LIGHT ) ) // Look out for early input IF bPlayerCurrentlyPerformingBeatdown AND sLocalData.eLastBeatdown != CCPLAYERANIM_INVALID AND HAS_CROWD_CONTROL_PLAYER_FINISHED_ANIM( PLAYER_PED_ID(), sLocalData.eLastBeatdown, 0.25, TRUE, sLocalData.iSyncSceneBeatdown ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInputTaken ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Early input taken and stored" ) ENDIF bMeleePressed = TRUE ENDIF BOOL bDisableMelee INT iPedToBeat = -1 INT iCrowd IF bCanPlayerBeat REPEAT sData.iNumCrowdControlPeds iCrowd BOOL bResetProbe = FALSE bResetProbe = FALSE IF NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPeds[sData.iCrowdControlCloudIndex[iCrowd]] ) PED_INDEX pedCrowd = NET_TO_PED( niPeds[sData.iCrowdControlCloudIndex[iCrowd]] ) IF NOT IS_PED_INJURED( pedCrowd ) AND IS_BIT_SET_ENUM( sPedData[iCrowd].iBitSet, CCPEDDATA_RunningBespokeAnims ) // disable regular melee buttons for player while near a crowd ped IF GET_DISTANCE_BETWEEN_ENTITIES( PLAYER_PED_ID(), pedCrowd ) < cfCC_BeatdownMeleeDisableDist bDisableMelee = TRUE ENDIF // found a ped we want for the beat down, but need to do 1 final test to probe for collision IF IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE( pedCrowd, PLAYER_PED_ID(), sLocalData, sLocalPedData[iCrowd] ) IF CAN_CROWD_CONTROL_PED_BE_BEATDOWN( pedCrowd, sPedData[iCrowd], sLocalPedData[iCrowd].eCreatorAssignedPedID, sLocalData.eHeistType ) INT iWasSomethingHit = 0 VECTOR vHitPos = <<0,0,0>> VECTOR vHitNormal = <<0,0,0>> ENTITY_INDEX entityHit = NULL SHAPETEST_STATUS eStatus = GET_SHAPE_TEST_RESULT( sLocalData.shapetestBeatdownProbe, iWasSomethingHit, vHitPos, vHitNormal, entityHit ) // Start a new shape test // either 1 hadn't been started or we want to test a different ped IF eStatus = SHAPETEST_STATUS_NONEXISTENT OR sLocalData.iCrowdPedBeatdownProbe != iCrowd VECTOR vCrowdPedCoord = GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET( pedCrowd, sLocalPedData[iCrowd].eCreatorAssignedPedID, GET_ENTITY_COORDS( PLAYER_PED_ID() ), sLocalData.eHeistType ) sLocalData.shapetestBeatdownProbe = START_SHAPE_TEST_CAPSULE( GET_ENTITY_COORDS( PLAYER_PED_ID() ), vCrowdPedCoord, 0.25, SCRIPT_INCLUDE_ALL, PLAYER_PED_ID(), SCRIPT_SHAPETEST_OPTION_IGNORE_NO_COLLISION ) sLocalData.iCrowdPedBeatdownProbe = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - Starting new probe." ) // Results ready, process them ELIF eStatus = SHAPETEST_STATUS_RESULTS_READY // We only update this flag once the test result comes back, we do not clear it and only set it to true // for the frames the result comes back on, this would lead to nothing happening a lot of the time input is pressed. IF iWasSomethingHit = 0 OR ( DOES_ENTITY_EXIST( entityHit ) AND IS_ENTITY_A_PED( entityHit ) AND GET_PED_INDEX_FROM_ENTITY_INDEX( entityHit ) = pedCrowd ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownProbeResultAllowHit ) CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - Probe successfull, Setting flag CCLOCALDATA_BeatdownProbeResultAllowHit" ) sLocalData.shapetestBeatdownProbe = NULL ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - Probe hit something, reset probe." ) bResetProbe = TRUE ENDIF ENDIF // SUCCESS, we are allowed to hit the ped IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownProbeResultAllowHit ) iPedToBeat = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - CCLOCALDATA_BeatdownProbeResultAllowHit is set, allow ped to be hit." ) ENDIF // Stop testing other peds iCrowd = sData.iNumCrowdControlPeds // BREAK LOOP ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - CAN_CROWD_CONTROL_PED_BE_BEATDOWN() failed." ) IF sLocalData.iCrowdPedBeatdownProbe = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - mark probe for reset." ) bResetProbe = TRUE ENDIF ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - IS_CROWD_CONTROL_PED_WITHIN_BEATDOWN_RANGE() failed." ) IF sLocalData.iCrowdPedBeatdownProbe = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - mark probe for reset." ) bResetProbe = TRUE ENDIF ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - ped dead or not running custom anims." ) IF sLocalData.iCrowdPedBeatdownProbe = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - mark probe for reset." ) bResetProbe = TRUE ENDIF ENDIF ELSE CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - net id does not exist." ) IF sLocalData.iCrowdPedBeatdownProbe = iCrowd CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - mark probe for reset." ) bResetProbe = TRUE ENDIF ENDIF IF bResetProbe CDEBUG2LN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() iCrowd = ", iCrowd, " - resetting probe, clearing flag CCLOCALDATA_BeatdownProbeResultAllowHit, sLocalData.iCrowdPedBeatdownProbe = ", sLocalData.iCrowdPedBeatdownProbe ) sLocalData.shapetestBeatdownProbe = NULL sLocalData.iCrowdPedBeatdownProbe = -1 CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownProbeResultAllowHit ) ENDIF ENDREPEAT ENDIF IF bDisableMelee 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_ATTACK_ALTERNATE ) SET_PED_CONFIG_FLAG( PLAYER_PED_ID(), PCF_DisableMelee, TRUE ) SET_PED_RESET_FLAG( PLAYER_PED_ID(), PRF_DisableAmbientMeleeMoves, TRUE ) SET_PED_RESET_FLAG( PLAYER_PED_ID(), PRF_SuspendInitiatedMeleeActions, TRUE ) ELSE SET_PED_CONFIG_FLAG( PLAYER_PED_ID(), PCF_DisableMelee, FALSE ) ENDIF IF bCanPlayerBeat IF iPedToBeat != -1 IF bMeleePressed IF bPlayerCurrentlyPerformingBeatdown AND IS_BIT_SET_ENUM( sLocalData.iBitset, CCLOCALDATA_BeatdownInterrupt ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Beatdown has been interrupted by new melee request" ) ENDIF WEAPON_TYPE eWeapType GET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), eWeapType ) CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_BEATDOWNS() - Playing beatdown on ped[", iPedToBeat, "] = ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData[iPedToBeat].eCreatorAssignedPedID ) ) PLAY_CROWD_CONTROL_BEATDOWN( niPeds[sData.iCrowdControlCloudIndex[iPedToBeat]], iPedToBeat, eWeapType, sData, sLocalData, sPedData[iPedToBeat], sLocalPedData[iPedToBeat] ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownInputTaken ) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Run by each player manages the minigame state for the host and also various local assets, cutscenes, etc for each player. PROC PROCESS_CROWD_CONTROL_MINIGAME_STATE( CROWD_CONTROL_SERVER_DATA &sCrowdControlData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sCrowdControlPedData[], CROWD_CONTROL_LOCAL_PED_DATA &sCrowdControlLocalPedData[], INT &iCrowdControlPedCloudIndex[], INT iNumCrowdPeds, NETWORK_INDEX &niPeds[], INT &iCurrentHighestPriority[], INT iLocalPlayersTeam ) UNUSED_PARAMETER(niPeds) UNUSED_PARAMETER(iCrowdControlPedCloudIndex) INT i // this is here cus stupid language won't let me declare is inside a switch case, BOOOOOOOOOOOOOOOOOO INT iLookupArray[FMMC_MAX_CROWD_PEDS] VECTOR vAlarmCoords[ciCC_MaxAlarms] // Custom anims required BOOL bRequireCustomAnims IF sLocalData.eHeistType = CCHEIST_CUSTOM_FLEECA OR sLocalData.eHeistType = CCHEIST_CUSTOM_ORNATE bRequireCustomAnims = TRUE ENDIF //STAGE ZERO - Wait for peds to initialise and start their intro idle scene SWITCH sCrowdControlData.iMinigameStage CASE 0 IF bRequireCustomAnims REQUEST_MODEL( PROP_PHONE_ING ) ENDIF IF NETWORK_IS_HOST_OF_THIS_SCRIPT() // Check if all peds are initialised BOOL bAllPedsReady bAllPedsReady = TRUE FOR i = 0 TO iNumCrowdPeds-1 IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_HasBeenInitialised ) bAllPedsReady = FALSE ENDIF ENDFOR IF bAllPedsReady // has already been reset else where, doubling up causes some issues //RESET_CROWD_CONTROL_LOCAL_DATA( sLocalData ) // Crowd is restricted to start with SET_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) // Set hero pick timer make sure an initial hero is selected SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimeSetNextHeroPick ) sLocalData.fFear = 0.0 sCrowdControlData.iMinigameStage++ ENDIF ENDIF BREAK //STAGE ONE - Kick off the crowd panic CASE 1 IF bRequireCustomAnims AND NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_IntroAnimsRequested ) REQUEST_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CCPANIM_INTRO, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) REQUEST_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CCPANIM_COWER_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) IF sLocalData.eHeistType != CCHEIST_CUSTOM_ORNATE REQUEST_ADDITIONAL_TEXT_FOR_DLC( "OBHFAU", DLC_TEXT_SLOT0 ) ENDIF SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_IntroAnimsRequested ) ENDIF IF NETWORK_IS_HOST_OF_THIS_SCRIPT() BOOL bKickOffCrowd // Has at least 1 ped kicked off? FOR i = 0 TO iNumCrowdPeds-1 // Crowd ped is no longer in intro state IF sCrowdControlPedData[i].eState != CCPS_INTRO bKickOffCrowd = TRUE i = FMMC_MAX_CROWD_PEDS // break loop ENDIF ENDFOR IF bRequireCustomAnims // SYNC SCENE: Intro transition to Cower // (note: only 1 machine can create and start the sync scene including on peds it doesnt own this is why we are doing it this way) IF HAVE_CROWD_CONTROL_PED_ANIMS_LOADED_FOR_SCENE( CCPANIM_INTRO, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) AND HAVE_CROWD_CONTROL_PED_ANIMS_LOADED_FOR_SCENE( CCPANIM_COWER_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) IF NOT bKickOffCrowd // Intro loop not running, run it IF sLocalData.iSyncSceneIntroLoop = -1 OR NOT IS_SYNCHRONIZED_SCENE_RUNNING( NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID( sLocalData.iSyncSceneIntroLoop ) ) PLAY_CROWD_CONTROL_SYNC_SCENE( sLocalData.iSyncSceneIntroLoop, niPeds, iCrowdControlPedCloudIndex, sCrowdControlLocalPedData, iNumCrowdPeds, CCPANIM_INTRO_LOOP, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, TRUE, FALSE, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT ) ENDIF ELSE // Intro loop -> Intro main (transition to cower where it all kicks off) PLAY_CROWD_CONTROL_SYNC_SCENE( sCrowdControlData.iSyncScene, niPeds, iCrowdControlPedCloudIndex, sCrowdControlLocalPedData, iNumCrowdPeds, CCPANIM_INTRO, sLocalData.eHeistType, REALLY_SLOW_BLEND_IN, -0.1, FALSE, TRUE, SYNCED_SCENE_USE_PHYSICS, RBF_PLAYER_IMPACT ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_RecievedSyncedScene ) // host will have the sync scene straight way so set this sCrowdControlData.iMinigameStage++ ENDIF ENDIF // No anim req so just go to the next stage ELSE sCrowdControlData.iMinigameStage++ ENDIF IF sCrowdControlData.iMinigameStage > 1 // Initialise the fear to full sLocalData.fFear = 100.0 // Set when the panic should be over sLocalData.timeCrowdKickedOff = GET_NETWORK_TIME() CPRINTLN( DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_MINIGAME_STATE() - bit set CCDATA_Active" ) SET_BIT_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) // Set active to inform other peds they need to kick off ENDIF ENDIF BREAK //STAGE TWO - Main minigame controller CASE 2 IF bRequireCustomAnims IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_MainAnimsRequested ) REQUEST_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CCPANIM_FLINCH_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) REQUEST_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CCPANIM_HERO_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) REQUEST_ANIM_DICT( GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( CCPLAYERANIM_BEATDOWN_RIFLE_A ) ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_MainAnimsRequested ) ENDIF // release the intro stuff now, we dont need it again IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_IntroAnimsRequested ) RELEASE_CROWD_CONTROL_PED_ANIMS_FOR_SCENE( CCPANIM_INTRO_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData, iNumCrowdPeds ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_IntroAnimsRequested ) ENDIF ENDIF IF NETWORK_IS_HOST_OF_THIS_SCRIPT() // Fail/Pass logic //------------------------------------------------------------------------- // Fail not currently disabled IF NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_FailDisabled ) IF SHOULD_DISABLE_CROWD_CONTROL_FAIL( sLocalData, iCurrentHighestPriority, iLocalPlayersTeam ) SET_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_FailDisabled ) // Not picked up a fail from a ped ELIF NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Failed ) INT iDeadCount, iKnockedOutPeds INT iDeadPedID, iKnockedOutPedID iDeadPedID = -1 iDeadCount = GET_CROWD_CONTROL_NUMBER_OF_DEAD_PEDS_WITH_PED_ID( sCrowdControlPedData, sCrowdControlData, iDeadPedID ) iKnockedOutPedID = -1 iKnockedOutPeds = GET_CROWD_CONTROL_NUMBER_OF_KNOCKED_OUT_PEDS_WITH_PED_ID( sCrowdControlPedData, sCrowdControlData, iKnockedOutPedID ) INT iDeadLimit, iKnockoutLimit iDeadLimit = GET_CROWD_CONTROL_PED_DEAD_LIMIT( sLocalData.eHeistType ) SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_ORNATE iKnockoutLimit = 2 BREAK DEFAULT iKnockoutLimit = -1 BREAK ENDSWITCH // dead limit reached - fail IF iDeadCount != -1 AND iDeadCount > iDeadLimit IF iDeadCount <= 1 sLocalData.eFailReason = CCFAIL_PEDKILLED ELSE sLocalData.eFailReason = CCFAIL_PEDSKILLED ENDIF sLocalData.iFailCausedByPed = iDeadPedID sLocalData.timeFailDelay = GET_TIME_OFFSET( GET_NETWORK_TIME(), 2000 ) // 2 second delay // knocked out limit reached, fail ELIF iKnockoutLimit != -1 AND iKnockedOutPeds > iKnockoutLimit sLocalData.eFailReason = CCFAIL_TOOMANYKNOCKOUTS sLocalData.iFailCausedByPed = sLocalData.iCashierPed sLocalData.timeFailDelay = GET_TIME_OFFSET( GET_NETWORK_TIME(), 3000 ) // no hits remaining ELIF sCrowdControlData.iNumHitsRemaining <= 0 sLocalData.eFailReason = CCFAIL_NOHITSREMAINING sLocalData.iFailCausedByPed = sLocalData.iCashierPed sLocalData.timeFailDelay = GET_TIME_OFFSET( GET_NETWORK_TIME(), 3000 ) ELSE CLEAR_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_FearFailsBlocked ) FOR i = 0 TO FMMC_MAX_TEAMS-1 IF iCurrentHighestPriority[i] < FMMC_MAX_RULES IF IS_BIT_SET( g_FMMC_STRUCT.sFMMCEndConditions[i].iRuleBitsetTwo[iCurrentHighestPriority[i]], ciBS_RULE2_DISABLE_CROWD_FEAR ) SET_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_FearFailsBlocked ) ENDIF ENDIF ENDFOR // Fail for overall fear level not acceptable IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Active ) AND NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_FearFailsBlocked ) AND NOT HAVE_ALL_PLAYERS_PASSED_CROWD_CONTROL_RULE( sLocalData, iCurrentHighestPriority, iLocalPlayersTeam ) AND sLocalData.fFear != -1 AND sLocalData.fIntimidationBar != -1 AND sLocalData.fIntimidationBar <= ciCC_FearFailMin // start the timer IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearFail ) sLocalData.timeFearFail = GET_TIME_OFFSET( GET_NETWORK_TIME(), 2000 ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearFail ) ENDIF // Fail by fear timer has expired and the fear is still not withint acceptable ranges IF IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalData.timeFearFail ) sLocalData.eFailReason = CCFAIL_FEARLOW sLocalData.timeFailDelay = GET_NETWORK_TIME() // no delay sLocalData.iFailCausedByPed = sLocalData.iCashierPed ENDIF ELSE // reset the fail timer IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearFail ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimerSetFearFail ) ENDIF ENDIF ENDIF IF sLocalData.eFailReason != CCFAIL_NONE SET_BIT_ENUM( sCrowdControlData.iBitSet, CCDATA_Failed ) CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_MINIGAME_STATE() - FAIL DETECTED - Fail Reason = ", GET_CROWD_CONTROL_FAIL_REASON_STRING( sLocalData.eFailReason ) ) BROADCAST_FMMC_CC_FAIL( ENUM_TO_INT( sLocalData.eFailReason ), sLocalData.iFailCausedByPed, sLocalData.timeFailDelay ) ENDIF ENDIF ENDIF // Hero picking logic //------------------------------------------------------------------------- SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA // Restrict the crowd after the easy pass and the cashier is into normal cower IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_EasyPassComplete ) IF NOT IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) SET_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ENDIF ELSE IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) CLEAR_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ENDIF ENDIF BREAK CASE CCHEIST_CUSTOM_ORNATE // Restrict the cashiers while waiting for the thermite to blow the door open objective IF ( sLocalData.iThermiteTeam != -1 AND sLocalData.iThermiteTeam < FMMC_MAX_TEAMS AND sLocalData.iThermiteRule != -1 AND sLocalData.iThermiteRule < FMMC_MAX_RULES AND iCurrentHighestPriority[sLocalData.iThermiteTeam] > sLocalData.iThermiteRule ) #IF IS_DEBUG_BUILD OR IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_RestrictedDebug ) #ENDIF IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) CLEAR_BIT_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ENDIF ENDIF BREAK ENDSWITCH // Clear any active heros that are no longer valid INT iLowestHeroAttempts iLowestHeroAttempts = -1 FOR i = 0 TO iNumCrowdPeds-1 INT iCurrentHeroAttemptsValue iCurrentHeroAttemptsValue = GET_PACKED_BITFIELD_VALUE_FROM_ARRAY( sCrowdControlData.iHeroAttempts, i, ciCC_HeroAttemptsDataBitWidth ) IF IS_BIT_SET( sCrowdControlData.iCurrentActiveHeros, i ) // If the mission has failed or passed or the hero is no longer valid or the crowd is now locked in clear the hero IF IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_Dead ) OR IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_KnockedOut ) OR IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Failed ) OR IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_FailDisabled ) OR ( NOT IS_CROWD_CONTROL_PED_A_VALID_HERO( sCrowdControlPedData[i], sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ) AND sCrowdControlPedData[i].eState != CCPS_HERO_ATTEMPT AND sCrowdControlPedData[i].eState != CCPS_HERO AND sCrowdControlPedData[i].eState != CCPS_COMBAT ) // Increment the attempts by 1 IF IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_HeroAttempted ) iCurrentHeroAttemptsValue++ SET_PACKED_BITFIELD_VALUE_IN_ARRAY( sCrowdControlData.iHeroAttempts, i, ciCC_HeroAttemptsDataBitWidth, iCurrentHeroAttemptsValue ) ENDIF CLEAR_BIT( sCrowdControlData.iCurrentActiveHeros, i ) ENDIF ENDIF // Check out all valid heroes who are not always active and see who has the lowest number of attempts IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_Dead ) AND NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_KnockedOut ) AND NOT IS_CROWD_CONTROL_PED_HERO_ALWAYS_ACTIVE( sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType ) AND IS_CROWD_CONTROL_PED_A_VALID_HERO( sCrowdControlPedData[i], sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ) IF iLowestHeroAttempts = -1 OR iCurrentHeroAttemptsValue < iLowestHeroAttempts iLowestHeroAttempts = iCurrentHeroAttemptsValue ENDIF ENDIF ENDFOR // Either minigame has failed or the fail has now been disabled, don't assign heros and go to next stage IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_FailDisabled ) OR IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Failed ) sCrowdControlData.iMinigameStage++ ELSE INT iHeroCount FOR i = 0 TO iNumCrowdPeds-1 // Initialse look up array with start numbers iLookupArray[i] = i // Count the current number of active regular heroes IF IS_BIT_SET( sCrowdControlData.iCurrentActiveHeros, i ) IF NOT IS_CROWD_CONTROL_PED_HERO_ALWAYS_ACTIVE( sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType ) iHeroCount++ ENDIF ENDIF // Make sure always active heros are turned on now IF NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_Dead ) AND NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_KnockedOut ) AND IS_CROWD_CONTROL_PED_HERO_ALWAYS_ACTIVE( sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType ) AND IS_CROWD_CONTROL_PED_A_VALID_HERO( sCrowdControlPedData[i], sCrowdControlLocalPedData[i].eCreatorAssignedPedID, sLocalData.eHeistType, IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ) CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_MINIGAME_STATE() - HERO SELECTED(always on hero) = ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) ) SET_BIT( sCrowdControlData.iCurrentActiveHeros, i ) ENDIF ENDFOR // Setup to only pick 1 new normal hero each time, even if we increase the max active heroes we still want this // so that we have a delay between heroes becoming active to avoid getting 2 becoming active at the same time // Only pick a new hero if there is space IF iHeroCount < ciCC_MaxActiveHeros IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimeSetNextHeroPick ) // Random time between 10 - 25 seconds (in 1 second intervals) sLocalData.timeNextHeroPick = GET_TIME_OFFSET( GET_NETWORK_TIME(), GET_RANDOM_INT_IN_RANGE( 7, 15 ) * 1000 ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimeSetNextHeroPick ) ENDIF // If the hero pick timer has expired then select a new hero IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimeSetNextHeroPick ) AND IS_TIME_MORE_THAN( GET_NETWORK_TIME(), sLocalData.timeNextHeroPick ) // Randomise array by using random value switching FOR i = 0 TO iNumCrowdPeds-1 INT iRand, iTemp iRand = GET_RANDOM_INT_IN_RANGE( 0, iNumCrowdPeds ) iTemp = iLookupArray[i] iLookupArray[i] = iLookupArray[iRand] iLookupArray[iRand] = iTemp ENDFOR // Set new heros in the random array FOR i = 0 TO iNumCrowdPeds-1 // Check if we can set this hero active IF NOT IS_BIT_SET( sCrowdControlData.iCurrentActiveHeros, iLookupArray[i] ) AND NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_Dead ) AND NOT IS_BIT_SET_ENUM( sCrowdControlPedData[i].iBitSet, CCPEDDATA_KnockedOut ) AND IS_CROWD_CONTROL_PED_A_VALID_HERO( sCrowdControlPedData[iLookupArray[i]], sCrowdControlLocalPedData[iLookupArray[i]].eCreatorAssignedPedID, sLocalData.eHeistType, IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Restricted ) ) AND NOT IS_CROWD_CONTROL_PED_HERO_ALWAYS_ACTIVE( sCrowdControlLocalPedData[iLookupArray[i]].eCreatorAssignedPedID, sLocalData.eHeistType ) AND GET_PACKED_BITFIELD_VALUE_FROM_ARRAY( sCrowdControlData.iHeroAttempts, iLookupArray[i], ciCC_HeroAttemptsDataBitWidth ) = iLowestHeroAttempts CPRINTLN(DEBUG_NET_MINIGAME, "PROCESS_CROWD_CONTROL_MINIGAME_STATE() - HERO SELECTED = ", GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sCrowdControlLocalPedData[iLookupArray[i]].eCreatorAssignedPedID ) ) SET_BIT( sCrowdControlData.iCurrentActiveHeros, iLookupArray[i] ) // Reset the hero pick timer and break the loop, only want to pick 1 this timer around CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_TimeSetNextHeroPick ) i = FMMC_MAX_CROWD_PEDS // break the loop ENDIF ENDFOR ENDIF ENDIF ENDIF ENDIF // Client machines check to see if their synced scene has started and if they can start updating the individual // peds that they own IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RecievedSyncedScene ) IF sCrowdControlData.iSyncScene != -1 INT iLocalSSID iLocalSSID = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID( sCrowdControlData.iSyncScene ) IF IS_SYNCHRONIZED_SCENE_RUNNING( iLocalSSID ) AND GET_SYNCHRONIZED_SCENE_PHASE( iLocalSSID ) > 0.5 // gives time for the anims to start SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_RecievedSyncedScene ) ENDIF ENDIF ENDIF BREAK //STAGE THREE - Post Crowd Control - Pass/Fail CASE 3 // Cleanup assets //---------------------------------------------------------------------------------- IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_MainAnimsRequested ) BOOL bAllCleanedUp bAllCleanedUp = TRUE FOR i = 0 TO sCrowdControlData.iNumCrowdControlPeds-1 IF NOT NETWORK_DOES_ENTITY_EXIST_WITH_NETWORK_ID( niPeds[sCrowdControlData.iCrowdControlCloudIndex[i]] ) OR IS_PED_INJURED( NET_TO_PED( niPeds[sCrowdControlData.iCrowdControlCloudIndex[i]] ) ) RELEASE_CROWD_CONTROL_PED_ANIM( CCPANIM_COWER_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) RELEASE_CROWD_CONTROL_PED_ANIM( CCPANIM_FLINCH_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) RELEASE_CROWD_CONTROL_PED_ANIM( CCPANIM_HERO_LOOP, sLocalData.eHeistType, sCrowdControlLocalPedData[i].eCreatorAssignedPedID ) ELSE bAllCleanedUp = FALSE ENDIF ENDFOR IF bAllCleanedUp REMOVE_ANIM_DICT( GET_CROWD_CONTROL_PLAYER_ANIM_DICTIONARY( CCPLAYERANIM_BEATDOWN_PISTOL_A ) ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_MainAnimsRequested ) ENDIF ENDIF // Raise the alarms //---------------------------------------------------------------------------------- IF IS_BIT_SET_ENUM( sCrowdControlData.iBitset, CCDATA_Failed ) BOOL bAlarmAvailable TEXT_LABEL_23 tlAlarmSoundBank TEXT_LABEL_23 tlAlarmName TEXT_LABEL_23 tlAlarmSountSet SWITCH sLocalData.eHeistType CASE CCHEIST_CUSTOM_FLEECA bAlarmAvailable = TRUE tlAlarmSoundBank = "ALARM_BELL_01" tlAlarmName = "Bell_01" tlAlarmSountSet = "ALARMS_SOUNDSET" vAlarmCoords[0] = <<-2965.2305, 486.2513, 17.5822>> BREAK CASE CCHEIST_CUSTOM_ORNATE bAlarmAvailable = TRUE tlAlarmSoundBank = "ALARM_BELL_01" tlAlarmName = "Bell_01" tlAlarmSountSet = "ALARMS_SOUNDSET" vAlarmCoords[0] = <<246.5,228.0,113.3>> vAlarmCoords[1] = <<260.3,216.0,104.1>> BREAK ENDSWITCH // Process loading and playing the alarms, if one is avilable IF bAlarmAvailable IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RaiseAlarms ) AND NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_AlarmsPlaying ) IF REQUEST_SCRIPT_AUDIO_BANK( tlAlarmSoundBank ) REPEAT ciCC_MaxAlarms i IF sLocalData.iSFXAlarms[i] = -1 sLocalData.iSFXAlarms[i] = GET_SOUND_ID() ENDIF IF sLocalData.iSFXAlarms[i] != -1 IF HAS_SOUND_FINISHED( sLocalData.iSFXAlarms[i] ) PLAY_SOUND_FROM_COORD( sLocalData.iSFXAlarms[i], tlAlarmName, vAlarmCoords[i], tlAlarmSountSet ) ENDIF ENDIF ENDREPEAT SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_AlarmsPlaying ) ENDIF ENDIF ENDIF ENDIF BREAK ENDSWITCH ENDPROC PROC PROCESS_CROWD_CONTROL_MINIGAME_HUD( CROWD_CONTROL_SERVER_DATA &sCrowdControlServerData, CROWD_CONTROL_LOCAL_DATA &sLocalData, BOOL bObjectiveIsCrowdControl ) IF bObjectiveIsCrowdControl // Player has entered the bank IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) IF HAS_PED_ENTERED_CROWD_CONTROL_TRIGGER_ZONE( PLAYER_PED_ID(), sLocalData, TRUE ) OR IS_BIT_SET_ENUM( sCrowdControlServerData.iBitset, CCDATA_Active ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) ENDIF ENDIF ELSE IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) CLEAR_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) ENDIF ENDIF IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_StartedFailCutscene ) // Initialise the bar to the current level of fear IF sLocalData.fIntimidationBar = -1 sLocalData.fIntimidationBar = 0.0 ELIF IS_BIT_SET_ENUM( sCrowdControlServerData.iBitset, CCDATA_Active ) // Interpolate the current bars value towards the desired one IF sLocalData.fIntimidationBar < sLocalData.fFear sLocalData.fIntimidationBar = CLAMP( sLocalData.fIntimidationBar + ( sLocalData.fIntimidationBarInterpRate * TIMESTEP() ), sLocalData.fIntimidationBar, sLocalData.fFear ) ELIF sLocalData.fIntimidationBar > sLocalData.fFear sLocalData.fIntimidationBar = CLAMP( sLocalData.fIntimidationBar - ( sLocalData.fIntimidationBarInterpRate * TIMESTEP() ), sLocalData.fFear, sLocalData.fIntimidationBar ) ENDIF ENDIF ENDIF IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) //AND NOT IS_BIT_SET(iLocalBoolCheck5,LBOOL5_PED_INVOLVED_IN_CUTSCENE) //AND NOT IS_BIT_SET(MC_playerBD[iPartToUse].iClientBitSet,PBBOOL_FINISHED) AND NOT g_bMissionEnding AND NOT IS_CUTSCENE_PLAYING() // Intimidation bar //-------------------------------------------------------------------------------- HUD_COLOURS eColor INT iFlashTimer // Enable the colour change and flashing once the bar has gone above the threshold for the first time IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HUDWarning ) AND sLocalData.fIntimidationBar > cfCC_PedBreakoutCowerThreshold SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_HUDWarning ) ENDIF IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HUDWarning ) AND sLocalData.fIntimidationBar <= cfCC_PedBreakoutCowerThreshold eColor = HUD_COLOUR_RED ELSE eColor = HUD_COLOUR_YELLOW ENDIF IF IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HUDWarning ) AND sLocalData.fIntimidationBar <= 15.0 iFlashTimer = 999999999 ELSE iFlashTimer = 0 ENDIF DRAW_GENERIC_METER( ROUND( sLocalData.fIntimidationBar ), 100, "MC_CRCON_L", eColor, iFlashTimer, HUDORDER_DONTCARE, -1, -1, FALSE, TRUE ) // Help text //-------------------------------------------------------------------------------- // HELP 1 - Brief IF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText1 ) PRINT_HELP( "CC_HELP1", 7000 ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText1 ) // HELP 2 - Intimidation instructions ELIF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText2 ) IF IS_BIT_SET_ENUM( sCrowdControlServerData.iBitset, CCDATA_Active ) AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( "CC_HELP1" ) PRINT_HELP( "CC_HELP2" ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText2 ) ENDIF // HELP 3 - Warning about hitting peds too much ELIF NOT IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText3 ) IF IS_BIT_SET_ENUM( sCrowdControlServerData.iBitset, CCDATA_Active ) IF sCrowdControlServerData.iNumHitsRemaining < ciCC_MaxBeatdownHitsTotal / 2 PRINT_HELP( "CC_HELP3" ) SET_BIT_ENUM( sLocalData.iBitSet, CCLOCALDATA_HelpText3 ) ENDIF ENDIF ENDIF ELSE IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( "CC_HELP1" ) OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( "CC_HELP2" ) CLEAR_HELP() ENDIF ENDIF ENDPROC #IF IS_DEBUG_BUILD CONST_FLOAT cfXOffsetStartHeader 0.03 CONST_FLOAT cfXOffsetStart 0.05 CONST_FLOAT cfYOffsetStart 0.15 CONST_FLOAT cfYOffset 0.015 PROC DISPLAY_DEBUG_PROGRESS_BAR( STRING strBarName, FLOAT fValue, INT &iCounter, FLOAT fMaxValue = 1.0, FLOAT fMinValue = 0.0, BOOL bIncludeWrittenValue = TRUE, FLOAT fUpperThreshold = -1.0, FLOAT fLowerThreshold = -1.0 ) TEXT_LABEL_63 tlDebug = strBarName tlDebug += ": " IF bIncludeWrittenValue tlDebug += GET_STRING_FROM_FLOAT( fValue, 2 ) ENDIF tlDebug += " [" // Clamp and adjust value for rendering the bar FLOAT fBarValue = CLAMP( fValue, fMinValue, fMaxValue ) fBarValue = ( fBarValue - fMinValue ) / ( fMaxValue - fMinValue ) INT i FOR i = 0 TO 9 IF fBarValue > ( i / 10.0 ) tlDebug += "x" ELSE tlDebug += "." ENDIF ENDFOR tlDebug += "]" IF ( fUpperThreshold != -1 AND fValue >= fUpperThreshold ) OR ( fLowerThreshold != -1 AND fValue <= fLowerThreshold ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColWarningR, ciCC_DebugColWarningG, ciCC_DebugColWarningB, 255 ) ELSE DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) ENDIF iCounter++ ENDPROC PROC DISPLAY_CROWD_CONTROL_DEBUG( CROWD_CONTROL_SERVER_DATA &sCrowdControlData, CROWD_CONTROL_LOCAL_DATA &sLocalData, INT &iThreatenData[], INT iNumCrowdPeds, INT &iCurrentHighestPriority[], INT iThisTeam ) IF sLocalData.eDebugDisplay != CCDEBUG_OFF INT iCounter TEXT_LABEL_63 tlDebug tlDebug = "CROWD CONTROL DEBUG: " tlDebug += GET_CROWD_CONTROL_DEBUG_NAME( sLocalData.eDebugDisplay ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ tlDebug = "STATE DATA" DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ IF NETWORK_IS_HOST_OF_THIS_SCRIPT() tlDebug = "I AM HOST" DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColActiveR, ciCC_DebugColActiveG, ciCC_DebugColActiveB, 255 ) ELSE tlDebug = "I AM A CLIENT" DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) ENDIF iCounter++ tlDebug = "eHeistType: " tlDebug += GET_CROWD_CONTROL_HEIST_TYPE_STRING( sLocalData.eHeistType ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "iMinigameStage: " tlDebug += sCrowdControlData.iMinigameStage DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ INT i FOR i = 0 TO FMMC_MAX_TEAMS-1 tlDebug = "iPriority[" tlDebug += i tlDebug += "]: " tlDebug += iCurrentHighestPriority[i] DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ ENDFOR iCounter++ // space // Bit flags tlDebug = "CrowdControlActive: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Active ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "CrowdRestricted: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Restricted ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "iNumHitsRemaining: " tlDebug += sCrowdControlData.iNumHitsRemaining DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ iCounter++ // space tlDebug = "PASS/FAIL" DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ tlDebug = "CrowdControlFailed: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_Failed ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "FailDisabled: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_FailDisabled ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "FailProcessed: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_FailProcessed ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "FailReason: " tlDebug += GET_CROWD_CONTROL_FAIL_REASON_STRING( sLocalData.eFailReason ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "EasyPassComplete: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_EasyPassComplete ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "EasyPassProcessed: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_EasyPassProcessed ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "FearFailsBlocked: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_FearFailsBlocked ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "RaiseAlarms: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RaiseAlarms ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "RaiseAlarmDialogue: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sCrowdControlData.iBitSet, CCDATA_RaiseAlarmDiagloue ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ iCounter++ // space IF sLocalData.eDebugDisplay = CCDEBUG_FEAR_AND_THREATS OR sLocalData.eDebugDisplay = CCDEBUG_ALL OR sLocalData.eDebugDisplay = CCDEBUG_BASIC tlDebug = "FEAR & THREATS" DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ DISPLAY_DEBUG_PROGRESS_BAR( "Fear(Local)", sLocalData.fFear, iCounter, 100.0, 0.0, DEFAULT, -1, cfCC_PedBreakoutCowerThreshold ) DISPLAY_DEBUG_PROGRESS_BAR( "Fear(Server)", sCrowdControlData.fFear, iCounter, 100.0, 0.0, DEFAULT, -1, cfCC_PedBreakoutCowerThreshold ) DISPLAY_DEBUG_PROGRESS_BAR( "Intimidation", sLocalData.fIntimidationBar, iCounter, 100.0, 0.0, DEFAULT, -1, cfCC_PedBreakoutCowerThreshold ) tlDebug = "BarInterpRate: " tlDebug += GET_STRING_FROM_FLOAT( sLocalData.fIntimidationBarInterpRate ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ DISPLAY_DEBUG_PROGRESS_BAR( "PlayerVoice", NETWORK_GET_PLAYER_LOUDNESS( PLAYER_ID() ), iCounter, DEFAULT, DEFAULT, DEFAULT, cfCC_ShoutVolumeLevel ) // Players threats to each crowd member FOR i = 0 TO iNumCrowdPeds-1 tlDebug = "[" tlDebug += i tlDebug += "]: " tlDebug += GET_CROWD_CONTROL_THREAT_TYPE_STRING( INT_TO_ENUM( CROWD_CONTROL_THREAT_TYPE, GET_PACKED_BITFIELD_VALUE_FROM_ARRAY( iThreatenData, i, ciCC_ThreatTypeDataBitWidth ) ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ ENDFOR iCounter++ // space ENDIF // BEATDOWNS //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_BEATDOWNS OR sLocalData.eDebugDisplay = CCDEBUG_ALL OR sLocalData.eDebugDisplay = CCDEBUG_BASIC tlDebug = "BEATDOWN" DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ tlDebug = "iCrowdPedBeatdownProbe: " tlDebug += sLocalData.iCrowdPedBeatdownProbe DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "ProbeResultAllowHit: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BeatdownProbeResultAllowHit ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ iCounter++ // space ENDIF // Misc //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_MISC OR sLocalData.eDebugDisplay = CCDEBUG_ALL OR sLocalData.eDebugDisplay = CCDEBUG_BASIC tlDebug = "MISC DATA" DRAW_DEBUG_TEXT_2D( tlDebug, <>, 255, 255, 255, 255 ) iCounter++ tlDebug = "DisplayHUD: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_DisplayHUD ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "ReceivedSyncScene: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_RecievedSyncedScene ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <<0.05, cfYOffsetStart + (cfYOffset * iCounter), 0.0>>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "SSIntroToCower: " tlDebug += sCrowdControlData.iSyncScene INT iSyncSceneLocal = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID( sCrowdControlData.iSyncScene ) tlDebug += "(" tlDebug += iSyncSceneLocal tlDebug += ")" DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "SSIntroLoop: " tlDebug += sLocalData.iSyncSceneIntroLoop iSyncSceneLocal = NETWORK_GET_LOCAL_SCENE_FROM_NETWORK_ID( sCrowdControlData.iSyncScene ) tlDebug += "(" tlDebug += iSyncSceneLocal tlDebug += ")" DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "iCCRule[" tlDebug += iThisTeam tlDebug += "]: " tlDebug += sLocalData.iCCRule[iThisTeam] DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ tlDebug = "BlockingActionMode" tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalData.iBitSet, CCLOCALDATA_BlockingActionMode ) ) DRAW_DEBUG_TEXT_2D( tlDebug, <>, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, 255 ) iCounter++ iCounter++ // space ENDIF ENDIF ENDPROC PROC DISPLAY_CROWD_CONTROL_PED_DEBUG( PED_INDEX ped, CROWD_CONTROL_SERVER_DATA &sData, CROWD_CONTROL_LOCAL_DATA &sLocalData, CROWD_CONTROL_PED_DECORATOR_DATA &sPedData, CROWD_CONTROL_LOCAL_PED_DATA &sLocalPedData, INT iCrowdNum, BOOL bIsOwned ) IF sLocalData.eDebugDisplay != CCDEBUG_OFF CONST_INT icXOffset 10 CONST_INT icYOffset 10 IF DOES_ENTITY_EXIST( ped ) VECTOR vPlayerCoord = GET_ENTITY_COORDS( PLAYER_PED_ID(), FALSE ) VECTOR vPedCoord = GET_ENTITY_COORDS( ped, FALSE ) IF NOT IS_VECTOR_ZERO( vPedCoord ) vPedCoord.Z += 0.75 FLOAT fDist = GET_DISTANCE_BETWEEN_COORDS( GET_FINAL_RENDERED_CAM_COORD(), vPedCoord ) INT iAlpha = ROUND( 255 * ( 1 - CLAMP( FMAX( fDist - 5.0, 0.0 ) / 10.0, 0.0, 1.0 ) ) ) INT iCounter TEXT_LABEL_63 tlDebug // BASIC //-------------------------------------------------------------------------------- tlDebug = "BASIC" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ IF bIsOwned tlDebug = "OWNED" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColActiveR, ciCC_DebugColActiveG, ciCC_DebugColActiveB, iAlpha ) ELSE tlDebug = "REMOTE" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) ENDIF iCounter++ tlDebug = "[" tlDebug += iCrowdNum tlDebug += "] " tlDebug += GET_CROWD_CONTROL_PED_NAME_FROM_ANIM_ID( sLocalPedData.eCreatorAssignedPedID ) IF IS_BIT_SET( sData.iCurrentActiveHeros, iCrowdNum ) OR IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroComplete ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColWarningR, ciCC_DebugColWarningG, ciCC_DebugColWarningB, iAlpha ) ELSE DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) ENDIF iCounter++ tlDebug = "State: " tlDebug += GET_CROWD_CONTROL_PED_STATE_STRING( sPedData.eState ) SWITCH sPedData.eState CASE CCPS_COMBAT CASE CCPS_HERO_ATTEMPT DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColWarningR, ciCC_DebugColWarningG, ciCC_DebugColWarningB, iAlpha ) BREAK DEFAULT DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) BREAK ENDSWITCH iCounter++ tlDebug = "StatePrev: " tlDebug += GET_CROWD_CONTROL_PED_STATE_STRING( sPedData.eStatePrev ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ IF NOT IS_PED_INJURED( ped ) tlDebug = "Speech: " IF IS_ANY_SPEECH_PLAYING( ped ) IF IS_AMBIENT_SPEECH_PLAYING( ped ) tlDebug += "Dialogue" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColActiveR, ciCC_DebugColActiveG, ciCC_DebugColActiveB, iAlpha ) ELSE tlDebug += "Pain" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColWarningR, ciCC_DebugColWarningG, ciCC_DebugColWarningB, iAlpha ) ENDIF ELSE DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) ENDIF ENDIF iCounter++ iCounter++ // space // FEAR //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_FEAR_AND_THREATS OR sLocalData.eDebugDisplay = CCDEBUG_ALL tlDebug = "FEAR & THREATS" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ tlDebug = "InfluenceDirectThreat: " tlDebug += GET_STRING_FROM_FLOAT( sPedData.fInfluenceDirectThreat, 2 ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "InfluenceShouting: " tlDebug += GET_STRING_FROM_FLOAT( sPedData.fInfluenceShouting, 2 ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_FearLocked: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_FearLocked ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space IF bIsOwned tlDebug = "*OWNER ONLY* eBiggestThreat: " tlDebug += GET_CROWD_CONTROL_THREAT_TYPE_STRING( sLocalPedData.eBiggestThreat ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "*OWNER ONLY* eThreatFelt: " tlDebug += GET_CROWD_CONTROL_THREAT_TYPE_STRING( sLocalPedData.eDebugThreatFelt ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ // draw line between ped and the player threatening them IF DOES_ENTITY_EXIST( sLocalPedData.pedBiggestThreat ) DRAW_DEBUG_LINE( vPedCoord, GET_ENTITY_COORDS( sLocalPedData.pedBiggestThreat ), 255, 0, 0, 255 ) ENDIF iCounter++ // space ENDIF ENDIF // HERO //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_HERO OR sLocalData.eDebugDisplay = CCDEBUG_ALL tlDebug = "HERO" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_HeroAttempted: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroAttempted ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_HeroComplete: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroComplete ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_HeroBroken: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HeroBroken ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "iHeroAttempts: " tlDebug += GET_PACKED_BITFIELD_VALUE_FROM_ARRAY( sData.iHeroAttempts, iCrowdNum, ciCC_HeroAttemptsDataBitWidth ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space ENDIF // BEATDOWNS //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_BEATDOWNS OR sLocalData.eDebugDisplay = CCDEBUG_ALL tlDebug = "BEATDOWNS" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ tlDebug = "iBeatdownRounds: " tlDebug += sPedData.iBeatdownRounds DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "iBeatdownHitsRemaining: " tlDebug += sPedData.iBeatdownHitsRemaining DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "BeatdownFired: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_BeatdownFired ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "BeatdownSyncSceneStarted: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_BeatdownSyncSceneStarted ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space IF IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) VECTOR vMoverOffset VECTOR vGroundCoord vMoverOffset = GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET( ped, sLocalPedData.eCreatorAssignedPedID, GET_ENTITY_COORDS( PLAYER_PED_ID(), FALSE ), sLocalData.eHeistType ) vGroundCoord = vMoverOffset GET_GROUND_Z_FOR_3D_COORD( vMoverOffset, vGroundCoord.Z ) // Melee disable range INT iColR, iColG, iColB // Animated melee range FLOAT fDistToMover fDistToMover = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD( PLAYER_PED_ID(), vMoverOffset, FALSE ) IF fDistToMover <= cfCC_BeatdownDistMax // Set the color to green iColR = 0 iColG = 255 iColB = 0 // Draw debug showing the mover offset VECTOR vMin, vMax IF GET_CROWD_CONTROL_PED_BEATDOWN_MOVER_OFFSET_MIN_MAX( sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, vMin, vMax ) vMin = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS( ped, vMin ) vMax = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS( ped, vMax ) // joining line DRAW_DEBUG_LINE( vMin, vMax, 0, 0, 255, 255 ) // min node and line to ground DRAW_DEBUG_LINE( vMin, <>, 0, 0, 255, 255 ) DRAW_DEBUG_SPHERE( vMin, 0.03, 0, 0, 255, 255 ) // max node and line to ground DRAW_DEBUG_LINE( vMax, <>, 0, 0, 255, 255 ) DRAW_DEBUG_SPHERE( vMax, 0.03, 0, 0, 255, 255 ) ENDIF // Mover offset DRAW_DEBUG_SPHERE( vMoverOffset, 0.05, 255, 0, 0, 255 ) ELSE iColR = 255 iColG = 0 iColB = 0 ENDIF DRAW_MARKER(MARKER_CONE, vGroundCoord+<<0,0,0.01>>, <<0,0,0>>, <<0,0,0>>, <>, iColR, iColG, iColB, iAlpha ) FLOAT fCoronaHeight IF fDistToMover <= cfCC_BeatdownMeleeDisableDist // Draw the angle range debug once within melee disable range FLOAT fCurrentFacingAngleRange, fPlayerHeading VECTOR vLeftBoundary, vRightBoundary fCurrentFacingAngleRange = GET_CROWD_CONTROL_PED_BEATDOWN_FACING_ANGLE_RANGE( vPlayerCoord, vMoverOffset ) fPlayerHeading = GET_ENTITY_HEADING( PLAYER_PED_ID() ) vLeftBoundary = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS( vPlayerCoord, fPlayerHeading - fCurrentFacingAngleRange, << 0, cfCC_BeatdownDistMax, 0 >> ) vRightBoundary = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS( vPlayerCoord, fPlayerHeading + fCurrentFacingAngleRange, << 0, cfCC_BeatdownDistMax, 0 >> ) IF IS_ENTITY_FACING_COORD_WITHIN_RANGE( PLAYER_PED_ID(), vMoverOffset, fCurrentFacingAngleRange ) iColR = 0 iColG = 255 iColB = 0 ELSE iColR = 255 iColG = 50 iColB = 0 ENDIF tlDebug = GET_STRING_FROM_FLOAT( -fCurrentFacingAngleRange, 2 ) DRAW_DEBUG_LINE( vPlayerCoord, vLeftBoundary, iColR, iColG, iColB, 255 ) DRAW_DEBUG_TEXT( tlDebug, vLeftBoundary, iColR, iColG, iColB, 255 ) tlDebug = GET_STRING_FROM_FLOAT( fCurrentFacingAngleRange, 2 ) DRAW_DEBUG_LINE( vPlayerCoord, vRightBoundary, iColR, iColG, iColB, 255 ) DRAW_DEBUG_TEXT( tlDebug, vRightBoundary, iColR, iColG, iColB, 255 ) // Melee disable corona color & height iColR = 255 iColG = 0 iColB = 0 fCoronaHeight = 0.1 ELSE iColR = 255 iColG = 255 iColB = 255 fCoronaHeight = 0.05 ENDIF // Draw the disable melee corona DRAW_MARKER(MARKER_CYLINDER, vGroundCoord, <<0,0,0>>, <<0,0,0>>, <>, iColR, iColG, iColB, iAlpha ) ENDIF ENDIF // Dialogue //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_DIALOGUE tlDebug = "DIALOGUE" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ tlDebug = "Current: " tlDebug += GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueCurrentlyPlaying ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Context: " IF IS_ANY_SPEECH_PLAYING( ped ) IF IS_AMBIENT_SPEECH_PLAYING( ped ) TEXT_LABEL_23 tlConvo, tlDummy INT iLine IF GET_CROWD_CONTROL_PED_DIALOGUE_ROOT_LABEL( sLocalPedData.eCreatorAssignedPedID, sLocalPedData.eDialogueCurrentlyPlaying, sLocalData.eHeistType, tlConvo, tlDummy, iLine ) tlDebug += tlConvo tlDebug += " (" tlDebug += GET_CONVERSATION_LINE_FILENAME_FROM_CONVERSATION_ROOT( tlConvo, iLine ) tlDebug += ")" ENDIF ELSE tlDebug += GET_AUD_DAMAGE_REASON_DEBUG_STRING( GET_CROWD_CONTROL_PED_ALTERNATIVE_PAIN_DIALOGUE( sLocalPedData.eDialogueCurrentlyPlaying ) ) ENDIF ENDIF DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Client->Host: " tlDebug += GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueClientToHost ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Host->Client: " tlDebug += GET_CROWD_CONTROL_DIALOGUE_ENUM_STRING( sLocalPedData.eDialogueHostToClient ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space TEXT_LABEL_15 tlProfile TEXT_LABEL_23 tlDummy GET_CROWD_CONTROL_VOICE_RACE_GENDER_PREFIX( sLocalPedData.eCreatorAssignedPedID, sLocalData.eHeistType, tlProfile, tlDummy ) tlDebug = "Profile: " tlDebug += tlProfile DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "LastTriggered: " tlDebug += GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueLastBroadcast, GET_NETWORK_TIME() ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space tlDebug = "Timer(SCARED_HIGH): " tlDebug += IMAX( 0, GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueContextTimers[CCDIACONTEXT_SCARED_HIGH], GET_NETWORK_TIME() ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Timer(SCARED_MEDIUM): " tlDebug += IMAX( 0, GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueContextTimers[CCDIACONTEXT_SCARED_MEDIUM], GET_NETWORK_TIME() ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Timer(SCARED_LOW): " tlDebug += IMAX( 0, GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueContextTimers[CCDIACONTEXT_SCARED_LOW], GET_NETWORK_TIME() ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Timer(SCARED_SECOND_HAND): " tlDebug += IMAX( 0, GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueContextTimers[CCDIACONTEXT_SCARED_SECOND_HAND], GET_NETWORK_TIME() ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "Timer(AMBIENT): " tlDebug += IMAX( 0, GET_TIME_DIFFERENCE( sLocalPedData.timeDialogueContextTimers[CCDIACONTEXT_AMBIENT], GET_NETWORK_TIME() ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space ENDIF // MISC //-------------------------------------------------------------------------------- IF sLocalData.eDebugDisplay = CCDEBUG_MISC OR sLocalData.eDebugDisplay = CCDEBUG_ALL tlDebug = "MISC" DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, 0, icYOffset * iCounter, 255, 255, 255, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_Dead: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_Dead ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_KnockedOut: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_KnockedOut ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_HasBeenInitialised: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_HasBeenInitialised ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCLOCALPEDDATA_LocallyInitialised: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sLocalPedData.iBitSet, CCLOCALPEDDATA_LocallyInitialised ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_RunningBespokeAnims: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_RunningBespokeAnims ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ tlDebug = "CCPEDDATA_IgnoreStickyBombs: " tlDebug += BOOL_TO_STRING( IS_BIT_SET_ENUM( sPedData.iBitSet, CCPEDDATA_IgnoreStickyBombs ) ) DRAW_DEBUG_TEXT_WITH_OFFSET( tlDebug, vPedCoord, icXOffset, icYOffset * iCounter, ciCC_DebugColNormalR, ciCC_DebugColNormalG, ciCC_DebugColNormalB, iAlpha ) iCounter++ iCounter++ // space ENDIF ENDIF ENDIF ENDIF ENDPROC #ENDIF