Files
gtav-src/script/dev_ng/singleplayer/include/private/beast_secret_fight.sch
T
2025-09-29 00:52:08 +02:00

1152 lines
48 KiB
Scheme
Executable File

USING "globals.sch"
USING "rage_builtins.sch"
USING "net_include.sch"
USING "ambient_globals.sch"
USING "commands_player.sch"
USING "commands_audio.sch"
USING "script_clock.sch"
USING "candidate_public.sch"
USING "beast_secret_shared.sch"
#IF FEATURE_SP_DLC_BEAST_SECRET
//
// The Beast Finale
//
CONST_INT BF_BIT_REQUESTED_ASSETS 0
CONST_INT BF_BIT_CREATED_BEAST 1
CONST_INT BF_BIT_BEAST_WAITING 2
CONST_INT BF_BIT_BEAST_LEAVING 3
CONST_INT BF_BIT_BEAST_WINDOW_PASSED 4
CONST_INT BF_BIT_BEAST_INJURED 5
CONST_INT BF_BIT_BEAST_FIGHT_ACTIVE 6
CONST_INT BF_BIT_BEAST_DEAD 7
CONST_INT BF_BIT_SOUND_PLAYING 8
CONST_INT BF_BIT_KNOCKED_DOWN 9
CONST_INT BF_BIT_ALLOWED_TO_RUN_LAST_FRAME 10
CONST_FLOAT BF_STREAM_IN_RANGE_SQR 5625.0 //75^2
CONST_FLOAT BF_STREAM_OUT_RANGE_SQR 6400.0 //80^2
CONST_FLOAT BF_LEAVE_TIMER_RANGE_SQR 3600.0 //60^2
CONST_INT BF_VISIBLE_TIME 9000
CONST_INT BF_BUSH_SLIDE_TIME 400
CONST_INT BF_STUCK_UNDER_CAR_TIME 500
CONST_INT BF_MAX_DEAD_FRAMES 10 //Frames to wait until cancelling fight
#IF IS_DEBUG_BUILD
FUNC STRING Get_Beast_Fight_State_String(BeastFightState eBFS)
SWITCH eBFS
CASE BFS_Intro RETURN "Intro" BREAK
CASE BFS_Approach_Player RETURN "Approach player" BREAK
CASE BFS_Attack_Player RETURN "Attack player" BREAK
CASE BFS_Let_Player_Get_Up RETURN "Let player get up" BREAK
CASE BFS_Call_Backup RETURN "Call backup" BREAK
CASE BFS_Let_Dogs_Attack RETURN "Let dogs attack" BREAK
CASE BFS_Run_Away RETURN "Running away" BREAK
CASE BFS_Death RETURN "Death" BREAK
ENDSWITCH
RETURN "Unknown"
ENDFUNC
#ENDIF
PROC Set_Beast_State(BeastFightState eBFS, INT iStageTimerValue = 0)
CPRINTLN(debug_hunting, "->Beast switching from state ",Get_Beast_Fight_State_String(sBeastFinaleVars.eBeastFightingState)," to: ",Get_Beast_Fight_State_String(eBFS))
sBeastFinaleVars.eBeastFightingState = eBFS
sBeastFinaleVars.iProg = 0
sBeastFinaleVars.iTimerStage = GET_GAME_TIMER() + iStageTimerValue
ENDPROC
PROC Reset_Beast_Finale_Variables()
//Unset "ready" flag
CLEAR_BITMASK(g_iBeastSetupInt, BH_Bit_Fight_Init)
sBeastFinaleVars.iState = 0
sBeastFinaleVars.iSoundID = -1
sBeastFinaleVars.iTimer = -1
//Beast peyote Z set-up
Set_Beast_Peyote_Vectors_Z()
//Beast Hunt X Set-up
Set_Beast_Hunt_Vectors_X()
//Beast fight y set-up
Set_Beast_Fight_Vectors_y()
sBeastFinaleVars.relGroupHashBeast = INT_TO_ENUM(REL_GROUP_HASH, HASH("DLC_SFX1/BEAST"))
sBeastFinaleVars.sFightMusic = Build_Beast_String_31("OWE","HALL","SIC","EN_START_MU") //"HALLOWEEN_START_MUSIC"
sBeastFinaleVars.sFightMusicStop = Build_Beast_String_31("WEEN_F","HALLO","P_MUSIC","AST_STO") //"HALLOWEEN_FAST_STOP_MUSIC"
//Taunts for when the player is down.
sBeastFinaleVars.sTauntAnimDicts[0] = Build_Long_Beast_String_63( "NUCKL", "M@MP_PLA", "NMALE@K",
"E_CRUNCH", "ANI", "TCELE",
"BRATIO", "YER_IN") //"ANIM@MP_PLAYER_INTCELEBRATIONMALE@KNUCKLE_CRUNCH"
sBeastFinaleVars.sTauntAnims[0] = Build_Beast_String_23("UCK", "KN", "UNCH", "LE_CR") //"KNUCKLE_CRUNCH"
sBeastFinaleVars.sTauntAnimDicts[1] = Build_Long_Beast_String_63( "ALE@FAC", "IM@MP", "ATIONM",
"E_PALM", "AN", "ER_INTC",
"ELEBR", "_PLAY") //"ANIM@MP_PLAYER_INTCELEBRATIONMALE@FACE_PALM"
sBeastFinaleVars.sTauntAnims[1] = Build_Beast_String_23("CE", "FA", "LM", "_PA") //"FACE_PALM"
sBeastFinaleVars.sTauntAnimDicts[2] = Build_Long_Beast_String_63( "B_ON_E", "M@MP_PLA", "E@THUM",
"ARS", "ANI", "LEBRATI",
"ONMAL", "YER_INTCE") //"ANIM@MP_PLAYER_INTCELEBRATIONMALE@THUMB_ON_EARS"
sBeastFinaleVars.sTauntAnims[2] = Build_Beast_String_23("MB_", "THU", "ARS", "ON_E") //"THUMB_ON_EARS"
sBeastFinaleVars.sTauntAnimDicts[3] = Build_Beast_String_63("E_STRA", "MOV", "OLL", "FE@R") //"MOVE_STRAFE@ROLL"
sBeastFinaleVars.sTauntAnims[3] = Build_Beast_String_23("ATRO","COMB","D_P1_180","LL_BW") //"COMBATROLL_BWD_P1_180"
sBeastFinaleVars.sTransformAnimDict = Build_Beast_String_31("M@MP_F","ANI","T@INTRO","M_EVEN") //"ANIM@MP_FM_EVENT@INTRO"
sBeastFinaleVars.sTransformAnim = Build_Beast_String_31("ST_T","BEA","FORM","RANS") //"BEAST_TRANSFORM"
sBeastFinaleVars.sBeastSfx = Build_Beast_String_31("C_SF", "DL", "AST", "X1/BE") //"DLC_SFX1/BEAST"
sBeastFinaleVars.sKneelingAnim = Build_Beast_String_31("DIC@ST","AMB@ME","EEL@IDLE_A","ANDING@KN") //"AMB@MEDIC@STANDING@KNEEL@IDLE_A"
sBeastFinaleVars.sRelGroup = Build_Beast_String_31("L_GR","RE","AST","OUP_BE")
sBeastFinaleVars.sBeastCalls = Build_Beast_String_31("ST_C","BEA","LS","AL") //"BEAST_CALLS"
sBeastFinaleVars.sFMEvents = Build_Beast_String_31("NTS_S","FM_EVE","TCH_SOUNDS","ASQUA") //"FM_EVENTS_SASQUATCH_SOUNDS")
ENDPROC
PROC Request_Beast_Finale_Assets()
INT i
CPRINTLN(DEBUG_HUNTING, "Requesting beast finale assets.")
REQUEST_SCRIPT_AUDIO_BANK(sBeastFinaleVars.sBeastSfx) //"DLC_SFX1/BEAST"
MODEL_NAMES eBeastModel = Get_Beast_Model()
MODEL_NAMES eLionModel = Get_Beast_Hint_Model_A(BHT_LION)
MODEL_NAMES eRottweilerModel = Get_Rottweiler_Model()
REQUEST_MODEL(eBeastModel)
REQUEST_MODEL(eLionModel)
REQUEST_MODEL(eRottweilerModel)
REQUEST_ANIM_DICT(sBeastFinaleVars.sKneelingAnim) //"AMB@MEDIC@STANDING@KNEEL@IDLE_A")
REQUEST_ANIM_DICT(sBeastFinaleVars.sTransformAnimDict)
REPEAT BF_NUM_TAUNT_ANIMS i
REQUEST_ANIM_DICT(sBeastFinaleVars.sTauntAnimDicts[i])
ENDREPEAT
ADD_RELATIONSHIP_GROUP(sBeastFinaleVars.sRelGroup, sBeastFinaleVars.relGroupHashBeast)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
ENDPROC
FUNC BOOL Have_Beast_Finale_Assets_Loaded()
INT i
REPEAT BF_NUM_TAUNT_ANIMS i
IF NOT HAS_ANIM_DICT_LOADED(sBeastFinaleVars.sTauntAnimDicts[i])
RETURN FALSE
ENDIF
ENDREPEAT
MODEL_NAMES eBeastModel = Get_Beast_Model()
MODEL_NAMES eLionModel = Get_Beast_Hint_Model_A(BHT_LION)
MODEL_NAMES eRottweilerModel = Get_Rottweiler_Model()
IF REQUEST_SCRIPT_AUDIO_BANK(sBeastFinaleVars.sBeastSfx) //"DLC_SFX1/BEAST"
AND HAS_MODEL_LOADED(eBeastModel)
AND HAS_MODEL_LOADED(eLionModel)
AND HAS_MODEL_LOADED(eRottweilerModel)
AND HAS_ANIM_DICT_LOADED(sBeastFinaleVars.sKneelingAnim) //"AMB@MEDIC@STANDING@KNEEL@IDLE_A")
AND HAS_ANIM_DICT_LOADED(sBeastFinaleVars.sTransformAnimDict)
AND DOES_RELATIONSHIP_GROUP_EXIST(sBeastFinaleVars.relGroupHashBeast)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC Release_Beast_Finale_Assets()
INT i
CPRINTLN(DEBUG_HUNTING, "Releasing beast finale assets.")
RELEASE_SCRIPT_AUDIO_BANK()
MODEL_NAMES eBeastModel = Get_Beast_Model()
MODEL_NAMES eLionModel = Get_Beast_Hint_Model_A(BHT_LION)
MODEL_NAMES eRottweilerModel = Get_Rottweiler_Model()
SET_MODEL_AS_NO_LONGER_NEEDED(eBeastModel)
SET_MODEL_AS_NO_LONGER_NEEDED(eLionModel)
SET_MODEL_AS_NO_LONGER_NEEDED(eRottweilerModel)
REMOVE_ANIM_DICT(sBeastFinaleVars.sKneelingAnim) //"AMB@MEDIC@STANDING@KNEEL@IDLE_A")
REMOVE_ANIM_DICT(sBeastFinaleVars.sTransformAnimDict)
REPEAT BF_NUM_TAUNT_ANIMS i
REMOVE_ANIM_DICT(sBeastFinaleVars.sTauntAnimDicts[i])
ENDREPEAT
REMOVE_RELATIONSHIP_GROUP(sBeastFinaleVars.relGroupHashBeast)
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
ENDPROC
PROC Cleanup_Beast_Fight(BOOL bDeleteBeast = FALSE)
CPRINTLN(DEBUG_HUNTING, "Cleaning up beast fight.")
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
SET_PED_AS_NO_LONGER_NEEDED(sBeastFinaleVars.pedBeast)
IF bDeleteBeast
DELETE_PED(sBeastFinaleVars.pedBeast)
ENDIF
ENDIF
INT iAnimalIndex
REPEAT BF_MAX_ANIMALS_TO_SPAWN iAnimalIndex
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedAnimals[iAnimalIndex])
SET_PED_AS_NO_LONGER_NEEDED(sBeastFinaleVars.pedAnimals[iAnimalIndex])
ENDIF
ENDREPEAT
//Free up weather.
TEXT_LABEL_23 tlWeather = Build_Beast_String_23("TR", "EX", "NY", "ASUN") //"EXTRASUNNY"
SET_WEATHER_TYPE_OVERTIME_PERSIST(tlWeather, 5.0)
//Free up clock.
PAUSE_CLOCK(FALSE)
//Stop event music
CANCEL_MUSIC_EVENT(sBeastFinaleVars.sFightMusic)
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_FIGHT_ACTIVE)
CPRINTLN(debug_hunting,"Triggering music stop")
TRIGGER_MUSIC_EVENT(sBeastFinaleVars.sFightMusicStop) // "HALLOWEEN_FAST_STOP_MUSIC")
ENDIF
//Default wanted levels
SET_MAX_WANTED_LEVEL(sBeastFinaleVars.iStartWantedLevel)
Release_Beast_Finale_Assets()
sBeastFinaleVars.iState = 0
ENDPROC
PROC Fail_Beast_Fight()
CPRINTLN(debug_hunting, "Beast fight failed, cleaning up")
Cleanup_Beast_Fight(TRUE)
//Set the bits for the failed fight
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_FIGHT_ACTIVE)
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_FIGHT_FAILED)
ENDPROC
PROC Create_Beast(VECTOR vPosition, FLOAT fHeading, BOOL bForCombat)
CPRINTLN(DEBUG_HUNTING, "Creating beast.")
sBeastFinaleVars.pedBeast = CREATE_PED(PEDTYPE_MISSION, MP_M_FREEMODE_01, vPosition, fHeading, FALSE, FALSE)
IF IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
CERRORLN(debug_hunting, "WARNING! Beast ped not alive this frame!")
EXIT
ENDIF
Set_Male_Beast_Outfit_On_Ped(sBeastFinaleVars.pedBeast )
SET_PED_SUFFERS_CRITICAL_HITS(sBeastFinaleVars.pedBeast, FALSE)
SET_PED_MAX_HEALTH(sBeastFinaleVars.pedBeast, 100000)
SET_ENTITY_HEALTH(sBeastFinaleVars.pedBeast, 100000)
SET_PED_MONEY(sBeastFinaleVars.pedBeast, 0)
DISABLE_PED_PAIN_AUDIO(sBeastFinaleVars.pedBeast, TRUE)
IF bForCombat
SET_PED_RELATIONSHIP_GROUP_HASH(sBeastFinaleVars.pedBeast, sBeastFinaleVars.relGroupHashBeast)
//Remove all weapons but the melee
REMOVE_ALL_PED_WEAPONS(sBeastFinaleVars.pedBeast, FALSE)
SET_CURRENT_PED_WEAPON(sBeastFinaleVars.pedBeast, WEAPONTYPE_UNARMED, TRUE)
//Beast hates the player.
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE, RELGROUPHASH_PLAYER, sBeastFinaleVars.relGroupHashBeast)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE, sBeastFinaleVars.relGroupHashBeast, RELGROUPHASH_PLAYER)
//Ignores the Hillbillies.
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_IGNORE, RELGROUPHASH_AMBIENT_GANG_HILLBILLY, sBeastFinaleVars.relGroupHashBeast)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_IGNORE, sBeastFinaleVars.relGroupHashBeast, RELGROUPHASH_AMBIENT_GANG_HILLBILLY)
//Likes the guards dogs.
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, INT_TO_ENUM(REL_GROUP_HASH, HASH("GUARD_DOG")), sBeastFinaleVars.relGroupHashBeast)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, sBeastFinaleVars.relGroupHashBeast, INT_TO_ENUM(REL_GROUP_HASH, HASH("GUARD_DOG")))
//Likes cougars.
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, INT_TO_ENUM(REL_GROUP_HASH, HASH("COUGAR")), sBeastFinaleVars.relGroupHashBeast)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, sBeastFinaleVars.relGroupHashBeast, INT_TO_ENUM(REL_GROUP_HASH, HASH("COUGAR")))
//Likes wild animals.
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE, INT_TO_ENUM(REL_GROUP_HASH, HASH("WILD_ANIMAL")), sBeastFinaleVars.relGroupHashBeast)
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE, sBeastFinaleVars.relGroupHashBeast, INT_TO_ENUM(REL_GROUP_HASH, HASH("WILD_ANIMAL")))
SET_PLAYER_MELEE_WEAPON_DAMAGE_MODIFIER(PLAYER_ID(), 150.0) //Player melee damage against the beast
SET_DISABLE_HIGH_FALL_DEATH(sBeastFinaleVars.pedBeast, TRUE)
SET_COMBAT_FLOAT(sBeastFinaleVars.pedBeast, CCF_FIGHT_PROFICIENCY, 1.0)
SET_PED_COMBAT_ABILITY(sBeastFinaleVars.pedBeast, CAL_PROFESSIONAL)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_AGGRESSIVE, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_ALWAYS_FIGHT, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_PERFECT_ACCURACY, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_MAINTAIN_MIN_DISTANCE_TO_TARGET, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_CAN_FIGHT_ARMED_PEDS_WHEN_NOT_ARMED, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_CAN_CHARGE, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_CAN_SEE_UNDERWATER_PEDS, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedBeast, CA_DISABLE_FLEE_FROM_COMBAT, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_DontActivateRagdollFromFire, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_DontActivateRagdollFromBulletImpact, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_DontActivateRagdollFromExplosions, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_ShouldChargeNow, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_ShoutToGroupOnPlayerMelee, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_IgnoreMeleeFistWeaponDamageMult, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_AllowMeleeReactionIfMeleeProofIsOn, FALSE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_DisableExplosionReactions, TRUE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_RunFromFiresAndExplosions, FALSE)
SET_ENTITY_PROOFS(sBeastFinaleVars.pedBeast, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sBeastFinaleVars.pedBeast, TRUE)
ELSE
SET_ENTITY_PROOFS(sBeastFinaleVars.pedBeast, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
SET_PED_CAN_BE_TARGETTED(sBeastFinaleVars.pedBeast, FALSE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sBeastFinaleVars.pedBeast, TRUE)
SET_PED_CAN_RAGDOLL(sBeastFinaleVars.pedBeast, FALSE)
SET_PED_CONFIG_FLAG(sBeastFinaleVars.pedBeast, PCF_DisableExplosionReactions,TRUE)
sBeastFinaleVars.iSyncScene = CREATE_SYNCHRONIZED_SCENE(vPosition, << 0.000, 0.000, fHeading >>)
SET_SYNCHRONIZED_SCENE_LOOPED(sBeastFinaleVars.iSyncScene, TRUE)
TEXT_LABEL_23 tlAnim = Build_Beast_String_23("DL", "I", "A", "E_") //"IDLE_A"
TASK_SYNCHRONIZED_SCENE (sBeastFinaleVars.pedBeast, sBeastFinaleVars.iSyncScene, sBeastFinaleVars.sKneelingAnim, tlAnim, INSTANT_BLEND_IN, INSTANT_BLEND_OUT )
ENDIF
SET_BIT(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
ENDPROC
PROC Play_Beast_Sound_From_Position(VECTOR vPosition)
CPRINTLN(DEBUG_HUNTING, "Playing beast sound at position ", vPosition, ".")
sBeastFinaleVars.iSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_COORD(sBeastFinaleVars.iSoundId, sBeastFinaleVars.sBeastCalls, vPosition, sBeastFinaleVars.sFMEvents)
ENDPROC
PROC Destroy_Player_Vehicle()
VEHICLE_INDEX vehLast = GET_LAST_DRIVEN_VEHICLE()
sBeastFinaleVars.iState = sBeastFinaleVars.iState //Unreferenced variable fix
IF DOES_ENTITY_EXIST(vehLast)
IF NOT IS_ENTITY_DEAD(vehLast)
MODEL_NAMES mVehicle = GET_ENTITY_MODEL(vehLast)
CPRINTLN(debug_hunting, "Found last vehicle: ",GET_MODEL_NAME_FOR_DEBUG(mVehicle))
IF NOT (IS_THIS_MODEL_A_BICYCLE(mVehicle))
IF IS_ENTITY_AT_COORD(vehLast, g_vBeastFinaleArenaPos, g_vBeastFinaleArenaSize)
CPRINTLN(debug_hunting, "Last vehicle in range")
//Destroy vehicle
SET_ENTITY_HEALTH(vehLast, 0)
ADD_EXPLOSION(GET_ENTITY_COORDS(vehLast, false),EXP_TAG_STICKYBOMB)
// SET_VEHICLE_TIMED_EXPLOSION(vehLast, PLAYER_PED_ID(),0)
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
//===============Beast fighting section
CONST_INT HIT_TIME 2500
CONST_INT MAX_HITS 5
PROC Maintain_Player_Hit_Combo(PED_INDEX beast, INT &iTimer, INT &iHitCount, BOOL bCheat = FALSE)
//Check if a new hit took place
IF DOES_ENTITY_EXIST(beast) AND NOT IS_ENTITY_DEAD(beast) AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(beast, PLAYER_PED_ID())
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(beast, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE)
iHitCount = IMIN(MAX_HITS, iHitCount+1)
iTimer = GET_GAME_TIMER() + HIT_TIME
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(beast)
CLEAR_ENTITY_LAST_WEAPON_DAMAGE(beast)
IF bCheat
SET_ENTITY_HEALTH(beast, 100000) //Reset the beast health if cheating
ENDIF
ENDIF
ENDIF
//Check if we need to reduce the hit counter
IF GET_GAME_TIMER() > iTimer AND iHitCount > 0
iHitCount--
iTimer = GET_GAME_TIMER() + HIT_TIME
ENDIF
//Draw combo counter
#IF IS_DEBUG_BUILD
IF iHitCount > 0
TEXT_LABEL_23 msg = "Hits:"
msg += iHitCount
msg += " Time:"
msg += (iTimer - GET_GAME_TIMER())
Beast_Display_Onscreen_Text(0.5,0.9,msg, 0.3)
ENDIF
#ENDIF
ENDPROC
PROC Knock_Player_Weapon()
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
WEAPON_TYPE currentWeapon
GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(),currentWeapon,FALSE)
IF currentWeapon != WEAPONTYPE_UNARMED
//Remove the weapon
OBJECT_INDEX weaponObj = GET_WEAPON_OBJECT_FROM_PED(PLAYER_PED_ID(),FALSE)
weaponObj = weaponObj
REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(),currentWeapon)
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED,TRUE)
ENDIF
ENDIF
ENDPROC
PROC Stun_Player_On_Shout(FLOAT fMaxRange = 3.0, BOOL bCheating = FALSE)
VECTOR vUpForce = <<0,0,0.5>>
IF bCheating //Increase stun range if cheating
fMaxRange = 10
vUpForce = <<0,0,8>>
ENDIF
IF NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast) AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
AND GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast),FALSE) < fMaxRange //Check the max range
IF NOT IS_PED_RAGDOLL(PLAYER_PED_ID())
//Set the player to ragdoll
SET_PED_TO_RAGDOLL(PLAYER_PED_ID(), 2000, 6000, TASK_NM_BALANCE, FALSE)
Knock_Player_Weapon()
ENDIF
VECTOR vForce = NORMALISE_VECTOR(GET_ENTITY_COORDS(PLAYER_PED_ID()) - GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast)) * (sBeastFinaleVars.fPushForce / 5) //Local multiplier
CPRINTLN(debug_hunting,"Applying force of power ",vForce)
APPLY_FORCE_TO_ENTITY(PLAYER_PED_ID(), APPLY_TYPE_IMPULSE, vForce + vUpForce, <<0,0,0.5>>, 0, FALSE, TRUE, TRUE)
IF (bCheating) //Also drop health if cheating
SET_ENTITY_HEALTH(PLAYER_PED_ID(), IMAX(GET_ENTITY_HEALTH(PLAYER_PED_ID())/2 - 300, 0))
ENDIF
// Beast_Display_Onscreen_Text(0.5, 0.6, "Applying force")
ENDIF
ENDPROC
FUNC BOOL Should_Beast_Counter_Hit()
IF sBeastFinaleVars.iHitCount = MAX_HITS //If we're at max hits
OR (NOT IS_PED_DEAD_OR_DYING(PLAYER_PED_ID())
AND IS_PED_ARMED(PLAYER_PED_ID(), WF_INCLUDE_MELEE)) //If we're using a melee weapon
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC Update_Beast()
//Local vars
VECTOR vBeastStartLoc = g_vBeastFinaleStartPoint
VECTOR vJumpOffPlanePoint = g_vBeastFinaleJumpOffPoint
SCRIPTTASKSTATUS status
BOOL bCheating = FALSE
INT i, iNumCars
VEHICLE_INDEX vehNearCars[10]
FLOAT fHeading
SEQUENCE_INDEX si
#IF IS_DEBUG_BUILD TEXT_LABEL_23 tl #ENDIF
IF IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
CERRORLN(debug_hunting, "Can't update beast, entity dead")
EXIT
ENDIF
// DISPLAY_RADAR(TRUE)
//Constant updates
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_InfiniteStamina, TRUE)
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_PreventAllMeleeTakedowns, TRUE)
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_IgnoreCombatManager, TRUE)
SET_PED_MOVE_RATE_OVERRIDE(sBeastFinaleVars.pedBeast, 1.75)
//Fail check
IF sBeastFinaleVars.eBeastFightingState != BFS_Run_Away
AND NOT (IS_ENTITY_DEAD(PLAYER_PED_ID()) OR IS_ENTITY_AT_COORD(PLAYER_PED_ID(), g_vBeastFinaleArenaPos,g_vBeastFinaleArenaSize))
VECTOR vPos = GET_ENTITY_COORDS(PLAYER_PED_ID(), false)
CPRINTLN(debug_hunting, "Player at ",vpos," not at ",g_vBeastFinaleArenaPos," / ",g_vBeastFinaleArenaSize)
Set_Beast_State(BFS_Run_Away)
ENDIF
//Check if player is cheating/modding
bCheating = Maintain_Beast_Cheating_Check()
//Check if beast has just punched the player
Maintain_Apply_Beast_Punches_To_Ped(PLAYER_PED_ID(), sBeastFinaleVars.pedBeast,DEFAULT,sBeastFinaleVars.fPushForce,
500+300*sBeastFinaleVars.iHitCount) //Scaling damage with hit count
Maintain_Player_Hit_Combo(sBeastFinaleVars.pedBeast, sBeastFinaleVars.iTimerHit, sBeastFinaleVars.iHitCount)
//Apply constant countering
IF Should_Beast_Counter_Hit()
OR bCheating
//Uncomment this to get the counter working
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_ForceMeleeCounter, TRUE)
CPRINTLN(debug_hunting, "Either max hit combo or player armed with melee, countering")
ENDIF
//Pinned under car check
BOOL bUnderCar = FALSE
IF IS_PED_RAGDOLL(sBeastFinaleVars.pedBeast)
iNumCars = GET_PED_NEARBY_VEHICLES(sBeastFinaleVars.pedBeast, vehNearCars)
FOR i = 0 to iNumCars - 1
IF NOT IS_ENTITY_DEAD(vehNearCars[i])
IF IS_ENTITY_TOUCHING_ENTITY(sBeastFinaleVars.pedBeast, vehNearCars[i])
//AND GET_ENTITY_HEIGHT_ABOVE_GROUND(sBeastFinaleVars.pedBeast) < GET_ENTITY_HEIGHT_ABOVE_GROUND(vehNearCars[i])
//Beast_Display_Onscreen_Text(0.8,0.8, "Under Car", 0.3)
bUnderCar = TRUE
IF sBeastFinaleVars.iUnderCarTime + BF_STUCK_UNDER_CAR_TIME < GET_GAME_TIMER()
//Apply force to car
VECTOR vForce = NORMALISE_VECTOR(GET_ENTITY_COORDS(vehNearCars[i]) - GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast))
vForce = vForce * sBeastFinaleVars.fPushForce
APPLY_FORCE_TO_ENTITY(vehNearCars[i], APPLY_TYPE_IMPULSE, vForce, <<0,0,0>>, 0, FALSE, TRUE, TRUE)
CPRINTLN(debug_hunting,"Applied force on car!")
ENDIF
ENDIF
ENDIF
ENDFOR
ENDIF
IF NOT bUnderCar sBeastFinaleVars.iUnderCarTime = GET_GAME_TIMER() ENDIF
SWITCH sBeastFinaleVars.eBeastFightingState
CASE BFS_Intro
//Check if player looking at beast, trigger anim
IF sBeastFinaleVars.iProg = 0
AND IS_SPHERE_VISIBLE(vBeastStartLoc, 1.0)
AND NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
//Draw attention, activate fight
SET_GAMEPLAY_ENTITY_HINT(sBeastFinaleVars.pedBeast,<<0,0,0>>,DEFAULT, 1000,1000)
TASK_PLAY_ANIM(sBeastFinaleVars.pedBeast, sBeastFinaleVars.sTransformAnimDict //"ANIM@MP_FM_EVENT@INTRO"
,sBeastFinaleVars.sTransformAnim, INSTANT_BLEND_IN, NORMAL_BLEND_OUT,DEFAULT,DEFAULT,0.2) //"BEAST_TRANSFORM"
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
Play_Beast_Sound_From_Position(GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast))
SET_BIT(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
ENDIF
Destroy_Player_Vehicle()
sBeastFinaleVars.iProg++
ELIF sBeastFinaleVars.iProg = 1
//Jump off plane
IF NOT IS_ENTITY_PLAYING_ANIM(sBeastFinaleVars.pedBeast, sBeastFinaleVars.sTransformAnimDict, sBeastFinaleVars.sTransformAnim)
OPEN_SEQUENCE_TASK(si)
TASK_ACHIEVE_HEADING(NULL, GET_HEADING_BETWEEN_VECTORS_2D(g_vBeastFinaleStartPoint, vJumpOffPlanePoint) -20)
TASK_JUMP(NULL, TRUE, TRUE)
CLOSE_SEQUENCE_TASK(si)
TASK_PERFORM_SEQUENCE(sBeastFinaleVars.pedBeast, si)
CLEAR_SEQUENCE_TASK(si)
Set_Beast_State(BFS_Approach_Player)
ENDIF
ENDIF
BREAK
CASE BFS_Approach_Player
IF GET_SCRIPT_TASK_STATUS(sBeastFinaleVars.pedBeast,SCRIPT_TASK_PERFORM_SEQUENCE) > PERFORMING_TASK
OR VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast)) < 4 //2x2
Set_Beast_State(BFS_Attack_Player, GET_RANDOM_INT_IN_RANGE(8,15)*1000)
ENDIF
BREAK
CASE BFS_Attack_Player
//Check if beast lost the combat ped task
status = GET_SCRIPT_TASK_STATUS(sBeastFinaleVars.pedBeast, SCRIPT_TASK_COMBAT)
IF status != PERFORMING_TASK AND status != WAITING_TO_START_TASK
AND GET_GAME_TIMER() > sBeastFinaleVars.iTimer2 + 500 //Don't constantly re-task
CPRINTLN(debug_hunting,"Tasking beast to combat player, was ",status)
CLEAR_PED_TASKS(sBeastFinaleVars.pedBeast)
TASK_COMBAT_PED(sBeastFinaleVars.pedBeast, PLAYER_PED_ID())
sBeastFinaleVars.iTimer2 = GET_GAME_TIMER()
ENDIF
//Check if beast should wait for the player to get up
IF IS_PED_RAGDOLL(PLAYER_PED_ID())
Knock_Player_Weapon()
Set_Beast_State(BFS_Let_Player_Get_Up)
ENDIF
//Check if we should call for backup
IF GET_GAME_TIMER() > sBeastFinaleVars.iTimerStage
Set_Beast_State(BFS_Call_Backup)
ENDIF
BREAK
CASE BFS_Let_Player_Get_Up
#IF IS_DEBUG_BUILD
IF sBeastFinaleVars.bDebugDrawTriggers
tl = "Get up timer: "
tl += GET_GAME_TIMER() - sBeastFinaleVars.iTimer2
Beast_Display_Onscreen_Text(0.4,0.5,tl, 0.3)
ENDIF
#ENDIF
IF sBeastFinaleVars.iProg = 0
CLEAR_PED_TASKS(sBeastFinaleVars.pedBeast)
i = GET_RANDOM_INT_IN_RANGE(0,BF_NUM_TAUNT_ANIMS)
fHeading = GET_HEADING_BETWEEN_VECTORS_2D(GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast, false), GET_ENTITY_COORDS(PLAYER_PED_ID(), false))
OPEN_SEQUENCE_TASK(si)
TASK_ACHIEVE_HEADING(null,fHeading)
TASK_PLAY_ANIM(null,sBeastFinaleVars.sTauntAnimDicts[i],sBeastFinaleVars.sTauntAnims[i])
CLOSE_SEQUENCE_TASK(si)
TASK_PERFORM_SEQUENCE(sBeastFinaleVars.pedBeast, si)
CLEAR_SEQUENCE_TASK(si)
sBeastFinaleVars.iTimer2 = GET_GAME_TIMER() + 4000
sBeastFinaleVars.iProg++
ELIF sBeastFinaleVars.iProg = 1
status = GET_SCRIPT_TASK_STATUS(sBeastFinaleVars.pedBeast, SCRIPT_TASK_PLAY_ANIM)
IF NOT IS_PED_RAGDOLL(PLAYER_PED_ID())
AND NOT IS_PED_GETTING_UP(PLAYER_PED_ID())
CLEAR_PED_TASKS(sBeastFinaleVars.pedBeast)
Set_Beast_State(BFS_Attack_Player, GET_RANDOM_INT_IN_RANGE(7,15)*1000)
ELIF GET_GAME_TIMER() > sBeastFinaleVars.iTimer2
sBeastFinaleVars.iProg = 0
ENDIF
ENDIF
BREAK
CASE BFS_Call_Backup
IF sBeastFinaleVars.iProg = 0
//Start the anim, set ped melee-proof
SET_ENTITY_PROOFS(sBeastFinaleVars.pedBeast, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
TASK_PLAY_ANIM(sBeastFinaleVars.pedBeast, sBeastFinaleVars.sTransformAnimDict, sBeastFinaleVars.sTransformAnim , NORMAL_BLEND_IN, NORMAL_BLEND_OUT,
DEFAULT,DEFAULT,0.3)
sBeastFinaleVars.iProg++
ELIF sBeastFinaleVars.iProg = 1
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_DisableMeleeHitReactions, TRUE)
IF GET_SCRIPT_TASK_STATUS(sBeastFinaleVars.pedBeast,SCRIPT_TASK_PLAY_ANIM) = PERFORMING_TASK
//Play beast sound when he's actually animating
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
Play_Beast_Sound_From_Position(GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast))
Stun_Player_On_Shout(3, bCheating) //Push player away
SET_BIT(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
sBeastFinaleVars.iProg++
ENDIF
ENDIF
ELIF sBeastFinaleVars.iProg = 2
IF GET_SCRIPT_TASK_STATUS(sBeastFinaleVars.pedBeast,SCRIPT_TASK_PLAY_ANIM) > PERFORMING_TASK
//Reset beast proofs
SET_ENTITY_PROOFS(sBeastFinaleVars.pedBeast, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE)
sBeastFinaleVars.iTimer = 0
Set_Beast_State(BFS_Attack_Player, GET_RANDOM_INT_IN_RANGE(7,15)*1000)
ENDIF
ENDIF
BREAK
CASE BFS_Run_Away
IF sBeastFinaleVars.iProg = 0
//Set the beast to run away from the player
CPRINTLN(debug_hunting,"Player outside of combat arena, running away")
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
TASK_SMART_FLEE_PED(sBeastFinaleVars.pedBeast, PLAYER_PED_ID(), 200, -1)
ENDIF
sBeastFinaleVars.iProg++
ELIF sBeastFinaleVars.iProg = 1
IF IS_ENTITY_OCCLUDED(sBeastFinaleVars.pedBeast)
CPRINTLN(debug_hunting,"Fleeing beast not visible, deleting ped")
Fail_Beast_Fight()
sBeastFinaleVars.iProg++
ENDIF
ENDIF
BREAK
ENDSWITCH
ENDPROC
PROC Update_Beast_Animal_Friends()
INT iAnimalIndex
REPEAT BF_MAX_ANIMALS_TO_SPAWN iAnimalIndex
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedAnimals[iAnimalIndex])
IF NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedAnimals[iAnimalIndex])
SET_PED_RESET_FLAG(sBeastFinaleVars.pedAnimals[iAnimalIndex], PRF_IgnoreCombatManager, TRUE)
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC Spawn_Beast_Animal_Friend()
//Pick model.
MODEL_NAMES eAnimalModel
IF GET_RANDOM_INT_IN_RANGE(0,100) < 10 //10% chance of mountain lion
eAnimalModel = Get_Beast_Hint_Model_A(BHT_LION)
ELSE
eAnimalModel = Get_Rottweiler_Model()
ENDIF
//Pick spawn point.
INT iSpawnPoint = GET_RANDOM_INT_IN_RANGE(0, BF_ANIMAL_SPAWN_POINT_COUNT)
WHILE NOT WOULD_ENTITY_BE_OCCLUDED(eAnimalModel, g_vBeastFinaleAnimalSpawnVec[iSpawnPoint])
iSpawnPoint = GET_RANDOM_INT_IN_RANGE(0, BF_ANIMAL_SPAWN_POINT_COUNT)
ENDWHILE
CPRINTLN(DEBUG_HUNTING, "Spawning Beast animal friend. Spawn:", iSpawnPoint, " Model:", PICK_STRING(eAnimalModel = A_C_MTLION, "MTLION", "ROTTWEILER"), ".")
INT iAnimalIndex
REPEAT BF_MAX_ANIMALS_TO_SPAWN iAnimalIndex
IF NOT DOES_ENTITY_EXIST(sBeastFinaleVars.pedAnimals[iAnimalIndex])
sBeastFinaleVars.pedAnimals[iAnimalIndex] = CREATE_PED( PEDTYPE_SPECIAL,
eAnimalModel,
g_vBeastFinaleAnimalSpawnVec[iSpawnPoint],
g_vBeastFinaleAnimalSpawnHead[iSpawnPoint],
FALSE, FALSE)
SET_PED_RELATIONSHIP_GROUP_HASH(sBeastFinaleVars.pedAnimals[iAnimalIndex], sBeastFinaleVars.relGroupHashBeast)
SET_COMBAT_FLOAT(sBeastFinaleVars.pedAnimals[iAnimalIndex], CCF_FIGHT_PROFICIENCY, 1.0)
SET_PED_COMBAT_ABILITY(sBeastFinaleVars.pedAnimals[iAnimalIndex], CAL_PROFESSIONAL)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_DISABLE_PIN_DOWN_OTHERS, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_AGGRESSIVE, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_ALWAYS_FIGHT, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_PERFECT_ACCURACY, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_MAINTAIN_MIN_DISTANCE_TO_TARGET, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_CAN_FIGHT_ARMED_PEDS_WHEN_NOT_ARMED, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_CAN_CHARGE, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_CAN_SEE_UNDERWATER_PEDS, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_DISABLE_FLEE_FROM_COMBAT, TRUE)
SET_PED_COMBAT_ATTRIBUTES(sBeastFinaleVars.pedAnimals[iAnimalIndex], CA_DISABLE_SEEK_DUE_TO_LINE_OF_SIGHT, FALSE)
OPEN_SEQUENCE_TASK(sBeastFinaleVars.seqAnimalAttack[iAnimalIndex])
TASK_GO_TO_ENTITY(NULL, PLAYER_PED_ID(), -1, 4.0)
TASK_COMBAT_PED(NULL, PLAYER_PED_ID())
CLOSE_SEQUENCE_TASK(sBeastFinaleVars.seqAnimalAttack[iAnimalIndex])
TASK_PERFORM_SEQUENCE(sBeastFinaleVars.pedAnimals[iAnimalIndex], sBeastFinaleVars.seqAnimalAttack[iAnimalIndex])
CLEAR_SEQUENCE_TASK(sBeastFinaleVars.seqAnimalAttack[iAnimalIndex])
EXIT
ENDIF
ENDREPEAT
ENDPROC
PROC Destroy_Beast()
CPRINTLN(DEBUG_HUNTING, "Destroying beast.")
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
sBeastFinaleVars.iSyncScene = -1
IF NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
CLEAR_PED_TASKS(sBeastFinaleVars.pedBeast)
ENDIF
DELETE_PED(sBeastFinaleVars.pedBeast)
ENDIF
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
ENDPROC
FUNC BOOL Is_Beast_Fight_Allowed_To_Run()
RETURN IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
AND NOT IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_FIGHT_FAILED)
AND NOT IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
AND GET_PLAYER_MODEL() = Get_Sasquatch_Model()
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_DIRECTOR) //No Director Mode fight
ENDFUNC
PROC Maintain_Beast_Hidden_Trigger()
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
//Player inside streaming range.
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBeastFinaleRootPosition) < BF_STREAM_IN_RANGE_SQR
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
Request_Beast_Finale_Assets()
ELIF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
IF Have_Beast_Finale_Assets_Loaded()
Create_Beast(g_vBeastFinaleRootPosition - <<0.1, -0.1, -1>>, -20.400, FALSE)
//Preload fight music.
PREPARE_MUSIC_EVENT(sBeastFinaleVars.sFightMusic)
ENDIF
//Beast created in world.
ELSE
//Apply beast per-frame flags
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
IF NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
SET_PED_RESET_FLAG(sBeastFinaleVars.pedBeast, PRF_DisablePotentialBlastReactions, TRUE)
ENDIF
ENDIF
//Make the beast leave if the player gets too close.
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_WAITING)
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBeastFinaleRootPosition) < BF_LEAVE_TIMER_RANGE_SQR
CPRINTLN(DEBUG_HUNTING, "Player triggered wait timer.")
sBeastFinaleVars.iTimer = GET_GAME_TIMER() + BF_VISIBLE_TIME
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_WAITING)
ENDIF
ELSE
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_LEAVING)
IF GET_GAME_TIMER() > sBeastFinaleVars.iTimer
OR IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_INJURED)
CPRINTLN(DEBUG_HUNTING, "Beast started leaving.")
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_INJURED)
Play_Beast_Sound_From_Position( GET_ENTITY_COORDS(sBeastFinaleVars.pedBeast, FALSE))
SET_BIT(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
ENDIF
sBeastFinaleVars.iTimer = GET_GAME_TIMER() + BF_BUSH_SLIDE_TIME
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_LEAVING)
ENDIF
ELSE
IF sBeastFinaleVars.iSyncScene != -1
TASK_PLAY_ANIM(sBeastFinaleVars.pedBeast, sBeastFinaleVars.sTauntAnimDicts[3], sBeastFinaleVars.sTauntAnims[3],
INSTANT_BLEND_IN,INSTANT_BLEND_OUT,-1, AF_DEFAULT,0.2)
sBeastFinaleVars.iSyncScene = -1
ENDIF
IF GET_GAME_TIMER() > sBeastFinaleVars.iTimer
CPRINTLN(DEBUG_HUNTING, "Beast sliding into the bush.")
Destroy_Beast()
//Release_Beast_Finale_Assets(iState)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_WINDOW_PASSED)
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_INJURED)
CPRINTLN(DEBUG_HUNTING, "The player injured the beast. Waiting for player to investigate...")
//Set up some ambience: Weather, time-of-day, music.
TEXT_LABEL_23 tlWeather = Build_Beast_String_23("HUN", "T", "R", "DE") //"THUNDER"
SET_WEATHER_TYPE_OVERTIME_PERSIST(tlWeather, 15.0)
PAUSE_CLOCK(TRUE)
TRIGGER_MUSIC_EVENT(sBeastFinaleVars.sFightMusic)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_FIGHT_ACTIVE)
//Disable wanted levels and active police
CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID())
sBeastFinaleVars.iStartWantedLevel = GET_MAX_WANTED_LEVEL()
SET_MAX_WANTED_LEVEL(0)
ELSE
CPRINTLN(DEBUG_HUNTING, "The player missed the beast. Event over.")
Fail_Beast_Fight()
ENDIF
EXIT
ENDIF
ENDIF
ENDIF
//Pass the event if the player injures the beast.
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sBeastFinaleVars.pedBeast, PLAYER_PED_ID())
OR IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE,g_vBeastFinaleRootPosition, 5)
OR VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBeastFinaleRootPosition) < 25 //5*5
CPRINTLN(DEBUG_HUNTING, "Beast damage/proximity detected.")
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_INJURED)
ENDIF
ENDIF
ENDIF
//Player outside streaming range.
ELIF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBeastFinaleRootPosition) > BF_STREAM_OUT_RANGE_SQR
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
Destroy_Beast()
ENDIF
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
Release_Beast_Finale_Assets()
ENDIF
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_LEAVING)
ENDIF
ENDIF
ENDPROC
PROC Update_Beast_Fight_Time()
IF GET_TIMEOFDAY_HOUR(g_todCurrent) != 4 //Force fight to take place around 4:45am
OR GET_TIMEOFDAY_MINUTE(g_todCurrent) < 40
OR GET_TIMEOFDAY_MINUTE(g_todCurrent) > 50
TIMEOFDAY todFight = g_todCurrent
ADD_TIME_TO_TIMEOFDAY(todFight, 0, 2) //Fast forward time by 1 min per frame.
SET_CLOCK_TIME(GET_TIMEOFDAY_HOUR(todFight), GET_TIMEOFDAY_MINUTE(todFight), GET_TIMEOFDAY_SECOND(todFight))
SET_CLOCK_DATE(GET_TIMEOFDAY_DAY(todFight), GET_TIMEOFDAY_MONTH(todFight), GET_TIMEOFDAY_YEAR(todFight))
ENDIF
ENDPROC
PROC Maintain_Beast_Fight()
Update_Beast_Fight_Time()
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
sBeastFinaleVars.iDeadFrames = 0
//Wait for player to go and check The Beast's coords.
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), g_vBeastFinaleCheckPos,<<3.00000,3.00000,2.000000>>)
AND IS_SPHERE_VISIBLE(g_vBeastFinaleRootPosition - <<0.3, 1, -1>>,0.5)
CPRINTLN(DEBUG_HUNTING, "Player went to investigate. Spwaning beast fight.")
Create_Beast(g_vBeastFinaleStartPoint, -155, TRUE)
Set_Beast_State(BFS_Intro)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
sBeastFinaleVars.iTimer = -1//GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(4000, 20000) //No longer spawns companion by default
SET_BIT(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
ENDIF
//Check if player buggered off after damagint the beast
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBeastFinaleRootPosition) > BF_STREAM_OUT_RANGE_SQR
CPRINTLN(debug_hunting,"Player left area after hurting beast, cancelling")
Cleanup_Beast_Fight()
ENDIF
//Fight running.
ELIF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_DEAD)
Update_Beast()
Update_Beast_Animal_Friends()
IF GET_GAME_TIMER() > sBeastFinaleVars.iTimer
AND sBeastFinaleVars.iTimer > -1
Spawn_Beast_Animal_Friend()
sBeastFinaleVars.iTimer = -1 // GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(8000, 15000)
ENDIF
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
IF IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
CPRINTLN(DEBUG_HUNTING, "The beast was killed. Starting transition out.")
sBeastFinaleVars.iTimer = GET_GAME_TIMER() + 2000
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
TASK_PLAY_ANIM(PLAYER_PED_ID(), sBeastFinaleVars.sTransformAnimDict //"ANIM@MP_FM_EVENT@INTRO"
,sBeastFinaleVars.sTransformAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_DEAD)
ENDIF
ENDIF
ENDIF
ELSE
IF GET_GAME_TIMER() > sBeastFinaleVars.iTimer
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
//Display an unlock message that hints the player towards the Director Mode "WildBeast" character.
CPRINTLN(DEBUG_HUNTING, "Event complete! Display beast unlocked feed message.")
TEXT_LABEL_23 tlFeedImage = Build_Beast_String_23("R_A", "CHA", "G_UP", "CTIN") //"CHAR_ACTING_UP"
TEXT_LABEL_23 tlFeedCharName = Build_Beast_String_23("_FEE", "DI", "AR", "D_CH") //"DI_FEED_CHAR"
TEXT_LABEL_23 tlFeedSubtitle = Build_Beast_String_23("AIR_G", "H", "0", "ROUP_E") //"HAIR_GROUP_E0"
BEGIN_TEXT_COMMAND_THEFEED_POST("")
END_TEXT_COMMAND_THEFEED_POST_MESSAGETEXT_SUBTITLE_LABEL(tlFeedImage, tlFeedImage, FALSE, TEXT_ICON_BLANK, tlFeedCharName, tlFeedSubtitle)
//Hack, tell scripts that the player has died to force the peyote trip to end.
g_bAnimalControllerFakeDeath = TRUE
Cleanup_Beast_Fight()
ENDIF
ENDIF
ELSE
//Dead time buffer: Make sure player dead for a few frames before cancelling the fight
sBeastFinaleVars.iDeadFrames += 1
IF sBeastFinaleVars.iDeadFrames > BF_MAX_DEAD_FRAMES
CPRINTLN(debug_hunting, "Player killed, beast fight failed!")
Fail_Beast_Fight()
EXIT
ENDIF
ENDIF
ENDPROC
PROC Maintain_Beast_Sound()
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
IF HAS_SOUND_FINISHED(sBeastFinaleVars.iSoundID)
STOP_SOUND(sBeastFinaleVars.iSoundID)
RELEASE_SOUND_ID(sBeastFinaleVars.iSoundID)
sBeastFinaleVars.iSoundID = -1
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_SOUND_PLAYING)
ENDIF
ENDIF
ENDPROC
PROC Maintain_Beast_Finale()
IF Has_Beast_Secret_Data_Setup_Finished()
IF NOT IS_BITMASK_SET(g_iBeastSetupInt,BH_Bit_Fight_Init)
CPRINTLN(debug_hunting,"Fight data init now set-up, running the Beast Fight scripts")
SET_BITMASK(g_iBeastSetupInt,BH_Bit_Fight_Init)
ENDIF
ELSE
EXIT //Don't do anything until data setup finishes
ENDIF
IF Is_Beast_Fight_Allowed_To_Run()
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_ALLOWED_TO_RUN_LAST_FRAME)
CPRINTLN(debug_hunting, "Beast Fight finale now allowed to run")
SET_BIT(sBeastFinaleVars.iState, BF_BIT_ALLOWED_TO_RUN_LAST_FRAME)
ENDIF
IF NOT IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_WINDOW_PASSED)
Maintain_Beast_Hidden_Trigger()
ELIF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_BEAST_FIGHT_ACTIVE)
Maintain_Beast_Fight()
ENDIF
//Manage ending the sound if it is playing.
Maintain_Beast_Sound()
//Don't let the player record any of this.
REPLAY_PREVENT_RECORDING_AND_UI_THIS_FRAME()
ELSE
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_ALLOWED_TO_RUN_LAST_FRAME)
CPRINTLN(debug_hunting, "Fight not allowed now, bits: HUNT_COMPLETED:",
IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED),
" FIGHT_FAILED: ",IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_FIGHT_FAILED),
" KILLED_AND_UNLOCKED:", IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED))
//Fail the fight if the beast not defeated
IF NOT IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
Fail_Beast_Fight()
ENDIF
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_ALLOWED_TO_RUN_LAST_FRAME)
ENDIF
ENDIF
ENDPROC
#IF IS_DEBUG_BUILD
PROC Create_Beast_Finale_Widgets(WIDGET_GROUP_ID widgetID)
CPRINTLN(DEBUG_HUNTING, "Creating beast finale widgets from ",GET_THIS_SCRIPT_NAME())
IF widgetID != NULL
SET_CURRENT_WIDGET_GROUP(widgetID)
ENDIF
START_WIDGET_GROUP("Beast Finale")
ADD_WIDGET_BOOL("Warp to location", sBeastFinaleVars.bDebugWarpToLocation)
ADD_WIDGET_BOOL("Set fight ready to trigger", sBeastFinaleVars.bDebugCompleteHunt)
ADD_WIDGET_BOOL("Set Beast low health", sBeastFinaleVars.bDebugSetBeastLowHealth)
ADD_WIDGET_BOOL("Terminate thread", sBeastFinaleVars.bDebugTerminateThread)
ADD_WIDGET_BOOL("Draw triggers", sBeastFinaleVars.bDebugDrawTriggers)
ADD_WIDGET_BOOL("Start fight", sBeastFinaleVars.bDebugBeastDamaged)
ADD_WIDGET_BOOL("Draw animal spawns", sBeastFinaleVars.bDebugDrawAnimalSpawns)
ADD_WIDGET_BOOL("Toggle beast killed", sBeastFinaleVars.bDebugToggleBeastKilled)
ADD_WIDGET_BOOL("Beast killed and unlocked", sBeastFinaleVars.bDebugBeastKilledAndUnlocked)
ADD_WIDGET_FLOAT_SLIDER("Push force", sBeastFinaleVars.fPushForce,1,200,0.5)
STOP_WIDGET_GROUP()
IF widgetID != NULL
CLEAR_CURRENT_WIDGET_GROUP(widgetID)
ENDIF
ENDPROC
PROC Update_Beast_Finale_Widgets(BOOL bAllowTerminate = TRUE)
IF sBeastFinaleVars.bDebugTerminateThread
OR IS_DEBUG_KEY_JUST_PRESSED(KEY_F, KEYBOARD_MODIFIER_CTRL_SHIFT, "Terminate thread") //Also use F to kill
CPRINTLN(DEBUG_HUNTING, "Beast finale thread terminating from widget.")
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
Destroy_Beast()
Cleanup_Beast_Fight()
ENDIF
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
Release_Beast_Finale_Assets()
ENDIF
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_LEAVING)
IF bAllowTerminate
TERMINATE_THIS_THREAD()
ENDIF
ENDIF
IF sBeastFinaleVars.bDebugWarpToLocation
IF IS_PLAYER_PLAYING(PLAYER_ID())
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
CPRINTLN(DEBUG_HUNTING, "Starting warp to beast finale location from widget...")
SET_ENTITY_COORDS(PLAYER_PED_ID(), g_vBeastFinaleCheckPos - <<1, -82, 0>>, FALSE)
SET_ENTITY_HEADING(PLAYER_PED_ID(),176.0174)
// WHILE IS_PLAYER_TELEPORT_ACTIVE()
// WAIT(0)
// ENDWHILE
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
CPRINTLN(DEBUG_HUNTING, "Warp finished.")
ENDIF
sBeastFinaleVars.bDebugWarpToLocation = FALSE
ENDIF
IF sBeastFinaleVars.bDebugSetBeastLowHealth
IF DOES_ENTITY_EXIST(sBeastFinaleVars.pedBeast)
AND NOT IS_ENTITY_DEAD(sBeastFinaleVars.pedBeast)
SET_ENTITY_HEALTH(sBeastFinaleVars.pedBeast, 200)
ENDIF
sBeastFinaleVars.bDebugSetBeastLowHealth = FALSE
ENDIF
IF sBeastFinaleVars.bDebugCompleteHunt
sBeastFinaleVars.bDebugCompleteHunt = FALSE
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_FIGHT_FAILED)
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
ENDIF
IF sBeastFinaleVars.bDebugBeastDamaged
sBeastFinaleVars.bDebugBeastDamaged = FALSE
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_WINDOW_PASSED)
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_INJURED)
SET_BIT(sBeastFinaleVars.iState, BF_BIT_BEAST_FIGHT_ACTIVE)
CLEAR_BIT(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
SET_ENTITY_COORDS(PLAYER_PED_ID(),g_vBeastFinaleCheckPos, FALSE)
ENDIF
IF sBeastFinaleVars.bDebugDrawTriggers
OR sBeastFinaleVars.bDebugDrawAnimalSpawns
IF NOT sBeastFinaleVars.bDebugDrawingEnabled
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
sBeastFinaleVars.bDebugDrawingEnabled = TRUE
ENDIF
ELSE
IF sBeastFinaleVars.bDebugDrawingEnabled
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(FALSE)
sBeastFinaleVars.bDebugDrawingEnabled = FALSE
ENDIF
ENDIF
IF sBeastFinaleVars.bDebugDrawTriggers
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_CREATED_BEAST)
DRAW_DEBUG_SPHERE(g_vBeastFinaleRootPosition, SQRT(BF_LEAVE_TIMER_RANGE_SQR), 0, 0, 255, 60)
ENDIF
IF IS_BIT_SET(sBeastFinaleVars.iState, BF_BIT_REQUESTED_ASSETS)
DRAW_DEBUG_SPHERE(g_vBeastFinaleRootPosition, SQRT(BF_STREAM_OUT_RANGE_SQR), 255, 0, 0, 60)
ELSE
DRAW_DEBUG_SPHERE(g_vBeastFinaleRootPosition, SQRT(BF_STREAM_IN_RANGE_SQR), 0, 255, 0, 60)
ENDIF
ENDIF
IF sBeastFinaleVars.bDebugDrawAnimalSpawns
INT iSpawnIndex
TEXT_LABEL tlSpawnName
REPEAT BF_ANIMAL_SPAWN_POINT_COUNT iSpawnIndex
tlSpawnName = "Spawn "
tlSpawnName += iSpawnIndex
DRAW_DEBUG_TEXT(tlSpawnName, g_vBeastFinaleAnimalSpawnVec[iSpawnIndex], 0, 0, 255)
DRAW_DEBUG_SPHERE(g_vBeastFinaleAnimalSpawnVec[iSpawnIndex], 1.0, 0, 255, 0, 60)
ENDREPEAT
ENDIF
IF sBeastFinaleVars.bDebugToggleBeastKilled
IF IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
CPRINTLN(DEBUG_HUNTING, "Clearing beast as killed through widget.")
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
ELSE
CPRINTLN(DEBUG_HUNTING, "Setting beast as killed through widget.")
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
ENDIF
sBeastFinaleVars.bDebugToggleBeastKilled = FALSE
ENDIF
sBeastFinaleVars.bDebugBeastKilledAndUnlocked = IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_KILLED_AND_UNLOCKED)
ENDPROC
#ENDIF //DEBUG
#ENDIF //FEATURE_SP_DLC_BEAST_SECRET