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

1335 lines
51 KiB
XML
Executable File

USING "globals.sch"
USING "rage_builtins.sch"
USING "commands_water.sch"
USING "commands_player.sch"
USING "script_debug.sch"
USING "script_clock.sch"
USING "net_include.sch"
USING "script_conversion.sch"
USING "candidate_public.sch"
USING "beast_secret_shared.sch"
#IF FEATURE_SP_DLC_BEAST_SECRET
//╒═════════════════════════════════════════════════════════════════════════════╕
//╞════════════════════════════ The Beast Hunt ═════════════════════════╡
//╘═════════════════════════════════════════════════════════════════════════════╛
CONST_INT BH_BIT_BEAST_SOUND_PLAYING 1
CONST_INT BH_BIT_HINT_LOADED 2
CONST_INT BH_BIT_HUNTER_SEEN 3
CONST_INT BH_BIT_CHECKPOINT_ITEM_TRIGGERED 4
CONST_INT BH_BIT_IGNORE_1ST_NODE 5
//This was saved to point to g_savedGlobals.sFlowCustom.spInitBitset
CONST_INT BH_BITSHIFT_CURRENT_CHECKPOINT 14
CONST_INT BH_BITMASK_CURRENT_CHECKPOINT (BIT14|BIT15|BIT16|BIT17)
CONST_INT BH_BITSHIFT_NEXT_CHECKPOINT 18
CONST_INT BH_BITMASK_NEXT_CHECKPOINT (BIT18|BIT19|BIT20|BIT21)
CONST_INT BH_BITSHIFT_CURRENT_PATH_NODE 17
CONST_INT BH_BITMASK_CURRENT_PATH_NODE (BIT17|BIT18|BIT19|BIT20|BIT21|BIT22|BIT23|BIT24)
CONST_FLOAT BH_CHECKPOINT_HINT_RADIUS 200.0
CONST_FLOAT BH_CHECKPOINT_RADIUS 35.0
CONST_FLOAT BH_PATH_NODE_RADIUS 17.0
CONST_FLOAT BH_ITEM_COLLECT_RADIUS 5.
CONST_INT BH_SOUND_MIN_DELAY 4000
CONST_INT BH_SOUND_RANDOM_DELAY 4000
CONST_FLOAT BH_SOUND_DIST_FROM_PLAYER 60.0
CONST_FLOAT BH_SOUND_MIN_DIST_FROM_PLAYER 30.0
CONST_FLOAT BH_SOUND_MAX_RANGE_SQR 9000000.0
CONST_INT BH_RESET_TIME_DELAY 30000 //Time until the beast hunt becomes active again after failing the fight
STRUCT BeastHuntVars
INT iState
INT iHintTrackedPoint
INT iFadeOutTimer
BOOL bCouldRunLastFrame
BOOL bWasSasLastFrame
FLOAT fCurrentMaxRadius //Max range before resetting the current path progress
INT iNumPaths //Index for maximum paths currently stored
INT iBeastSoundID = -1, iNextSoundTime
VECTOR vSoundPos //This is relative
FLOAT fSoundDist
PED_INDEX pedHint
VEHICLE_INDEX vehHint
#IF IS_DEBUG_BUILD
BOOL bDebugWidgetsInitialised = FALSE
BOOL bDebugTerminateThread
BOOL bDebugPeyotesComplete
BOOL bDebugTogglePeyotesComplete
BOOL bDebugHunterSeen
BOOL bDebugToggleHunterSeen
BOOL bDebugHuntComplete
BOOL bDebugToggleHuntComplete
BOOL bDebugDisplayCheckpoints
BOOL bDebugDisplayPaths
BOOL bDebugDisplayActivePath
BOOL bDebugDisplayCurrentPath
BOOL bDebugDrawingEnabled
BOOL bWarpAndDisplay
BOOL bDebugSetCurrentPath
BOOL bSpreadPathNodes
BOOL bPrintPathInformation
BOOL bDebugDirectPath
#ENDIF
ENDSTRUCT
FUNC INT Get_Beast_Hunt_Current_Checkpoint()
INT iValue = Get_Int_From_Bitset(g_savedGlobals.sFlowCustom.spInitBitset, BH_BITMASK_CURRENT_CHECKPOINT, BH_BITSHIFT_CURRENT_CHECKPOINT)
// CDEBUG2LN(DEBUG_HUNTING, "Read beast hunt current checkpoint as ", iValue, ".")
RETURN iValue
ENDFUNC
PROC Set_Beast_Hunt_Current_Checkpoint(INT iValue)
CDEBUG2LN(DEBUG_HUNTING, "Set beast hunt current checkpoint to ", iValue, ".")
Set_Int_In_Bitset(g_savedGlobals.sFlowCustom.spInitBitset, iValue, BH_BITMASK_CURRENT_CHECKPOINT, BH_BITSHIFT_CURRENT_CHECKPOINT)
ENDPROC
FUNC INT Get_Beast_Hunt_Next_Checkpoint()
INT iValue = Get_Int_From_Bitset(g_savedGlobals.sFlowCustom.spInitBitset, BH_BITMASK_NEXT_CHECKPOINT, BH_BITSHIFT_NEXT_CHECKPOINT)
// CDEBUG2LN(DEBUG_HUNTING, "Read beast hunt next checkpoint as ", iValue, ".")
RETURN iValue
ENDFUNC
PROC Set_Beast_Hunt_Next_Checkpoint(INT iValue)
CDEBUG2LN(DEBUG_HUNTING, "Set beast hunt next checkpoint to ", iValue, ".")
Set_Int_In_Bitset(g_savedGlobals.sFlowCustom.spInitBitset, iValue, BH_BITMASK_NEXT_CHECKPOINT, BH_BITSHIFT_NEXT_CHECKPOINT)
ENDPROC
FUNC INT Get_Beast_Hunt_Current_Path_Node(INT iState)
INT iValue = SHIFT_RIGHT(iState & BH_BITMASK_CURRENT_PATH_NODE, BH_BITSHIFT_CURRENT_PATH_NODE)
CDEBUG3LN(DEBUG_HUNTING, "Read beast hunt current path node as ", iValue, ".")
RETURN iValue
ENDFUNC
PROC Set_Beast_Hunt_Current_Path_Node(INT &iState, INT iValue)
CDEBUG2LN(DEBUG_HUNTING, "Set beast hunt current path node to ", iValue, ".")
iState -= iState & BH_BITMASK_CURRENT_PATH_NODE
iState |= SHIFT_LEFT(iValue, BH_BITSHIFT_CURRENT_PATH_NODE)
ENDPROC
PROC Add_Beast_Hunt_Path(BeastHuntVars &sBHV, INT iFirstCP, INT iSecondCP, BOOL bIsReversible,
FLOAT x1=0.0, FLOAT y1=0.0, FLOAT z1=0.0,
FLOAT x2=0.0, FLOAT y2=0.0, FLOAT z2=0.0,
FLOAT x3=0.0, FLOAT y3=0.0, FLOAT z3=0.0,
FLOAT x4=0.0, FLOAT y4=0.0, FLOAT z4=0.0,
FLOAT x5=0.0, FLOAT y5=0.0, FLOAT z5=0.0,
FLOAT x6=0.0, FLOAT y6=0.0, FLOAT z6=0.0,
FLOAT x7=0.0, FLOAT y7=0.0, FLOAT z7=0.0,
FLOAT x8=0.0, FLOAT y8=0.0, FLOAT z8=0.0)
IF (sBHV.iNumPaths >= BH_MAX_PATH_COUNT)
CERRORLN(debug_hunting, "Couldn't add path, max number of paths reached: ",sBHV.iNumPaths)
EXIT
ENDIF
IF iFirstCP >= BH_CHECKPOINT_COUNT OR iSecondCp >= BH_CHECKPOINT_COUNT
OR iFirstCP <0 OR iSecondCP <0
CERRORLN(debug_hunting, "Couldn't add path, checkpoint numbers out of range: ",iFirstCP, "/", iSecondCP)
EXIT
ENDIF
g_iBHPathIndexes[iFirstCP][iSecondCP] = sbhv.iNumPaths
g_bBHPathReversed[iFirstCP][iSecondCP] = FALSE
IF bIsReversible
g_bBHPathReversed[iSecondCP][iFirstCP] = TRUE
g_iBHPathIndexes[iSecondCP][iFirstCP] = sbhv.iNumPaths
ELSE
g_bBHPathReversed[iSecondCP][iFirstCP] = FALSE
g_iBHPathIndexes[iSecondCP][iFirstCP] = -1
ENDIF
//Add nodes 1 by 1
INT iPath = 0
IF x1!=0 AND y1!=0 AND z1!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x1,y1,z1>> iPath++ ENDIF
IF x2!=0 AND y2!=0 AND z2!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x2,y2,z2>> iPath++ ENDIF
IF x3!=0 AND y3!=0 AND z3!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x3,y3,z3>> iPath++ ENDIF
IF x4!=0 AND y4!=0 AND z4!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x4,y4,z4>> iPath++ ENDIF
IF x5!=0 AND y5!=0 AND z5!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x5,y5,z5>> iPath++ ENDIF
IF x6!=0 AND y6!=0 AND z6!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x6,y6,z6>> iPath++ ENDIF
IF x7!=0 AND y7!=0 AND z7!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x7,y7,z7>> iPath++ ENDIF
IF x8!=0 AND y8!=0 AND z8!=0 g_sBHPath[sBHV.iNumPaths].vNode[iPath] = <<x8,y8,z8>> iPath++ ENDIF
g_sBHPath[sBHV.iNumPaths].iLength = iPath
CPRINTLN(debug_hunting, "Added path ",sBHV.inumPaths," with ",iPath," nodes")
sBHV.iNumPaths++
ENDPROC
PROC Add_Beast_Hunt_Path_Vec4(BeastHuntVars &sBHV, INT iFirstCP, INT iSecondCP, BOOL bIsReversible,
VECTOR v1, VECTOR v2, VECTOR v3, VECTOR v4)
Add_Beast_Hunt_Path(sBHV, iFirstCP, iSecondCP, bIsReversible, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z, v4.x, v4.y, v4.z)
ENDPROC
PROC Add_Beast_Hunt_Path_Vec3(BeastHuntVars &sBHV, INT iFirstCP, INT iSecondCP, BOOL bIsReversible,
VECTOR v1, VECTOR v2, VECTOR v3)
Add_Beast_Hunt_Path(sBHV, iFirstCP, iSecondCP, bIsReversible, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z)
ENDPROC
PROC Pick_Next_Checkpoint(BeastHuntVars &sBeastHuntVars)
INT iLast = Get_Beast_Hunt_Current_Checkpoint()
INT iJustFound = Get_Beast_Hunt_Next_Checkpoint()
CPRINTLN(DEBUG_HUNTING, "Picking new checkpoint. Last:", iLast, " JustFound:", iJustFound)
INT iNew = iLast
INT iMaxTries = 50
WHILE (iNew = iLast) | (iNew = iJustFound) | (g_iBHPathIndexes[iJustFound][iNew] = -1)
#IF IS_DEBUG_BUILD | ((sBeastHuntVars.bDebugDirectPath AND iNew < iLast AND iMaxTries > 0)) #ENDIF
iNew = GET_RANDOM_INT_IN_RANGE(0, BH_CHECKPOINT_COUNT)
iMaxTries--
ENDWHILE
CPRINTLN(DEBUG_HUNTING, "Updating checkpoints. Current:", iJustFound, " Next:", iNew)
Set_Beast_Hunt_Current_Checkpoint(iJustFound)
Set_Beast_Hunt_Next_Checkpoint(iNew)
ENDPROC
FUNC INT Get_Beast_Hunt_Current_Path_And_Checkpoints(BeastHuntVars &sBeastHuntVars, INT &iCurrent, INT &iNext)
//Debug and sanity check
IF Get_Beast_Hunt_Current_Checkpoint() = Get_Beast_Hunt_Next_Checkpoint()
Pick_Next_Checkpoint(sBeastHuntVars)
ENDIF
iCurrent = Get_Beast_Hunt_Current_Checkpoint()
iNext = Get_Beast_Hunt_Next_Checkpoint()
RETURN g_iBHPathIndexes[iCurrent][iNext]
ENDFUNC
FUNC BOOL Get_Beast_Hunt_Path_Endpoints(BeastHuntVars &sBeastHuntVars, INT iPath, INT& iStart, INT& iEnd)
INT i, j
sBeastHuntVars.iNumPaths = sBeastHuntVars.iNumPaths
REPEAT BH_CHECKPOINT_COUNT i
REPEAT BH_CHECKPOINT_COUNT j
IF i != j
AND g_iBHPathIndexes[i][j] = iPath
IF g_bBHPathReversed[i][j]
iStart = j iEnd = i
ELSE
iStart = i iEnd = j
ENDIF
RETURN TRUE
ENDIF
ENDREPEAT
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL Is_Node_Last_In_Path(BeastHuntVars &sBeastHuntVars, INT iNode)
sBeastHuntVars.iState = sBeastHuntVars.iState //Unreferenced fix
INT iCurCP, iNextCP
INT iPath = Get_Beast_Hunt_Current_Path_And_Checkpoints(sBeastHuntVars, iCurCP, iNextCP)
IF g_bBHPathReversed[iCurCP][iNextCP]
RETURN (iNode = 0)
ELSE
RETURN (iNode = g_sBHPath[iPath].iLength + 1)
ENDIF
ENDFUNC
FUNC BOOL Is_Node_First_In_Path(BeastHuntVars &sBeastHuntVars, INT iNode)
sBeastHuntVars.iState = sBeastHuntVars.iState //Unreferenced fix
INT iCurCP, iNextCP
INT iPath = Get_Beast_Hunt_Current_Path_And_Checkpoints(sBeastHuntVars, iCurCP, iNextCP)
IF NOT g_bBHPathReversed[iCurCP][iNextCP]
RETURN (iNode = 0)
ELSE
RETURN (iNode = g_sBHPath[iPath].iLength + 1)
ENDIF
ENDFUNC
FUNC VECTOR Get_Node_Location(BeastHuntVars &sBeastHuntVars, INT iNode)
INT iCurCP = Get_Beast_Hunt_Current_Checkpoint()
INT iNextCP = Get_Beast_Hunt_Next_Checkpoint()
INT iPath = g_iBHPathIndexes[iCurCP][iNextCP]
VECTOR vRes
IF Is_Node_Last_In_Path(sBeasthuntvars, iNode)
//Next checkpoint
vRes = g_vBHCheckpoints[iNextCP]
ELIF Is_Node_First_In_Path(sBeasthuntvars, iNode)
//First checkpoint
vRes = g_vBHCheckpoints[iCurCP]
ELSE
vRes = g_sBHPath[iPath].vNode[iNode-1]
ENDIF
// CPRINTLN(debug_hunting,"Returning node coord ", vRes)
RETURN vRes
ENDFUNC
FUNC INT Get_Next_Node_In_Path(BeastHuntVars &sBeastHuntVars, int iNode)
INT iCurCP = Get_Beast_Hunt_Current_Checkpoint()
INT iNextCP = Get_Beast_Hunt_Next_Checkpoint()
INT iPath = g_iBHPathIndexes[iCurCP][iNextCP]
iPath = iPath
IF Is_Node_Last_In_Path(sBeastHuntVars, iNode)
CERRORLN(debug_hunting, "Can't advance node ",iNode,", it is last in path", iPath," (",iCurCP,"->",iNextCP,")")
RETURN iNode
ELSE
IF g_bBHPathReversed[iCurCP][iNextCP]
RETURN iNode -1
ELSE
RETURN iNode +1
ENDIF
ENDIF
ENDFUNC
PROC Reset_Node_In_Path(BeastHuntVars &sBeastHuntVars)
INT iCurCP = Get_Beast_Hunt_Current_Checkpoint()
INT iNextCP = Get_Beast_Hunt_Next_Checkpoint()
INT iPath = g_iBHPathIndexes[iCurCP][iNextCP]
INT iNextNode = 0
IF IS_BIT_SET(sBeastHuntVars.iState, BH_BIT_IGNORE_1ST_NODE)
CPRINTLN(debug_hunting,"Ignoring the 1st node in the path")
iNextNode = 1
CLEAR_BIT(sBeastHuntVars.iState, BH_BIT_IGNORE_1ST_NODE)
ENDIF
IF g_bBHPathReversed[iCurCP][iNextCP]
iNextNode = g_sBHPath[iPath].iLength + 1 - iNextNode //This is to exclude the last if we're skipping it
ENDIF
Set_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState, iNextNode)
CPRINTLN(debug_hunting,"Reset node progress to ",Get_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState))
ENDPROC
PROC Reset_Beast_Hunt_Variables(BeastHuntVars &sBeastHuntVars)
CPRINTLN(debug_hunting,"Resetting hunt path data")
CLEAR_BITMASK(g_iBeastSetupInt,BH_Bit_Hunt_Init) //Force recreating the node array
//Reset path matrix
INT i, j
REPEAT BH_CHECKPOINT_COUNT i
REPEAT BH_CHECKPOINT_COUNT j
g_iBHPathIndexes[i][j] = -1
ENDREPEAT
ENDREPEAT
sBeastHuntVars.iState = 0
sBeastHuntVars.iNumPaths = 0
sBeastHuntVars.fCurrentMaxRadius = -1
//<---------------PATH SETUP INFO HERE----------------->
//First node starts as the Sasquatch hunter and becomes a hiker
//on subsequent visits.
g_iBHCheckpointType[0] = BHT_HUNTER
g_iBHCheckpointType[1] = BHT_DEER
g_iBHCheckpointType[2] = BHT_BOAR
g_iBHCheckpointType[3] = BHT_HIKER
g_iBHCheckpointType[4] = BHT_HIKER
g_iBHCheckpointType[5] = BHT_CAR_WRECK
g_iBHCheckpointType[6] = BHT_LION
g_iBHCheckpointType[7] = BHT_DEER
g_iBHCheckpointType[8] = BHT_HIPPIE
g_iBHCheckpointType[9] = BHT_REDNECK
g_iBHCheckpointType[10] = BHT_REDNECK
//Beast Peyote Y Set-up
Set_Beast_Peyote_Vectors_Y()
//Beast Hunt Z Set-up
Set_Beast_Hunt_Vectors_Z()
//Beast Fight Z Set-up
Set_Beast_Fight_Vectors_z()
//Rest of data init continues in Finalise_Data_Init()
ENDPROC
PROC Finalise_Data_Init(BeastHuntVars &sBeastHuntVars)
CPRINTLN(debug_hunting,"Data init complete, creating Beast Hunt path arrays")
//0 From 0 to 1
Add_Beast_Hunt_Path_Vec4(sBeastHuntVars, 0, 1, TRUE, g_vBHNodes[0 ][0], g_vBHNodes[0 ][1], g_vBHNodes[0 ][2], g_vBHNodes[0 ][3])
//1 From 0 to 3
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 0, 3, TRUE, g_vBHNodes[1 ][0], g_vBHNodes[1 ][1], g_vBHNodes[1 ][2])
//2 From 0 to 4
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 0, 4, TRUE, g_vBHNodes[2 ][0], g_vBHNodes[2 ][1], g_vBHNodes[2 ][2])
//3 From 1 to 2
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 1, 2, TRUE, g_vBHNodes[3 ][0], g_vBHNodes[3 ][1], g_vBHNodes[3 ][2])
//4 From 1 to 5
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 1, 5, TRUE, g_vBHNodes[4 ][0], g_vBHNodes[4 ][1], g_vBHNodes[4 ][2])
//5 From 2 to 3
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 2, 3, TRUE, g_vBHNodes[5 ][0], g_vBHNodes[5 ][1], g_vBHNodes[5 ][2])
//6 From 3 to 5
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 3, 5, TRUE, g_vBHNodes[6 ][0], g_vBHNodes[6 ][1], g_vBHNodes[6 ][2])
//7 From 3 to 6
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 3, 6, TRUE, g_vBHNodes[7 ][0], g_vBHNodes[7 ][1], g_vBHNodes[7 ][2])
//8 From 4 to 5
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 4, 5, TRUE, g_vBHNodes[8 ][0], g_vBHNodes[8 ][1], g_vBHNodes[8 ][2])
//9 From 4 to 6
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 4, 6, TRUE, g_vBHNodes[9 ][0], g_vBHNodes[9 ][1], g_vBHNodes[9 ][2])
//10 From 5 to 6
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 5, 6, TRUE, g_vBHNodes[10][0], g_vBHNodes[10][1], g_vBHNodes[10][2])
//11 From 5 to 8
Add_Beast_Hunt_Path_Vec4(sBeastHuntVars, 5, 8, TRUE, g_vBHNodes[11][0], g_vBHNodes[11][1], g_vBHNodes[11][2], g_vBHNodes[11 ][3])
//12 From 6 to 7
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 6, 7, TRUE, g_vBHNodes[12][0], g_vBHNodes[12][1], g_vBHNodes[12][2])
//13 From 6 to 8
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 6, 8, TRUE, g_vBHNodes[13][0], g_vBHNodes[13][1], g_vBHNodes[13][2])
//14 From 7 to 8
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 7, 8, TRUE, g_vBHNodes[14][0], g_vBHNodes[14][1], g_vBHNodes[14][2])
//15 From 7 to 9
Add_Beast_Hunt_Path_Vec4(sBeastHuntVars, 7, 9, TRUE, g_vBHNodes[15][0], g_vBHNodes[15][1], g_vBHNodes[15][2], g_vBHNodes[15 ][3])
//16 From 7 to 10
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 7, 10, TRUE, g_vBHNodes[16][0], g_vBHNodes[16][1], g_vBHNodes[16][2])
//17 From 8 to 9
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 8, 9, TRUE, g_vBHNodes[17][0], g_vBHNodes[17][1], g_vBHNodes[17][2])
//18 From 8 to 10
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 8, 10, TRUE, g_vBHNodes[18][0], g_vBHNodes[18][1], g_vBHNodes[18][2])
//19 From 9 to 10
Add_Beast_Hunt_Path_Vec3(sBeastHuntVars, 9, 10, TRUE, g_vBHNodes[19][0], g_vBHNodes[19][1], g_vBHNodes[19][2])
//<----------------END PATH SETUP INFO---------------->
//Get current and next checkpoint
IF Get_Beast_Hunt_Current_Checkpoint() = Get_Beast_Hunt_Next_Checkpoint()
Pick_Next_Checkpoint(sBeastHuntVars)
ENDIF
// Set_Beast_Hunt_Current_Checkpoint(0)
// Set_Beast_Hunt_Next_Checkpoint(0)
Set_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState, 0) //Don't skip the start point
ENDPROC
PROC Reset_Beast_Sound_Time(BeastHuntVars &sBHV, INT iAddTime = 0)
//Sets the sound to play as soon as possible
sBHV.iNextSoundTime = GET_GAME_TIMER() + iAddTime
ENDPROC
PROC Reset_Max_Node_Range(BeastHuntVars &sBHV, FLOAT fAddedDist = BH_CHECKPOINT_RADIUS, BOOL bKeepOldMin = FALSE)
FLOAT fOld = sBHV.fCurrentMaxRadius
//Recalculate max distance before node reset
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
sBHV.fCurrentMaxRadius = VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()),Get_Node_Location(sBHV, Get_Beast_Hunt_Current_Path_Node(sBHV.iState))) + fAddedDist*2
sBHV.fCurrentMaxRadius = FMAX(sBHV.fCurrentMaxRadius , BH_CHECKPOINT_RADIUS * 3)
sBHV.fCurrentMaxRadius *= sBHV.fCurrentMaxRadius
ENDIF
IF bKeepOldMin
sBHV.fCurrentMaxRadius = FMIN(sBHV.fCurrentMaxRadius, fOld)
ENDIF
CPRINTLN(Debug_hunting, "Max distance to node ",Get_Beast_Hunt_Current_Path_Node(sBHV.iState)," changed from ",fOld," to ",sBHV.fCurrentMaxRadius)
ENDPROC
PROC Release_Checkpoint_Hint_Assets(BeastHuntVars &sBHV, BOOL bDelete = FALSE)
IF DOES_ENTITY_EXIST(sBHV.vehHint)
CDEBUG1LN(DEBUG_HUNTING, "Releasing vehicle entity.")
IF bDelete
DELETE_VEHICLE(sBHV.vehHint)
ELSE
SET_VEHICLE_AS_NO_LONGER_NEEDED(sBHV.vehHint)
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(sBHV.pedHint)
CDEBUG1LN(DEBUG_HUNTING, "Releasing deer entity.")
IF bDelete
DELETE_PED(sBHV.pedHint)
ELSE
SET_PED_AS_NO_LONGER_NEEDED(sBHV.pedHint)
ENDIF
ENDIF
IF IS_BIT_SET(sBHV.iState, BH_BIT_HINT_LOADED)
CDEBUG1LN(DEBUG_HUNTING, "Releasing all hint models.")
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_HUNTER))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_B(BHT_HUNTER))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_HIKER))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_HIPPIE))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_REDNECK))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_DEER))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_LION))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_BOAR))
SET_MODEL_AS_NO_LONGER_NEEDED(Get_Beast_Hint_Model_A(BHT_CAR_WRECK))
CLEAR_BIT(sBHV.iState, BH_BIT_HINT_LOADED)
ENDIF
IF sBHV.iHintTrackedPoint != 0
CPRINTLN(DEBUG_HUNTING, "Destroying tracked point.")
DESTROY_TRACKED_POINT(sBHV.iHintTrackedPoint)
sBHV.iHintTrackedPoint = 0
ENDIF
//Stop audio scene
TEXT_LABEL_31 tlMixer = Build_Beast_String_31("til_P_","Exec_U","xer_Scene","B_Mi") //"Exec_Util_P_B_Mixer_Scene"
IF IS_AUDIO_SCENE_ACTIVE(tlMixer)
CPRINTLN(debug_hunting,"Stopping Beast mixer scene")
STOP_AUDIO_SCENE(tlMixer)
ENDIF
ENDPROC
PROC Manage_Checkpoint_Hint(BeastHuntVars &sBHV, VECTOR vPosition, INT iHintType, BOOL bRemoveExisting = FALSE)
IF iHintType = BHT_HUNTER
IF IS_BIT_SET(sBHV.iState, BH_BIT_HUNTER_SEEN)
iHintType = BHT_HIKER
ENDIF
ENDIF
MODEL_NAMES eHintModelA = Get_Beast_Hint_Model_A(iHintType)
MODEL_NAMES eHintModelB = Get_Beast_Hint_Model_B(iHintType)
VECTOR vHintEntityPosition = <<0,0,0>>
//Manage hint creation.
IF NOT DOES_ENTITY_EXIST(sBHV.pedHint)
AND NOT DOES_ENTITY_EXIST(sBHV.vehHint)
IF NOT IS_BIT_SET(sBHV.iState, BH_BIT_HINT_LOADED)
//Request models.
IF eHintModelA != DUMMY_MODEL_FOR_SCRIPT
REQUEST_MODEL(eHintModelA)
ENDIF
IF eHintModelB != DUMMY_MODEL_FOR_SCRIPT
REQUEST_MODEL(eHintModelB)
ENDIF
SET_BIT(sBHV.iState, BH_BIT_HINT_LOADED)
ELSE
//Check for models loading.
BOOL bLoadedAllModels = TRUE
IF eHintModelA != DUMMY_MODEL_FOR_SCRIPT
IF NOT HAS_MODEL_LOADED(eHintModelA)
bLoadedAllModels = FALSE
ENDIF
ENDIF
IF eHintModelB != DUMMY_MODEL_FOR_SCRIPT
IF NOT HAS_MODEL_LOADED(eHintModelB)
bLoadedAllModels = FALSE
ENDIF
ENDIF
IF bLoadedAllModels
//Create hint.
Create_Beast_Hint_Type(iHintType, sBHV.pedHint, sBHV.vehHint, vPosition)
CLEAR_BIT(sBHV.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
IF sBHV.iHintTrackedPoint != 0
CPRINTLN(DEBUG_HUNTING, "Destroying old tracked point.")
DESTROY_TRACKED_POINT(sBHV.iHintTrackedPoint)
sBHV.iHintTrackedPoint = 0
ENDIF
sBHV.iHintTrackedPoint = CREATE_TRACKED_POINT()
CPRINTLN(DEBUG_HUNTING, "Created tracked point with value ", sBHV.iHintTrackedPoint, ".")
SET_TRACKED_POINT_INFO(sBHV.iHintTrackedPoint, vPosition, GET_MODEL_LENGTH(eHintModelA))
ENDIF
ENDIF
ELSE
IF DOES_ENTITY_EXIST(sBHV.pedHint)
vHintEntityPosition = GET_ENTITY_COORDS(sBHV.pedHint, FALSE)
ELIF DOES_ENTITY_EXIST(sBHV.vehHint)
vHintEntityPosition = GET_ENTITY_COORDS(sBHV.vehHint, FALSE)
ELSE
//This should never get hit
SCRIPT_ASSERT("Manage_Checkpoint_Hint: Neither a ped or vehicle existed for the hint. Failed to query position.")
ENDIF
//Has the entity moved a long way from its original location?
//And is the player sufficiently far away to not see a respawn?
IF bRemoveExisting
IF NOT ARE_VECTORS_ALMOST_EQUAL(vHintEntityPosition, vPosition, 10, TRUE)
AND VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), vHintEntityPosition) > BH_CHECKPOINT_HINT_RADIUS
Release_Checkpoint_Hint_Assets(sBHV)
ENDIF
ENDIF
ENDIF
//Manage hint focus.
IF NOT IS_BIT_SET(sBHV.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
AND NOT Is_White_Faded_Out() //Don't do the hint cam when the white fade out is active
IF sBHV.iHintTrackedPoint != 0
IF VDIST(vPosition, GET_ENTITY_COORDS(PLAYER_PED_ID())) < BH_ITEM_COLLECT_RADIUS
SET_TRACKED_POINT_INFO(sBHV.iHintTrackedPoint ,vHintEntityPosition, GET_MODEL_LENGTH(eHintModelA))
IF IS_TRACKED_POINT_VISIBLE(sBHV.iHintTrackedPoint)
SET_GAMEPLAY_COORD_HINT(vHintEntityPosition)
SET_BIT(sBHV.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
IF iHintType = BHT_HUNTER
CPRINTLN(DEBUG_HUNTING, "Flagging hunter hint as seen. He will spawn as a hiker from now on.")
SET_BIT(sBHV.iState, BH_BIT_HUNTER_SEEN)
ENDIF
Set_Beast_Call_Made(TRUE) //Make sure the hint is heard at least once
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
PROC Manage_Beast_Checkpoint_Hints(BeastHuntVars &sBHV)
INT iCurrentCheckpoint, iNextCheckpoint
Get_Beast_Hunt_Current_Path_And_Checkpoints(sBHV, iCurrentCheckpoint, iNextCheckpoint)
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
VECTOR vPlayerCoords = GET_ENTITY_COORDS(PLAYER_PED_ID())
FLOAT fDistCurrCP = VDIST(vPlayerCoords, g_vBHCheckpoints[iCurrentCheckpoint])
FLOAT fDistNextCP = VDIST(vPlayerCoords, g_vBHCheckpoints[iNextCheckpoint])
IF fDistCurrCP < BH_CHECKPOINT_HINT_RADIUS
AND fDistCurrCP < fDistNextCP
Manage_Checkpoint_Hint(sBHV, g_vBHCheckpoints[iCurrentCheckpoint], g_iBHCheckpointType[iCurrentCheckpoint], TRUE)
ENDIF
IF fDistNextCP < BH_CHECKPOINT_HINT_RADIUS
Manage_Checkpoint_Hint(sBHV, g_vBHCheckpoints[iNextCheckpoint], g_iBHCheckpointType[iNextCheckpoint], TRUE)
ENDIF
IF fDistCurrCP > (BH_CHECKPOINT_HINT_RADIUS + 10)
AND fDistNextCP > (BH_CHECKPOINT_HINT_RADIUS + 10)
Release_Checkpoint_Hint_Assets(sBHV)
ENDIF
ENDIF
ENDPROC
//Checks if the beast call has been made and the sound isn't currently playing
FUNC BOOL Can_Play_Beast_Sound(BeastHuntVars &sBHV)
IF IS_BIT_SET(sBHV.iState, BH_BIT_BEAST_SOUND_PLAYING)
OR NOT Has_Beast_Call_Been_Made(DEFAULT #IF IS_DEBUG_BUILD , sBHV.bDebugDisplayPaths #ENDIF )
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
//Plays the Beast sound when the conditions are met, manages timer for playing the sound
PROC Manage_Beast_Sound(BeastHuntVars &sBHV, VECTOR vNextPos, BOOL bIsHint = FALSE)
//Manage sound
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
//Check beast call default wait
IF Has_Beast_Call_Just_Been_Made()
sbhv.iNextSoundTime = IMAX(sbhv.iNextSoundTime, GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(2000,4000))
CDEBUG1LN(debug_hunting,"Detected beast call - reply in ",sbhv.iNextSoundTime-GET_GAME_TIMER())
ENDIF
//Check if within max range but not within a CP radius
FLOAT fDist = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), vNextPos)
IF fDist < sBHV.fCurrentMaxRadius
AND (fDist > BH_CHECKPOINT_RADIUS * BH_CHECKPOINT_RADIUS OR NOT bIsHint) //Stop audio cue when close to the hint
AND fDist < BH_SOUND_MAX_RANGE_SQR
//Check timing
IF GET_GAME_TIMER() > sbhv.iNextSoundTime
IF Can_Play_Beast_Sound(sBHV)
//Update next sound time
sbhv.iNextSoundTime = GET_GAME_TIMER() + BH_SOUND_MIN_DELAY + GET_RANDOM_INT_IN_RANGE(0, BH_SOUND_RANDOM_DELAY)
CDEBUG1LN(debug_hunting,"Next beast audio in ",sbhv.iNextSoundTime - GET_GAME_TIMER())
TEXT_LABEL_63 temp = Build_Beast_String_63("C_SF", "DL", "AST", "X1/BE") //Prepare sound label
IF REQUEST_SCRIPT_AUDIO_BANK(temp)
Set_Beast_Call_Made(FALSE) //Disable bit that plays audio
//Calculate potision
sBHV.fSoundDist = FMAX(BH_SOUND_MIN_DIST_FROM_PLAYER, FMIN(BH_SOUND_DIST_FROM_PLAYER, VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), vNextPos)))
sBHV.vSoundPos = GET_VECTOR_OF_LENGTH(vNextPos - GET_ENTITY_COORDS(PLAYER_PED_ID()) , sBHV.fSoundDist)
CPRINTLN(debug_hunting, "Playing sound at ",sBHV.vSoundPos,", next in ",sbhv.iNextSoundTime - GET_GAME_TIMER()," ms")
//Play sound
sBHV.iBeastSoundID = GET_SOUND_ID()
TEXT_LABEL_23 temp2 = Build_Beast_String_23("st_C","Bea","ls","al") //"Beast_Calls"
temp = Build_Beast_String_63("nts_S","FM_Eve","atch_Sounds","asqu") //"FM_Events_Sasquatch_Sounds"
PLAY_SOUND_FROM_COORD(sBHV.iBeastSoundID, temp2, GET_ENTITY_COORDS(PLAYER_PED_ID()) + sBHV.vSoundPos, temp)
SET_BIT(sBHV.iState, BH_BIT_BEAST_SOUND_PLAYING)
//Reduce the range
Reset_Max_Node_Range(sBHV, BH_CHECKPOINT_RADIUS,TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
//Check if the sound is still playing
IF IS_BIT_SET(sBHV.iState, BH_BIT_BEAST_SOUND_PLAYING)
AND sBHV.iBeastSoundID != -1
IF HAS_SOUND_FINISHED(sBHV.iBeastSoundID)
RELEASE_SOUND_ID(sBHV.iBeastSoundID)
CLEAR_BIT(sBHV.iState, BH_BIT_BEAST_SOUND_PLAYING)
sBHV.iBeastSoundID = -1
ELSE
//Update sound position
UPDATE_SOUND_COORD(sBHV.iBeastSoundID, GET_ENTITY_COORDS(PLAYER_PED_ID()) + sBHV.vSoundPos)
#IF IS_DEBUG_BUILD
IF sBHV.bDebugDisplayPaths
//Debug draws
#IF IS_DEBUG_BUILD Beast_Display_Onscreen_Text(0.4,0.9, "Playing sound", 0.3) #ENDIF
DRAW_DEBUG_SPHERE(GET_ENTITY_COORDS(PLAYER_PED_ID()) + sBHV.vSoundPos, 1)
ENDIF
#ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL Is_Beast_Hunt_Allowed_To_Run(BeastHuntVars &sBeastHuntVars)
VEHICLE_INDEX vehTemp
//Temp: Would need to check some things in iState
sBeastHuntVars.iState = sBeastHuntVars.iState
RETURN IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED)
AND NOT IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
AND (IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_ANIMAL)) //No Director mode hunt
AND GET_PLAYER_MODEL() = Get_Sasquatch_Model()
AND NOT Is_Player_In_Bad_Hunt_Vehicle(vehTemp)
ENDFUNC
//==========================================MAIN UPDATE========================================
//=============================================================================================
PROC Maintain_Beast_Hunt(BeastHuntVars &sBeastHuntVars)
IF Has_Beast_Secret_Data_Setup_Finished()
IF NOT IS_BITMASK_SET(g_iBeastSetupInt,BH_Bit_Hunt_Init)
Finalise_Data_Init(sBeastHuntVars)
CPRINTLN(debug_hunting,"Hunting data init now set-up, running the Hunt scripts")
SET_BITMASK(g_iBeastSetupInt,BH_Bit_Hunt_Init)
ENDIF
ELSE
EXIT //Don't do anything until data setup finishes
ENDIF
//Only update if allowed to run
BOOL bCanRun = Is_Beast_Hunt_Allowed_To_Run(sBeastHuntVars)
IF NOT bCanRun
//Check if we need to delete the hints
IF DOES_ENTITY_EXIST(sBeastHuntVars.vehHint) OR DOES_ENTITY_EXIST(sBeastHuntVars.pedHint)
IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_ANIMAL)
OR NOT (GET_PLAYER_MODEL() = Get_Sasquatch_Model())
CPRINTLN(debug_hunting,"Player no longer on trip, cleaning hints")
Release_Checkpoint_Hint_Assets(sBeastHuntVars, TRUE)
ENDIF
ENDIF
IF sBeastHuntVars.bCouldRunLastFrame
CPRINTLN(debug_hunting,"Beast hunt no longer able to run.")
ENDIF
ELIF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF NOT sBeastHuntVars.bCouldRunLastFrame
CPRINTLN(debug_hunting,"Beast hunt now active.")
IF Is_White_Faded_Out() OR NOT sBeastHuntVars.bWasSasLastFrame
CPRINTLN(debug_hunting,"Starting white fade-out, Waiting until dead peds settle")
Do_White_Fade(255, 0)
sBeastHuntVars.iFadeOutTimer = 2000 //2 seconds
ENDIF
//Check if we need to run the audio scene
TEXT_LABEL_31 tlMixer = Build_Beast_String_31("til_P_","Exec_U","xer_Scene","B_Mi") //"Exec_Util_P_B_Mixer_Scene"
IF NOT IS_AUDIO_SCENE_ACTIVE(tlMixer)
//Activate the audio mixer scene
START_AUDIO_SCENE(tlMixer)
CPRINTLN(debug_hunting,"Started the Beast Hunt audio scene")
ENDIF
ENDIF
FLOAT fDist
//Get currenth path vars
INT iStart = Get_Beast_Hunt_Current_Checkpoint()
INT iNextCheckpoint = Get_Beast_Hunt_Next_Checkpoint()
INT iNode = Get_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState)
//Manage white fade-out wait time
IF sBeastHuntVars.iFadeOutTimer > 0
sBeastHuntVars.iFadeOutTimer -= FLOOR( GET_FRAME_TIME() * 1000)
//Call the fade-in when done
IF sBeastHuntVars.iFadeOutTimer <= 0
Do_White_Fade(0, DEFAULT_FADE_TIME)
CPRINTLN(debug_hunting,"Finished the white fade delay, fading in")
ENDIF
ENDIF
Update_White_Fade()
//Update spawning hint items at current and next checkpoint.
Manage_Beast_Checkpoint_Hints(sBeastHuntVars)
//Don't let the player record any of this.
REPLAY_PREVENT_RECORDING_AND_UI_THIS_FRAME()
//Check if on the last leg of the journey
IF Is_Node_Last_In_Path(sBeastHuntVars, iNode)
fDist = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), g_vBHCheckpoints[iNextCheckpoint])
//Next one is the next CP
IF fDist < BH_CHECKPOINT_RADIUS*BH_CHECKPOINT_RADIUS
AND IS_BIT_SET(sBeastHuntVars.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
Pick_Next_Checkpoint(sBeastHuntVars)
Reset_Node_In_Path(sBeastHuntVars)
Reset_Beast_Sound_Time(sBeastHuntVars, 4000)
CLEAR_BIT(sBeastHuntVars.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
//If this is the last checkpoint, activate the beast fight
IF iNextCheckpoint = BH_CHECKPOINT_COUNT - 1
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
SET_BIT(sBeastHuntVars.iState,BH_BIT_IGNORE_1ST_NODE) //Ignore the 1st node when coming back from the fight
Reset_Node_In_Path(sBeastHuntVars)
Reset_Max_Node_Range(sBeastHuntVars)
Set_Beast_Call_Made(TRUE) //Have beast call play when failing the fight
EXIT
ELSE
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_FIGHT_FAILED)
ENDIF
ELIF fDist > sBeastHuntVars.fCurrentMaxRadius
Reset_Node_In_Path(sBeastHuntVars)
Reset_Max_Node_Range(sBeastHuntVars)
ENDIF
Manage_Beast_Sound(sBeastHuntVars, g_vBHCheckpoints[iNextCheckpoint], TRUE)
ELIF Is_Node_First_In_Path(sBeastHuntVars,iNode)
fDist = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()),Get_Node_Location(sBeastHuntVars, iNode))
IF fDist < BH_CHECKPOINT_RADIUS * BH_CHECKPOINT_RADIUS
AND IS_BIT_SET(sBeastHuntVars.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
//Move to the next node
CPRINTLN(DEBUG_HUNTING, "-> Reached node ",iNode)
Set_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState, Get_Next_Node_In_Path(sBeastHuntVars, iNode))
Reset_Beast_Sound_Time(sBeastHuntVars, 4000)
Reset_Max_Node_Range(sBeastHuntVars)
CLEAR_BIT(sBeastHuntVars.iState, BH_BIT_CHECKPOINT_ITEM_TRIGGERED)
ELIF fDist > sBeastHuntVars.fCurrentMaxRadius
Reset_Max_Node_Range(sBeastHuntVars)
ENDIF
Manage_Beast_Sound(sBeastHuntVars, g_vBHCheckpoints[iStart], TRUE)
ELSE
fDist = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()),Get_Node_Location(sBeastHuntVars, iNode))
// DISPLAY_TEXT_WITH_FLOAT(0.4,0.5,"NUMBER",fDist,1)
//Check if player is close enough to trigger the next node
IF fDist < BH_PATH_NODE_RADIUS * BH_PATH_NODE_RADIUS
//Move to the next node
CPRINTLN(DEBUG_HUNTING, "-> Reached node ",iNode)
Set_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState, Get_Next_Node_In_Path(sBeastHuntVars, iNode))
Reset_Beast_Sound_Time(sBeastHuntVars)
Reset_Max_Node_Range(sBeastHuntVars)
//Check if player outside of range, reset path progress
ELIF fDist > sBeastHuntVars.fCurrentMaxRadius AND NOT Is_Node_First_In_Path(sBeastHuntVars,iNode)
//Reset path progress
Reset_Node_In_Path(sBeastHuntVars)
Reset_Max_Node_Range(sBeastHuntVars)
ENDIF
Manage_Beast_Sound(sBeastHuntVars, Get_Node_Location(sBeastHuntVars, iNode))
ENDIF
ENDIF
//Set last frame variables
sBeastHuntVars.bCouldRunLastFrame = bCanRun
sBeastHuntVars.bWasSasLastFrame = (GET_PLAYER_MODEL() = Get_Sasquatch_Model())
ENDPROC
#IF IS_DEBUG_BUILD
INT dbCheckPoint = -1, dbNode = -1, dbPath = -1
INT oldCheckPoint = -1, oldNode = -1, oldPath = -1
INT iCurrentPath
VECTOR oldPos
PROC Create_Beast_Hunt_Widgets(BeastHuntVars &sBeastHuntVars, WIDGET_GROUP_ID widgetID = NULL)
CPRINTLN(DEBUG_HUNTING, "Creating beast hunt widgets from ",GET_THIS_SCRIPT_NAME(),". Flags:",
" SP_INIT_BEAST_PEYOTES_COLLECTED:",IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED),",",
" SP_INIT_BEAST_HUNT_COMPLETED:",IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED))
IF widgetID != NULL
SET_CURRENT_WIDGET_GROUP(widgetID)
ENDIF
START_WIDGET_GROUP("Beast Hunt")
ADD_WIDGET_BOOL("Terminate thread", sBeastHuntVars.bDebugTerminateThread)
ADD_WIDGET_STRING("")
ADD_WIDGET_BOOL("Peyotes complete?", sBeastHuntVars.bDebugPeyotesComplete)
ADD_WIDGET_BOOL("Toggle peyotes complete", sBeastHuntVars.bDebugTogglePeyotesComplete)
ADD_WIDGET_STRING("")
ADD_WIDGET_BOOL("Hunt complete?", sBeastHuntVars.bDebugHuntComplete)
ADD_WIDGET_BOOL("Toggle hunt complete", sBeastHuntVars.bDebugToggleHuntComplete)
ADD_WIDGET_STRING("")
ADD_WIDGET_BOOL("Hunter hint seen?", sBeastHuntVars.bDebugHunterSeen)
ADD_WIDGET_BOOL("Toggle hunter hint seen", sBeastHuntVars.bDebugToggleHunterSeen)
ADD_WIDGET_STRING("")
ADD_WIDGET_BOOL("Warp and display", sBeastHuntVars.bWarpAndDisplay)
ADD_WIDGET_BOOL("Direct path to end", sBeastHuntVars.bDebugDirectPath)
ADD_WIDGET_BOOL("Display active path", sBeastHuntVars.bDebugDisplayActivePath)
ADD_WIDGET_BOOL("Display checkpoints", sBeastHuntVars.bDebugDisplayCheckpoints)
ADD_WIDGET_BOOL("Display all paths", sBeastHuntVars.bDebugDisplayPaths)
ADD_WIDGET_BOOL("Only current path", sBeastHuntVars.bDebugDisplayCurrentPath)
ADD_WIDGET_INT_SLIDER("Path", iCurrentPath, 0, sBeastHuntVars.iNumPaths-1, 1)
ADD_WIDGET_BOOL("Set current path", sBeastHuntVars.bDebugSetCurrentPath)
ADD_WIDGET_BOOL("Spread nodes on path", sBeastHuntVars.bSpreadPathNodes)
ADD_WIDGET_BOOL("Print path setup info", sBeastHuntVars.bPrintPathInformation)
STOP_WIDGET_GROUP()
IF widgetID != NULL
CLEAR_CURRENT_WIDGET_GROUP(widgetID)
ENDIF
ENDPROC
PROC Update_Beast_Hunt_Widgets(BeastHuntVars &sBeastHuntVars, WIDGET_GROUP_ID widgetID = NULL)
INT index, iCurrent, iNext
TEXT_LABEL_63 tl63Temp
//Alive check
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
ENDIF
//Check if data initialised, then create widgets
IF NOT Has_Beast_Secret_Data_Setup_Finished()
EXIT
ELSE
IF NOT sBeastHuntVars.bDebugWidgetsInitialised
Create_Beast_Hunt_Widgets(sBeastHuntVars, widgetID)
sBeastHuntVars.bDebugWidgetsInitialised = TRUE
ENDIF
ENDIF
IF sBeastHuntVars.bDebugTerminateThread
OR IS_DEBUG_KEY_JUST_PRESSED(KEY_F, KEYBOARD_MODIFIER_NONE, "Terminate thread")
CPRINTLN(DEBUG_HUNTING, "Beast hunt thread terminating from widget.")
TERMINATE_THIS_THREAD()
ENDIF
//Read only bools. Set it every frame based on state saved in global bitset.
sBeastHuntVars.bDebugPeyotesComplete = IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED)
sBeastHuntVars.bDebugHuntComplete = IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
sBeastHuntVars.bDebugHunterSeen = IS_BIT_SET(sBeastHuntVars.iState, BH_BIT_HUNTER_SEEN)
//Allow toggling of the saved bit.
IF sBeastHuntVars.bDebugTogglePeyotesComplete
IF IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED)
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED)
ELSE
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_PEYOTES_COLLECTED)
ENDIF
sBeastHuntVars.bDebugTogglePeyotesComplete = FALSE
ENDIF
IF sBeastHuntVars.bDebugToggleHuntComplete
IF IS_BIT_SET(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
CLEAR_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
ELSE
SET_BIT(g_savedGlobals.sFlowCustom.spInitBitset, SP_INIT_BEAST_HUNT_COMPLETED)
ENDIF
sBeastHuntVars.bDebugToggleHuntComplete = FALSE
ENDIF
IF sBeastHuntVars.bDebugToggleHunterSeen
IF IS_BIT_SET(sBeastHuntVars.iState, BH_BIT_HUNTER_SEEN)
CLEAR_BIT(sBeastHuntVars.iState, BH_BIT_HUNTER_SEEN)
ELSE
SET_BIT(sBeastHuntVars.iState, BH_BIT_HUNTER_SEEN)
ENDIF
sBeastHuntVars.bDebugToggleHunterSeen = FALSE
ENDIF
//Only update if allowed to run
IF NOT Is_Beast_Hunt_Allowed_To_Run(sBeastHuntVars)
EXIT
ENDIF
IF sBeastHuntVars.bWarpAndDisplay
//Get first checkpoint, warp player there
iCurrent = Get_Beast_Hunt_Current_Checkpoint()
iNext = Get_Beast_Hunt_Next_Checkpoint()
FLOAT fGroundZ
VECTOR vDir = NORMALISE_VECTOR(g_vBHCheckpoints[iCurrent] - g_vBHCheckpoints[iNext]) * BH_CHECKPOINT_RADIUS * 1.3
//Place the ped at that location
vDir = g_vBHCheckpoints[iCurrent] + vDir + <<0,0,50>>
SET_ENTITY_COORDS(PLAYER_PED_ID(), vDir )
Wait(0)
GET_GROUND_Z_FOR_3D_COORD(vDir,fGroundZ)
vDir.z = fGroundZ
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
SET_ENTITY_COORDS(PLAYER_PED_ID(),vDir)
ENDIF
SET_ENTITY_HEADING(PLAYER_PED_ID(),GET_HEADING_BETWEEN_VECTORS_2D(GET_ENTITY_COORDS(PLAYER_PED_ID()),g_vBHCheckpoints[iCurrent]))
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
//Set time to midnight
SET_CLOCK_TIME(0,0,0)
//Enable the debug spheres
sBeastHuntVars.bDebugDisplayCheckpoints = TRUE
sBeastHuntVars.bWarpAndDisplay = FALSE
ENDIF
IF sBeastHuntVars.bDebugDisplayCheckpoints
OR sBeastHuntVars.bDebugDisplayPaths
IF NOT sBeastHuntVars.bDebugDrawingEnabled
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
sBeastHuntVars.bDebugDrawingEnabled = TRUE
ENDIF
ELSE
IF sBeastHuntVars.bDebugDrawingEnabled
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(FALSE)
sBeastHuntVars.bDebugDrawingEnabled = FALSE
ENDIF
ENDIF
//Draw checkpoint spheres
IF sBeastHuntVars.bDebugDisplayCheckpoints
iCurrent = Get_Beast_Hunt_Current_Checkpoint()
iNext = Get_Beast_Hunt_Next_Checkpoint()
REPEAT BH_CHECKPOINT_COUNT index
tl63Temp = "Checkpoint("
tl63Temp += index
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_vBHCheckpoints[index], 255, 255, 0)
IF index = iCurrent
tl63Temp = "Current("
DRAW_DEBUG_SPHERE(g_vBHCheckpoints[index], BH_CHECKPOINT_RADIUS, 0, 0, 255, 60)
ELIF index = iNext
tl63Temp = "Next("
DRAW_DEBUG_SPHERE(g_vBHCheckpoints[index], BH_CHECKPOINT_RADIUS, 0, 255, 0, 60)
ELSE
tl63Temp = "Checkpoint("
DRAW_DEBUG_SPHERE(g_vBHCheckpoints[index], BH_CHECKPOINT_RADIUS, 255, 0, 0, 50)
ENDIF
tl63Temp += index
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_vBHCheckpoints[index], 255, 255, 0)
ENDREPEAT
ENDIF
//Draw the paths
IF sBeastHuntVars.bDebugDisplayPaths
INT path, curCP, nxtCP, pathStart, pathEnd, iNode
curCP = Get_Beast_Hunt_Current_Checkpoint()
nxtCP = Get_Beast_Hunt_Next_Checkpoint()
iNode = Get_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState)
path = g_iBHPathIndexes[curCP][nxtCP]
//Draw line to the current node and distance
DRAW_DEBUG_LINE(GET_ENTITY_COORDS(PLAYER_PED_ID())+<<0,0,1.2>>,Get_Node_Location(sBeastHuntVars, iNode),255,255,0)
tl63Temp = "CP:" tl63Temp += curCP tl63Temp += " Node:" tl63Temp += iNode
tl63Temp += " Dist:" tl63Temp += ROUND(VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()),Get_Node_Location(sBeastHuntVars, iNode)) * 10)
tl63Temp += "/" tl63Temp += Round(SQRT(sBeastHuntVars.fCurrentMaxRadius) * 10)
DRAW_DEBUG_TEXT(tl63Temp, GET_ENTITY_COORDS(PLAYER_PED_ID())+<<0,0,1.2>>,200,200,200)
REPEAT sBeastHuntVars.iNumPaths path
IF (NOT sBeastHuntVars.bDebugDisplayCurrentPath)
OR (g_iBHPathIndexes[curCP][nxtCP] = path OR g_iBHPathIndexes[nxtCP][curCP] = path)
Get_Beast_Hunt_Path_Endpoints(sBeastHuntVars, path, pathStart, pathEnd)
REPEAT g_sBHPath[path].iLength index
tl63Temp = "Path("
tl63Temp += path
tl63Temp += ") Node("
tl63Temp += index
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_sBHPath[path].vNode[index], 255, 255, 0)
DRAW_DEBUG_SPHERE(g_sBHPath[path].vNode[index], BH_PATH_NODE_RADIUS, 255, 255, 0, 60)
IF index = 0
DRAW_DEBUG_LINE(g_vBHCheckpoints[pathStart]+ <<0,0,BH_PATH_NODE_RADIUS>>, g_sBHPath[path].vNode[index]+ <<0,0,BH_PATH_NODE_RADIUS>>, 0, 255, 128, 255)
ENDIF
IF index = g_sBHPath[path].iLength-1
DRAW_DEBUG_LINE(g_sBHPath[path].vNode[index]+ <<0,0,BH_PATH_NODE_RADIUS>>, g_vBHCheckpoints[pathEnd]+ <<0,0,BH_PATH_NODE_RADIUS>>, 255, 0, 255, 255)
ELSE
DRAW_DEBUG_LINE(g_sBHPath[path].vNode[index]+ <<0,0,BH_PATH_NODE_RADIUS>>, g_sBHPath[path].vNode[index+1]+ <<0,0,BH_PATH_NODE_RADIUS>>, 0, 0, 255, 255)
ENDIF
ENDREPEAT
ENDIF
ENDREPEAT
ENDIF
IF sBeastHuntVars.bDebugDisplayActivePath
iCurrent = Get_Beast_Hunt_Current_Checkpoint()
iNext = Get_Beast_Hunt_Next_Checkpoint()
INT iPath = g_iBHPathIndexes[iCurrent][iNext]
//Draw current checkpoint.
tl63Temp = "Current("
tl63Temp += iCurrent
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_vBHCheckpoints[iCurrent], 255, 255, 0)
DRAW_DEBUG_SPHERE(g_vBHCheckpoints[iCurrent], BH_CHECKPOINT_RADIUS, 0, 0, 255, 60)
//Draw next checkpoint.
tl63Temp = "Next("
tl63Temp += iNext
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_vBHCheckpoints[iNext], 255, 255, 0)
DRAW_DEBUG_SPHERE(g_vBHCheckpoints[iNext], BH_CHECKPOINT_RADIUS, 0, 255, 0, 60)
//Draw path.
REPEAT g_sBHPath[iPath].iLength index
tl63Temp = "Path("
tl63Temp += iPath
tl63Temp += ") Node("
tl63Temp += index
tl63Temp += ")"
DRAW_DEBUG_TEXT(tl63Temp, g_sBHPath[iPath].vNode[index], 255, 255, 0)
DRAW_DEBUG_SPHERE(g_sBHPath[iPath].vNode[index], BH_PATH_NODE_RADIUS, 255, 255, 0, 60)
IF index < (g_sBHPath[iPath].iLength-2)
DRAW_DEBUG_LINE(g_sBHPath[iPath].vNode[index], g_sBHPath[iPath].vNode[index+1], 0, 0, 255, 255)
ENDIF
ENDREPEAT
ENDIF
//Manage mouse-clicking checkpoints and nodes
IF sBeastHuntVars.bDebugDisplayCheckpoints OR sBeastHuntVars.bDebugDisplayPaths
VECTOR vPos
IF IS_MOUSE_BUTTON_JUST_PRESSED(MB_LEFT_BTN)
SET_FOCUS_POS_AND_VEL(GET_GAMEPLAY_CAM_COORD(), <<0,0,0>>)
Wait(0) //Wait to generate collision at location
vPos = GET_SCRIPT_MOUSE_POINTER_IN_WORLD_COORDS()
//Search through all checkpoints
REPEAT BH_CHECKPOINT_COUNT index
IF VDIST2(vPos, g_vBHCheckpoints[index]) < BH_CHECKPOINT_RADIUS*BH_CHECKPOINT_RADIUS
dbCheckPoint = index
CPRINTLN(debug_dan,"found cp ",dbCheckPoint)
//Undo vars
oldPos = g_vBHCheckpoints[index] oldCheckpoint = index
BREAKLOOP
ENDIF
ENDREPEAT
IF dbCheckPoint = -1
INT path
//Search through all paths
REPEAT sBeastHuntVars.iNumPaths path
BOOL bFound = FALSE
REPEAT g_sBHPath[path].iLength index
IF VDIST2(vPos, g_sBHPath[path].vNode[index]) < BH_PATH_NODE_RADIUS * BH_PATH_NODE_RADIUS
dbPath = path dbNode = index bFound = TRUE
CPRINTLN(debug_dan,"found node ",dbNode)
//Undo vars
oldPos = g_sBHPath[path].vNode[index] oldPath = path oldNode = index
BREAKLOOP
ENDIF
ENDREPEAT
IF bFound BREAKLOOP ENDIF
ENDREPEAT
ENDIF
ELIF IS_MOUSE_BUTTON_PRESSED(MB_LEFT_BTN)
vPos = GET_SCRIPT_MOUSE_POINTER_IN_WORLD_COORDS()
VECTOR vDiff
//Set streaming in that area
SET_FOCUS_POS_AND_VEL(vPos, <<0,0,0>>)
IF (dbCheckPoint > -1 OR dbNode > -1 OR dbPath > -1)
//Move checkpoint
IF dbCheckPoint > -1
vDiff = vPos - g_vBHCheckpoints[dbCheckPoint]
g_vBHCheckpoints[dbCheckPoint] = vPos
CPRINTLN(debug_dan,"Move CP to ",vPos)
//Move node
ELSE
vDiff = vPos - g_sBHPath[dbPath].vNode[dbNode]
g_sBHPath[dbPath].vNode[dbNode] = vPos
ENDIF
//Apply movement to all nodes
IF IS_DEBUG_KEY_PRESSED(KEY_CAPITAL, KEYBOARD_MODIFIER_NONE, "Move all nodes")
vDiff.z = 0
REPEAT BH_CHECKPOINT_COUNT index
IF index != dbCheckpoint
g_vBHCheckpoints[index] += vDiff
ENDIF
ENDREPEAT
INT path
REPEAT sBeastHuntVars.iNumPaths path
REPEAT g_sBHPath[path].iLength index
IF path != dbPath OR index != dbNode
g_sBHPath[path].vNode[index] += vDiff
ENDIF
ENDREPEAT
ENDREPEAT
ENDIF
ENDIF
ELIF IS_MOUSE_BUTTON_JUST_RELEASED(MB_LEFT_BTN)
CLEAR_FOCUS()
dbNode = -1
dbPath = -1
dbCheckPoint = -1
ENDIF
//Check undo press
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_Z, KEYBOARD_MODIFIER_NONE, "Undo last move")
IF oldCheckpoint != -1
g_vBHCheckpoints[oldCheckpoint] = oldPos
oldCheckpoint = -1
ELIF oldNode != -1 AND oldPath != -1
g_sBHPath[oldPath].vNode[oldNode] = oldPos
oldNode = -1 oldPath = -1
ENDIF
ENDIF
ENDIF
//Print path info
IF sBeastHuntVars.bPrintPathInformation
sBeastHuntVars.bPrintPathInformation = FALSE
CPRINTLN(debug_hunting,"//<---------------PATH SETUP INFO HERE----------------->")
CPRINTLN(debug_hunting,"")
REPEAT BH_CHECKPOINT_COUNT index
CPRINTLN(debug_hunting, "g_vBHCheckpoints[",index,"] = ",g_vBHCheckpoints[index])
ENDREPEAT
INT path, iCP1, iCP2, index2
TEXT_LABEL_63 tlVec[4]
CPRINTLN(debug_hunting,"")
//Search through all paths
REPEAT sBeastHuntVars.iNumPaths path
Get_Beast_Hunt_Path_Endpoints(sBeastHuntVars, path, iCP1, iCP2)
REPEAT 4 index tlVec[index] = "" ENDREPEAT
REPEAT g_sBHPath[path].iLength index
index2 = index / 2
IF index > 0 tlVec[index2] += ", " ENDIF
tlVec[index2] += FLOAT_TO_STRING(g_sBHPath[path].vNode[index].x, 2)
tlVec[index2] += ", "
tlVec[index2] += FLOAT_TO_STRING(g_sBHPath[path].vNode[index].y, 2)
tlVec[index2] += ", "
tlVec[index2] += FLOAT_TO_STRING(g_sBHPath[path].vNode[index].z, 2)
ENDREPEAT
CPRINTLN(debug_hunting,"//Path ",path," from ",iCP1, " to ", iCP2)
CPRINTLN(debug_hunting,"Add_Beast_Hunt_Path(sBeastHuntVars, ",iCP1,", ",iCP2,", TRUE, ",tlVec[0],tlVec[1],")")
CPRINTLN(debug_hunting, "")
ENDREPEAT
CPRINTLN(debug_hunting,"")
CPRINTLN(debug_hunting,"//<----------------END PATH SETUP INFO---------------->")
ENDIF
//Set current path
IF sBeastHuntVars.bDebugSetCurrentPath
sBeastHuntVars.bDebugSetCurrentPath = FALSE
INT iStart, iEnd
Get_Beast_Hunt_Path_Endpoints(sBeastHuntVars, iCurrentPath, iStart, iEnd)
Set_Beast_Hunt_Current_Checkpoint(iStart)
Set_Beast_Hunt_Next_Checkpoint(iEnd)
Reset_Node_In_Path(sBeastHuntVars)
ENDIF
//Spread nodes on a path
IF sBeastHuntVars.bSpreadPathNodes
INT startCP, endCP
FLOAT fGround
Get_Beast_Hunt_Path_Endpoints(sBeastHuntVars, iCurrentPath, startCP, endCP)
VECTOR vStep = g_vBHCheckpoints[endCP] - g_vBHCheckpoints[startCP]
CPRINTLN(debug_hunting, startCP," - ",endCP," Step is ", vStep)
vStep /= TO_FLOAT(g_sBHPath[iCurrentPath].iLength + 1)
CPRINTLN(debug_hunting, "Step is ", vStep)
REPEAT g_sBHPath[iCurrentPath].iLength index
g_sBHPath[iCurrentPath].vNode[index] = g_vBHCheckpoints[startCP] + vStep * TO_FLOAT(index + 1)
SET_FOCUS_POS_AND_VEL(g_sBHPath[iCurrentPath].vNode[index], <<0,0,0>>)
Wait(0)
TEST_VERTICAL_PROBE_AGAINST_ALL_WATER(g_sBHPath[iCurrentPath].vNode[index] + <<0,0,500>>, SCRIPT_INCLUDE_MOVER, fGround)
g_sBHPath[iCurrentPath].vNode[index].z = fGround
ENDREPEAT
CLEAR_FOCUS()
sBeastHuntVars.bSpreadPathNodes = FALSE
ENDIF
//J-skip to next node
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_J, KEYBOARD_MODIFIER_SHIFT,"Skip to next node")
VECTOR vtemp = Get_Node_Location(sBeastHuntVars, Get_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState))
CPRINTLN(debug_hunting, "Starting j-skip to next node at ",vtemp)
IF IS_GAMEPLAY_HINT_ACTIVE()
STOP_GAMEPLAY_HINT()
ENDIF
// START_PLAYER_TELEPORT(PLAYER_ID(), Get_Node_Location(sBeastHuntVars, Get_Beast_Hunt_Current_Path_Node(sBeastHuntVars.iState)) + <<0,0,3>>, 0)
// INT iTimer = GET_GAME_TIMER() + 1500
// WHILE UPDATE_PLAYER_TELEPORT(PLAYER_ID()) AND GET_GAME_TIMER() < iTimer
// WAIT(0)
// ENDWHILE
// STOP_PLAYER_TELEPORT()
SET_ENTITY_COORDS(PLAYER_PED_ID(),vTemp + <<0,0,3>>,FALSE)
ENDIF
//Check the node locations in globals vs current
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_C, KEYBOARD_MODIFIER_CTRL_SHIFT, "Check node consistency")
INT i, j, iBad = 0
FOR i = 0 to 19
FOR j = 0 to 3
IF NOT ARE_VECTORS_EQUAL(g_sBHPath[i].vNode[j], g_vBHNodes[i][j])
CPRINTLN(Debug_Hunting,"node ",i," ",j," ",g_vBHNodes[i][j]," != ",g_sBHPath[i].vNode[j])
iBad++
ENDIF
ENDFOR
ENDFOR
CPRINTLN(debug_hunting,"Bad nodes found: ",iBad)
ENDIF
ENDPROC
#ENDIF //DEBUG
#ENDIF //FEATURE_SP_DLC_BEAST_SECRET