//- commands headers -// //- script headers -// //- public headers -// USING "friends_public.sch" //- private headers -// USING "friendUtil_dialogue_private.sch" USING "friendUtil_location_private.sch" #IF IS_DEBUG_BUILD //- debug headers -// #ENDIF ///private header for friend utils - including this file will include all utils /// sam.hackett@rockstarnorth.com /// CONST_FLOAT CONST_fApproachAmbientPlayerDistOn 10.5//12.5//15.0//15.0//20.0//15.0//20.0 CONST_FLOAT CONST_fApproachAmbientPlayerDistOff 12.0//15.0//17.0//20.0//25.0//30.0//40.0 CONST_INT CONST_iFriendAdhocChance 15 // ******************************************************************************************* // DEBUG OUTPUT UTILS // ******************************************************************************************* #IF IS_DEBUG_BUILD USING "script_debug.sch" USING "shared_debug.sch" // USING "hud_creator_tool.sch" // Draw background box (should probably be a function in FriendUtil_private.sch) FUNC BOOL DrawFriendBox(FLOAT fCentreX, FLOAT fCentreY, FLOAT fWidth, FLOAT fHeight, INT R, INT G, INT B, INT A) IF g_flowUnsaved.bShowMissionFlowDebugScreen IF (g_iDebugSelectedFriendConnDisplay > 0) DRAW_RECT(fCentreX, fCentreY, fWidth, fHeight, R, G, B, A) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL DrawFriendLiteralString(STRING sLiteral, INT iColumn, HUD_COLOURS eColour = HUD_COLOUR_PURE_WHITE) IF g_flowUnsaved.bShowMissionFlowDebugScreen IF (g_iDebugSelectedFriendConnDisplay > 0) CONST_FLOAT fDebugRow_one 0.5//0.320 //(12.0*0.0305) CONST_FLOAT fDebugRow_two 0.075 //(4.0*0.0305) CONST_FLOAT fDebugRow_three 0.023 FLOAT fDebugRow = 0.0 IF (g_iDebugSelectedFriendConnDisplay = 1) fDebugRow = fDebugRow_one ELIF (g_iDebugSelectedFriendConnDisplay = 2) fDebugRow = fDebugRow_two ENDIF INT red, green, blue, iAlpha GET_HUD_COLOUR(eColour, red, green, blue, iAlpha) SET_TEXT_SCALE(0.35, 0.30) SET_TEXT_COLOUR(red, green, blue, iAlpha) DISPLAY_TEXT_WITH_LITERAL_STRING(0.7795, fDebugRow+(fDebugRow_three*TO_FLOAT(iColumn)), "STRING", sLiteral) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL DrawFriendLiteralStringInt(STRING sLiteral, INT sInt, INT iColumn, HUD_COLOURS eColour = HUD_COLOUR_PURE_WHITE) TEXT_LABEL_63 sNewLiteral = sLiteral sNewLiteral += sInt RETURN DrawFriendLiteralString(sNewLiteral, iColumn, eColour) ENDFUNC FUNC BOOL DrawFriendLiteralStringFloat(STRING sLiteral, FLOAT sFloat, INT iColumn, HUD_COLOURS eColour = HUD_COLOUR_PURE_WHITE) TEXT_LABEL_63 sNewLiteral = sLiteral sNewLiteral += GET_STRING_FROM_FLOAT(sFloat) RETURN DrawFriendLiteralString(sNewLiteral, iColumn, eColour) ENDFUNC FUNC BOOL DrawFriendLiteralStringFriend(STRING sLiteral, enumFriend friendID, INT iColumn, HUD_COLOURS eColour = HUD_COLOUR_PURE_WHITE) TEXT_LABEL_63 sNewLiteral = GetLabel_enumFriend(friendID) sNewLiteral += " " sNewLiteral += sLiteral RETURN DrawFriendLiteralString(sNewLiteral, iColumn, eColour) ENDFUNC FUNC BOOL DrawFriendTimerBar(structTimer sTimer, FLOAT fHoursMax, INT iColumn, HUD_COLOURS eColour = HUD_COLOUR_PURE_WHITE) IF g_flowUnsaved.bShowMissionFlowDebugScreen IF (g_iDebugSelectedFriendConnDisplay > 0) CONST_FLOAT fTopX 0.7770 //= 0.7795 + (0.7770-0.7795) CONST_FLOAT fWidth 0.1500 CONST_FLOAT fHeight 0.0200 CONST_FLOAT fDebugRow_one 0.320 //(12.0*0.0305) CONST_FLOAT fDebugRow_two 0.075 //(4.0*0.0305) CONST_FLOAT fDebugRow_three 0.023 FLOAT fDebugRow = 0.0 IF (g_iDebugSelectedFriendConnDisplay = 1) fDebugRow = fDebugRow_one ELIF (g_iDebugSelectedFriendConnDisplay = 2) fDebugRow = fDebugRow_two ENDIF FLOAT fTopY = fDebugRow+(fDebugRow_three*TO_FLOAT(iColumn)) FLOAT fTimerInSeconds = GET_TIMER_IN_SECONDS(sTimer) FLOAT fHoursSeconds = fHoursMax*60*60 FLOAT fWidthMult =1-(fTimerInSeconds/fHoursSeconds) INT theR, theG, theB, theA GET_HUD_COLOUR(eColour, theR, theG, theB, theA) theR = ROUND(1.0-TO_FLOAT(theR)) theG = ROUND(1.0-TO_FLOAT(theG)) theB = ROUND(1.0-TO_FLOAT(theB)) theA = ROUND((TO_FLOAT(theA))*0.75) DRAW_RECT_FROM_CORNER(fTopX, fTopY, fWidth*fWidthMult, fHeight, theR, theG, theB, theA) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC #ENDIF //--------------------------------------------------------------------------------------------------- //-- Range functions //--------------------------------------------------------------------------------------------------- FUNC BOOL Util_IsPedInsideRange( ENTITY_INDEX hPed, VECTOR vCentre, FLOAT fRange ) VECTOR vPed = GET_ENTITY_COORDS(hPed) vPed.x -= vCentre.x vPed.y -= vCentre.y vPed.z -= vCentre.z RETURN (((vPed.x*vPed.x)+(vPed.y*vPed.y)+(vPed.z*vPed.z)) <= fRange*fRange) ENDFUNC FUNC BOOL Util_IsPedOutsideRange( ENTITY_INDEX hPed, VECTOR vCentre, FLOAT fRange ) VECTOR vPed = GET_ENTITY_COORDS(hPed) vPed.x -= vCentre.x vPed.y -= vCentre.y vPed.z -= vCentre.z RETURN (((vPed.x*vPed.x)+(vPed.y*vPed.y)+(vPed.z*vPed.z)) > fRange*fRange) ENDFUNC FUNC BOOL Util_IsVecInsideRange( VECTOR vPoint, VECTOR vCentre, FLOAT fRange ) vPoint.x -= vCentre.x vPoint.y -= vCentre.y vPoint.z -= vCentre.z RETURN (((vPoint.x*vPoint.x)+(vPoint.y*vPoint.y)+(vPoint.z*vPoint.z)) <= fRange*fRange) ENDFUNC FUNC BOOL Util_IsVecOutsideRange( VECTOR vPoint, VECTOR vCentre, FLOAT fRange ) vPoint.x -= vCentre.x vPoint.y -= vCentre.y vPoint.z -= vCentre.z RETURN (((vPoint.x*vPoint.x)+(vPoint.y*vPoint.y)+(vPoint.z*vPoint.z)) > fRange*fRange) ENDFUNC FUNC BOOL Util_IsPedInsideRangePed( ENTITY_INDEX hPed1, ENTITY_INDEX hPed2, FLOAT fRange ) VECTOR vPed1 = GET_ENTITY_COORDS(hPed1) VECTOR vPed2 = GET_ENTITY_COORDS(hPed2) vPed1.x -= vPed2.x vPed1.y -= vPed2.y vPed1.z -= vPed2.z RETURN (((vPed1.x*vPed1.x)+(vPed1.y*vPed1.y)+(vPed1.z*vPed1.z)) <= fRange*fRange) ENDFUNC FUNC BOOL Util_IsPedOutsideRangePed( ENTITY_INDEX hPed1, ENTITY_INDEX hPed2, FLOAT fRange ) VECTOR vPed1 = GET_ENTITY_COORDS(hPed1) VECTOR vPed2 = GET_ENTITY_COORDS(hPed2) vPed1.x -= vPed2.x vPed1.y -= vPed2.y vPed1.z -= vPed2.z RETURN (((vPed1.x*vPed1.x)+(vPed1.y*vPed1.y)+(vPed1.z*vPed1.z)) > fRange*fRange) ENDFUNC FUNC BOOL Private_IsPointInArea2D(VECTOR vPoint, VECTOR vMin, VECTOR vMax) IF vMin.x <= vPoint.x AND vPoint.x <= vMax.x AND vMin.y <= vPoint.y AND vPoint.y <= vMax.y RETURN TRUE ENDIF RETURN FALSE ENDFUNC //--------------------------------------------------------------------------------------------------- //-- Hospital charges //--------------------------------------------------------------------------------------------------- FUNC CC_CodeID Private_GetHospitalChargeCID(PED_INDEX hPed) IF DOES_ENTITY_EXIST(hPed) VECTOR vPos = GET_ENTITY_COORDS(hPed, FALSE) IF NOT DOES_ENTITY_EXIST(PLAYER_PED_ID()) OR HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(hPed, PLAYER_PED_ID()) SWITCH GET_CLOSEST_HOSPITAL(vPos, TRUE) CASE HOSPITAL_RH RETURN CID_HOSPITAL_CHARGE_RH BREAK CASE HOSPITAL_SC RETURN CID_HOSPITAL_CHARGE_SC BREAK CASE HOSPITAL_DT RETURN CID_HOSPITAL_CHARGE_DT BREAK CASE HOSPITAL_SS RETURN CID_HOSPITAL_CHARGE_SS BREAK CASE HOSPITAL_PB RETURN CID_HOSPITAL_CHARGE_PB BREAK ENDSWITCH RETURN CID_HOSPITAL_CHARGE_RH ENDIF ENDIF RETURN CID_BLANK ENDFUNC //--------------------------------------------------------------------------------------------------- //-- Connection played query functions //--------------------------------------------------------------------------------------------------- FUNC BOOL HAS_CONNECTION_BEEN_PLAYED(enumFriendConnection eConnection) IF eConnection < MAX_FRIEND_CONNECTIONS RETURN IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(FC_FLAG_DoneCompletionPercent)) ELSE SCRIPT_ASSERT("HAS_CONNECTION_BEEN_PLAYED() - Invalid connection") RETURN FALSE ENDIF ENDFUNC PROC SET_CONNECTION_PLAYED(enumFriendConnection eConnection) IF eConnection < MAX_FRIEND_CONNECTIONS IF NOT IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(FC_FLAG_DoneCompletionPercent)) CPRINTLN(DEBUG_FRIENDS, "SET_CONNECTION_PLAYED(", GetLabel_enumFriendConnection(eConnection), ")") SET_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(FC_FLAG_DoneCompletionPercent)) ENDIF ELSE SCRIPT_ASSERT("SET_CONNECTION_PLAYED() - Invalid connection") ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Placement functions //--------------------------------------------------------------------------------------------------- /// PURPOSE: /// Set's an entity either to the given heading, or it's opposite, whichever is nearest /// PARAMS: /// hEntity - entity to rotate /// fHeading - entity will be set to this direction, or the opposite direction /// RETURNS: /// Returns true if used given heading, false if used reverse heading FUNC BOOL SET_ENTITY_PARALLEL_TO_HEADING(ENTITY_INDEX hEntity, FLOAT fHeading) VECTOR vEntityForward = GET_ENTITY_FORWARD_VECTOR(hEntity) VECTOR vHeadingForward = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(<<0.0,0.0,0.0>>, fHeading, <<0.0,1.0,0.0>>) IF DOT_PRODUCT_XY(vEntityForward, vHeadingForward) >= 0 SET_ENTITY_HEADING(hEntity, fHeading) RETURN TRUE ELSE SET_ENTITY_HEADING(hEntity, fHeading+180.0) RETURN FALSE ENDIF ENDFUNC /// PURPOSE: /// Gets the heading an entity would need to have to point at a given coord /// PARAMS: /// hEntity - the entity to be rotated /// vLookAt - the point the entity wants to face FUNC FLOAT GET_FACING_HEADING(VECTOR vEntityPos, vector vLookAt) RETURN GET_HEADING_FROM_VECTOR_2D(vLookAt.x - vEntityPos.x, vLookAt.y - vEntityPos.y) ENDFUNC FUNC BOOL IS_ENTITY_FACING_HEADING(PED_INDEX hPed, FLOAT fHeading, FLOAT fMaxAngle = 30.0) VECTOR vForward = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(<<0.0, 0.0, 0.0>>, fHeading, <<0.0, 1.0, 0.0>>) VECTOR vFacing = GET_ENTITY_FORWARD_VECTOR(hPed) IF vFacing.x < 0.001 AND vFacing.y < 0.001 RETURN TRUE ENDIF vFacing.z = 0.0 vFacing = NORMALISE_VECTOR(vFacing) // Is entity facing to left? IF DOT_PRODUCT(vForward, vFacing) > COS(fMaxAngle) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL IS_ENTITY_FACING_COORD(ENTITY_INDEX hEntity, VECTOR vCoord) VECTOR vToCoord = vCoord - GET_ENTITY_COORDS(hEntity) VECTOR vFacing = GET_ENTITY_FORWARD_VECTOR(hEntity) IF DOT_PRODUCT_XY(vToCoord, vFacing) > 0 RETURN TRUE ENDIF RETURN FALSE ENDFUNC //FUNC BOOL IS_HEADING_FACING_COORD(VECTOR vOrigin, FLOAT fHeading, VECTOR vCoord) // // VECTOR vForward = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(<<0.0, 0.0, 0.0>>, fHeading, <<0.0, 1.0, 0.0>>) // vCoord -= vOrigin // // IF vCoord.x < 0.001 AND vCoord.y < 0.001 // RETURN TRUE // ENDIF // vCoord.z = 0.0 // // IF DOT_PRODUCT_XY(vForward, vCoord) > 0.0 // RETURN TRUE // ENDIF // // RETURN FALSE // //ENDFUNC //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- PROC Private_EnableFamilyScenes(enumCharacterList eChar, BOOL bEnable) IF bEnable = FALSE SWITCH eChar CASE CHAR_MICHAEL g_eCurrentFamilyEvent[FM_TREVOR_0_MICHAEL] = FAMILY_MEMBER_BUSY BREAK CASE CHAR_FRANKLIN // BREAK CASE CHAR_TREVOR g_eCurrentFamilyEvent[FM_TREVOR_0_TREVOR] = FAMILY_MEMBER_BUSY BREAK CASE CHAR_LAMAR g_eCurrentFamilyEvent[FM_FRANKLIN_LAMAR] = FAMILY_MEMBER_BUSY BREAK CASE CHAR_JIMMY g_eCurrentFamilyEvent[FM_MICHAEL_SON] = FAMILY_MEMBER_BUSY BREAK CASE CHAR_AMANDA g_eCurrentFamilyEvent[FM_MICHAEL_WIFE] = FAMILY_MEMBER_BUSY BREAK DEFAULT CPRINTLN(DEBUG_FRIENDS, "Private_EnableFamilyScenes(", GetLabel_enumCharacterList(eChar), ", FALSE) - This char not supported") SCRIPT_ASSERT("Private_EnableFamilyScenes() - This char not supported") BREAK ENDSWITCH ELSE SWITCH eChar CASE CHAR_MICHAEL IF g_eCurrentFamilyEvent[FM_TREVOR_0_MICHAEL] = FAMILY_MEMBER_BUSY g_eCurrentFamilyEvent[FM_TREVOR_0_MICHAEL] = NO_FAMILY_EVENTS ENDIF BREAK CASE CHAR_FRANKLIN // BREAK CASE CHAR_TREVOR IF g_eCurrentFamilyEvent[FM_TREVOR_0_TREVOR] = FAMILY_MEMBER_BUSY g_eCurrentFamilyEvent[FM_TREVOR_0_TREVOR] = NO_FAMILY_EVENTS ENDIF BREAK CASE CHAR_LAMAR IF g_eCurrentFamilyEvent[FM_FRANKLIN_LAMAR] = FAMILY_MEMBER_BUSY g_eCurrentFamilyEvent[FM_FRANKLIN_LAMAR] = NO_FAMILY_EVENTS ENDIF BREAK CASE CHAR_JIMMY IF g_eCurrentFamilyEvent[FM_MICHAEL_SON] = FAMILY_MEMBER_BUSY g_eCurrentFamilyEvent[FM_MICHAEL_SON] = NO_FAMILY_EVENTS ENDIF BREAK CASE CHAR_AMANDA IF g_eCurrentFamilyEvent[FM_MICHAEL_WIFE] = FAMILY_MEMBER_BUSY g_eCurrentFamilyEvent[FM_MICHAEL_WIFE] = NO_FAMILY_EVENTS ENDIF BREAK DEFAULT CPRINTLN(DEBUG_FRIENDS, "Private_EnableFamilyScenes(", GetLabel_enumCharacterList(eChar), ", TRUE) - This char not supported") SCRIPT_ASSERT("Private_EnableFamilyScenes() - This char not supported") BREAK ENDSWITCH ENDIF ENDPROC FUNC BOOL Private_IsFamilySceneCharActive(enumCharacterList eChar) SWITCH eChar CASE CHAR_MICHAEL IF g_eCurrentFamilyEvent[FM_TREVOR_0_MICHAEL] < MAX_FAMILY_EVENTS RETURN TRUE ENDIF BREAK CASE CHAR_FRANKLIN // BREAK CASE CHAR_TREVOR IF g_eCurrentFamilyEvent[FM_TREVOR_0_TREVOR] < MAX_FAMILY_EVENTS RETURN TRUE ENDIF BREAK CASE CHAR_LAMAR IF g_eCurrentFamilyEvent[FM_FRANKLIN_LAMAR] < MAX_FAMILY_EVENTS RETURN TRUE ENDIF BREAK CASE CHAR_JIMMY IF g_eCurrentFamilyEvent[FM_MICHAEL_SON] < MAX_FAMILY_EVENTS RETURN TRUE ENDIF BREAK CASE CHAR_AMANDA IF g_eCurrentFamilyEvent[FM_MICHAEL_WIFE] < MAX_FAMILY_EVENTS RETURN TRUE ENDIF BREAK DEFAULT CPRINTLN(DEBUG_FRIENDS, "Private_IsFamilySceneCharActive(", GetLabel_enumCharacterList(eChar), ", FALSE) - This char not supported") SCRIPT_ASSERT("Private_IsFamilySceneCharActive() - This char not supported") BREAK ENDSWITCH RETURN FALSE ENDFUNC //---------------------------------------------------------------------------------- FUNC BOOL CREATE_STORED_VEHICLE(VEHICLE_INDEX &ReturnVeh, enumCharacterList ePed, VECTOR vCoords, FLOAT fHeading, BOOL bCleanupModel, PED_VEH_DATA_STRUCT& sVehData) IF sVehData.model = DUMMY_MODEL_FOR_SCRIPT // Bail out so we don't get stuck. // Scripts should be checking if the vehicle is driveable anyway. RETURN TRUE ENDIF IF DOES_ENTITY_EXIST(ReturnVeh) IF GET_ENTITY_MODEL(ReturnVeh) != sVehData.model #IF IS_DEBUG_BUILD SCRIPT_ASSERT("CREATE_STORED_VEHICLE - Vehicle ID already exists with different model") #ENDIF ENDIF RETURN TRUE ENDIF REQUEST_MODEL(sVehData.model) IF HAS_MODEL_LOADED(sVehData.model) PRINTLN(GET_THIS_SCRIPT_NAME(), ": CREATE_STORED_VEHICLE() Using stored data") ReturnVeh = CREATE_VEHICLE(sVehData.model, vCoords, fHeading) SET_VEHICLE_ON_GROUND_PROPERLY(ReturnVeh) SET_VEHICLE_NOT_STEALABLE_AMBIENTLY(ReturnVeh, FALSE) SET_VEHICLE_CAN_SAVE_IN_GARAGE(ReturnVeh, FALSE) SET_VEHICLE_HAS_STRONG_AXLES(ReturnVeh, TRUE) SET_VEH_DATA_FROM_STRUCT(ReturnVeh, sVehData) IF sVehData.bIsPlayerVehicle // Attach Mr Raspberry Jam to Trevors truck IF ePed = CHAR_TREVOR IF GET_ENTITY_MODEL(ReturnVeh) = BODHI2 TURN_ON_MR_RASPBERRY_JAM(ReturnVeh) ENDIF ENDIF STORE_TEMP_PLAYER_VEHICLE_ID(ReturnVeh, ePed) ENDIF IF bCleanupModel SET_MODEL_AS_NO_LONGER_NEEDED(sVehData.model) ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- FUNC BOOL Private_IsEntityOwnedBy(ENTITY_INDEX hEntity, STRING sCheckScript) STRING sOwnerScript = "" INT hOwnerScript = 0 sOwnerScript = GET_ENTITY_SCRIPT(hEntity, hOwnerScript) IF NOT IS_STRING_NULL_OR_EMPTY(sOwnerScript) AND NOT IS_STRING_NULL_OR_EMPTY(sCheckScript) IF ARE_STRINGS_EQUAL(sOwnerScript, sCheckScript) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC