Files
gtav-src/script/dev_ng/shared/include/public/rgeneral_include.sch
T
2025-09-29 00:52:08 +02:00

3168 lines
88 KiB
Scheme
Executable File

// *****************************************************************************************
// *****************************************************************************************
//
// FILE NAME : rgeneral_include.sch
// AUTHOR : Aaron Gandaa
// DESCRIPTION : Handy functions for spawn points and stuff
//
// *****************************************************************************************
// *****************************************************************************************
//----------------------
// INCLUDES
//----------------------
USING "rage_builtins.sch"
USING "globals.sch"
USING "commands_script.sch"
USING "commands_entity.sch"
USING "commands_object.sch"
USING "commands_hud.sch"
USING "commands_misc.sch"
USING "script_maths.sch"
USING "script_ped.sch"
USING "shared_hud_displays.sch"
//----------------------
// ENUMS
//----------------------
ENUM STAGE_PROGRESS
SP_LOADING,
SP_SETUP,
SP_RUNNING,
SP_CSKIPPED,
SP_CLEANUP
ENDENUM
ENUM RAND_GENTYPE
RAND_STICK,
RAND_LIM,
RAND_GERHARD,
RAND_BILL
ENDENUM
ENUM PLANE_SIDE
INFRONT_PLANE = 1,
BEHIND_PLANE = -1,
ON_PLANE = 0
ENDENUM
STRUCT COMBAT_PARAMETERS
FIRING_PATTERN_HASH hFiringPattern = FIRING_PATTERN_DELAY_FIRE_BY_ONE_SEC
FLOAT fPlayerWeaponDamageModifier = 1.0 // set this to increase or decrease damage dealt out by player
FLOAT fPlayerWeaponDefenseModifier = 1.0 // set this to increase or decrease damage taken by player
FLOAT fPlayerMeleeWeaponDefenseModifier = 1.0 // set this to increase or decrease melee damage taken by player
FLOAT fWeaponAccuracy1 = 0.075
FLOAT fWeaponAccuracy2 = 0.075
FLOAT fNearBlankChance = 0.0 // default in code
FLOAT fFarBlankChance = 0.5 // default in code
FLOAT fFlankChance = 0.2
FLOAT fCoverOnlyChance = 0.0
FLOAT fMinTimeBetweenPeeks = 10.0 // default in code
FLOAT fMaxTimeBetweenPeeks = 11.0
FLOAT fMinTimeBetweenCoverBurst = 1.25 // default in code
FLOAT fMaxTimeBetweenCoverBurst = 2.25
FLOAT fMinBurstDurationTime = 2.0 // default in code
FLOAT fMaxBurstDurationTime = 2.5
INT iMinShootRate = 99
INT iMaxShootRate = 100
INT iForcedCombatLevel = -1 // -1 - pick a random level, 0 - poor, 1 - average, 2 - pro
INT iForcedCombatRange = -1 // -1 - pick a random range, 0 - near, 1 - medium, 2 - far
FLOAT fAgressionChance = 0.5
ENDSTRUCT
//----------------------
// STRUCT
//----------------------
STRUCT COLOR_STRUCT
INT r
INT g
INT b
INT a
ENDSTRUCT
STRUCT ANGLED_AREA
VECTOR vPosition[2]
FLOAT fWidth
ENDSTRUCT
//----------------------
// CONST
//----------------------
CONST_INT ONE_MINUTE 60000
CONST_INT REQUEST_TIMEOUT 7500
CONST_INT MAX_PASSENGERS_IN_VEHICLE 16 // MAX_VEHICLE_SEATS=16 in VehicleDefines.h
//----------------------
// VARIABLES
//----------------------
INT iMissionDebugTime
BOOL bShowDebugMissionTime
INT iCurrentGameTime
//----------------------
// INTERP FUNCS
//-----------------------
/// PURPOSE:
/// Oscillates a Value using a sine wave
/// PARAMS:
/// ang - this is the value we use as the oscilator
/// t - the period of the oscilation
/// RETURNS:
/// Oscilated value
FUNC FLOAT SINE_OSCILLATOR(FLOAT &ang, FLOAT t)
ang += ((360.0 * GET_FRAME_TIME()) / t)
IF (ang > 360.0)
ang -= 360.0
ENDIF
RETURN SIN(ang)
ENDFUNC
/// PURPOSE:
/// Oscillates a Value using a sine wave
/// PARAMS:
/// ang - this is the value we use as the oscilator
/// t - the period of the oscilation
/// RETURNS:
/// Oscilated value
FUNC FLOAT COSINE_OSCILLATOR(FLOAT &ang, FLOAT t)
ang += ((360.0 * GET_FRAME_TIME()) / t)
IF (ang > 360.0)
ang -= 360.0
ENDIF
RETURN COS(ang)
ENDFUNC
/// PURPOSE:
/// To Linearly Interpolate 2 Ints
/// PARAM
/// i1 - Source Int
/// i2 - Target Int
/// t - how far you want to interpolate (0 = i1, 1 = t2)
/// RETURNS:
/// An int with the interpolated value
FUNC INT INTERPOLATE_INT(INT i1, INT i2, FLOAT t)
INT out
FLOAT f = TO_FLOAT(i1) + ((TO_FLOAT(i2 - i1)) * t)
out = CEIL(f)
IF (out < i1)
out = i1
ENDIF
IF (out > i2)
out = i2
ENDIF
RETURN out
ENDFUNC
FUNC FLOAT INTERPOLATE_FLOAT(FLOAT f1, FLOAT f2, FLOAT t, BOOL bClamp = TRUE)
IF (bClamp)
t = CLAMP(t, 0, 1)
ENDIF
RETURN f1 + (t * (f2 - f1))
ENDFUNC
/// PURPOSE:
/// To Linearly Interpolate 2 Vectors
/// PARAM
/// i1 - Source Vector
/// i2 - Target Vector
/// t - how far you want to interpolate (0 = i1, 1 = t2)
/// RETURNS:
/// A vector with the interpolated value
FUNC VECTOR INTERPOLATE_VECTOR(VECTOR v1, VECTOR v2, FLOAT t, BOOL bClamp = TRUE)
IF (bClamp)
t = CLAMP(t, 0, 1)
ENDIF
RETURN v1 + (t * (v2 - v1))
ENDFUNC
FUNC INT FSGN(FLOAT f)
IF (f < 0.0)
RETURN -1
ELSE
RETURN 1
ENDIF
ENDFUNC
//----------------------
// AREA FUNCS
//-----------------------
/// PURPOSE:
/// Sets up an Angled Area Struct
/// PARAM
/// a - Area Reference
/// v1 - Area Point 1
/// v2 - Area Point 2
/// w - Width of the area
PROC SET_ANGLED_AREA(ANGLED_AREA &a, VECTOR v1, VECTOR v2, FLOAT w)
a.vPosition[0] = v1
a.vPosition[1] = v2
a.fWidth = w
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Creates and Angled Area Debug Widget
PROC SETUP_ANGLED_AREA_DEBUG_WIDGET(ANGLED_AREA &area, STRING nme, INT idx = -1)
TEXT_LABEL sLabel = nme
IF (idx >= 0)
sLabel += idx
ENDIF
START_WIDGET_GROUP(sLabel)
ADD_WIDGET_VECTOR_SLIDER("Point 1", area.vPosition[0], -5000.0, 5000.0, 10.0)
ADD_WIDGET_VECTOR_SLIDER("Point 2", area.vPosition[1], -5000.0, 5000.0, 10.0)
ADD_WIDGET_FLOAT_SLIDER("Width", area.fWidth, 0.0, 200.0, 0.1)
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
///
/// PARAMS:
/// model_name -
/// AUTHOR: alwyn.roberts@rockstarnorth.com
/// COMMENTS:
PROC ADD_WIDGET_READ_ONLY_VECTOR(STRING name, VECTOR &pos_to_change)
TEXT_LABEL_63 slider_name = name
slider_name += " x"
ADD_WIDGET_FLOAT_READ_ONLY(slider_name, pos_to_change.x)
slider_name = name
slider_name += " y"
ADD_WIDGET_FLOAT_READ_ONLY(slider_name, pos_to_change.y)
slider_name = name
slider_name += " z"
ADD_WIDGET_FLOAT_READ_ONLY(slider_name, pos_to_change.z)
ENDPROC
#ENDIF
//----------------------
// COLOR FUNCS
//-----------------------
/// PURPOSE:
/// Populates a color struct
/// PARAMS:
/// col - color struct reference
/// r - red component (0 - 255)
/// g - green component (0 - 255)
/// b - blue component (0 - 255)
/// a - alpha component (0 - 255)
PROC SET_COLOR_STRUCT(COLOR_STRUCT &col, INT r, INT g, INT b, INT a)
col.r = r
col.g = g
col.b = b
col.a = a
ENDPROC
/// PURPOSE:
/// To Linearly Interpolate 2 Color
/// PARAM
/// i1 - Source Color
/// i2 - Target Color
/// t - how far you want to interpolate (0 = i1, 1 = t2)
/// RETURNS:
/// A Color Struct with the interpolated value
FUNC COLOR_STRUCT INTERPOLATE_COLOR_STRUCT(COLOR_STRUCT src, COLOR_STRUCT des, FLOAT t)
COLOR_STRUCT out
out.r = INTERPOLATE_INT(src.r, des.r, t)
out.g = INTERPOLATE_INT(src.g, des.g, t)
out.b = INTERPOLATE_INT(src.b, des.b, t)
out.a = INTERPOLATE_INT(src.a, des.a, t)
RETURN out
ENDFUNC
//----------------------
// ENTITY FUNCS
//-----------------------
/// PURPOSE:
/// Sets the alpha on a ped
/// PARAMS:
/// ind - ped index
/// val - value for 0 to 255
/// ac - alpha counter if this gets over 8 - it won't set alpha
PROC SET_PED_ALPHA(PED_INDEX ind, INT val, INT &ac)
IF (ac >= 8)
EXIT
ENDIF
SET_ENTITY_ALPHA(ind, val, FALSE)
ac ++
ENDPROC
/// PURPOSE:
/// Sets the alpha on a ped
/// PARAMS:
/// ind - ped index
/// val - value for 0 to 255
/// ac - alpha counter if this gets over 8 - it won't set alpha
PROC SET_VEHICLE_ALPHA(VEHICLE_INDEX ind, INT val, INT &ac)
IF (ac >= 8)
EXIT
ENDIF
SET_ENTITY_ALPHA(ind, val, FALSE)
ac ++
ENDPROC
/// PURPOSE:
/// Check if an entity exists and is alive
FUNC BOOL IS_ENTITY_OK(ENTITY_INDEX ent)
IF NOT DOES_ENTITY_EXIST(ent)
RETURN FALSE
ENDIF
RETURN NOT IS_ENTITY_DEAD(ent)
ENDFUNC
FUNC BOOL IS_PLAYER_UPRIGHT()
// check vehicle is upright
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VEHICLE_INDEX veh = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
RETURN IS_ENTITY_UPRIGHT(veh)
ENDIF
RETURN IS_ENTITY_UPRIGHT(PLAYER_PED_ID())
ENDFUNC
/// PURPOSE:
/// Gets Ratio Of Ped Health
/// PARAMS:
/// ped -
/// RETURNS:
/// 1.0 if at full hp
FUNC FLOAT GET_PED_HEALTH_RATIO(PED_INDEX ped)
IF NOT IS_ENTITY_OK(ped)
RETURN 0.0
ENDIF
RETURN TO_FLOAT(GET_ENTITY_HEALTH(ped)) / TO_FLOAT(GET_PED_MAX_HEALTH(ped))
ENDFUNC
/// PURPOSE:
/// Creates a fake weapon for the player to drop
/// Be aware calling this will remove all the player's actual weapons
/// PARAMS:
/// wpn - the weapontype of the weapon to drop
/// bLeftHand - set this to true to put weapon in left hand
/// RETURNS:
/// Object Index of the fake weapon - you need to call DETACH_ENTITY on this object 1 frame later to drop it
FUNC OBJECT_INDEX CREATE_FAKE_WEAPON_FOR_PLAYER(WEAPON_TYPE wpn, BOOL bLeftHand = FALSE)
OBJECT_INDEX obj
PED_BONETAG bonehand = BONETAG_PH_R_HAND
// if the player is dead - bail and return nothing
IF NOT IS_ENTITY_OK(PLAYER_PED_ID())
RETURN NULL
ENDIF
// sanity check to make sure people aren't trying to create stupid things
IF (wpn = WEAPONTYPE_INVALID) OR (wpn = WEAPONTYPE_UNARMED)
RETURN NULL
ENDIF
// just incase we want the left hand (why as left handed people are evil...)
IF (bLeftHand = TRUE)
bonehand = BONETAG_PH_L_HAND
ENDIF
// remove and create weapon
REMOVE_ALL_PED_WEAPONS(PLAYER_PED_ID())
obj = CREATE_OBJECT_NO_OFFSET(GET_WEAPONTYPE_MODEL(wpn), GET_PED_BONE_COORDS(PLAYER_PED_ID(), bonehand, <<0, 0, 0>>))
IF NOT DOES_ENTITY_EXIST(obj)
RETURN NULL
ENDIF
// attach weapon and finalize
ATTACH_ENTITY_TO_ENTITY(obj, PLAYER_PED_ID(), GET_PED_BONE_INDEX(PLAYER_PED_ID(), bonehand), <<0, 0, 0>>, <<0, 0, 0>>)
RETURN obj
ENDFUNC
PROC SAFE_REMOVE_PARTICLE_FX(PTFX_ID &id)
IF (id <> NULL)
// also stop it if it is looped
IF DOES_PARTICLE_FX_LOOPED_EXIST(id)
STOP_PARTICLE_FX_LOOPED(id)
ELSE
REMOVE_PARTICLE_FX(id)
ENDIF
id = NULL
ENDIF
ENDPROC
//----------------------
// LINE FUNCS
//-----------------------
FUNC BOOL IS_DIRECTION_WITHIN_DEGRESS_OF_DESIRED_DIRECTION(VECTOR fwd, VECTOR ddir, FLOAT angle)
RETURN ACOS(ABSF(DOT_PRODUCT(ddir, fwd))) <= angle
ENDFUNC
FUNC BOOL IS_DIRECTION_WITHIN_DEGRESS_OF_DESIRED_DIRECTION_2D(VECTOR fwd, VECTOR ddir, FLOAT angle)
RETURN ACOS(ABSF(DOT_PRODUCT(ddir, fwd))) <= angle
ENDFUNC
FUNC BOOL IS_DIRECTION_WITHIN_DEGRESS_OF_DESIRED_DIRECTION_SIGNED(VECTOR fwd, VECTOR ddir, FLOAT angle)
RETURN ACOS(DOT_PRODUCT(ddir, fwd)) <= angle
ENDFUNC
/// PURPOSE:
/// Check if an entity is range m from a position in 2d
/// PARAMS:
/// ent - Entity
/// pos - Position
/// range - distance we want to check
FUNC BOOL IS_ENTITY_IN_RANGE_COORDS_2D(ENTITY_INDEX ent, VECTOR pos, FLOAT range)
VECTOR ve = GET_ENTITY_COORDS(ent)
VECTOR v = pos - ve
RETURN ((v.x * v.x) + (v.y * v.y)) <= (range * range)
ENDFUNC
/// PURPOSE:
/// Calculates the length a line between 2 points
/// PARAMS:
/// stt - Line Start
/// end - Line End
/// RETURNS:
/// Length of Line
FUNC FLOAT GET_LINE_MAGNITUDE(VECTOR stt, VECTOR end)
VECTOR v = end - stt
RETURN SQRT(v.x * v.x + v.y * v.y + v.z * v.z)
ENDFUNC
/// PURPOSE:
/// Calculates the Squared length a line between 2 points
/// PARAMS:
/// stt - Line Start
/// end - Line End
/// RETURNS:
/// Squared Length of Line
FUNC FLOAT GET_LINE_MAGNITUDE_SQUARED(VECTOR stt, VECTOR end)
VECTOR v = end - stt
RETURN (v.x * v.x + v.y * v.y + v.z * v.z)
ENDFUNC
/// PURPOSE:
/// Gets the closest point on a line and the interpolate value
/// PARAMS:
/// p - point we want to check how close to the line it is
/// vStart - line Start
/// vEnd - line End
/// bClamp - do we clamp this to the end points
/// RETURNS:
/// Returns the closest point
//FUNC VECTOR GET_CLOSEST_POINT_ON_LINE(VECTOR p, VECTOR vStart, VECTOR vEnd, BOOL bClamp = TRUE)
// VECTOR diff = (vEnd - vStart)
// FLOAT u = GET_RATIO_OF_CLOSEST_POINT_ON_LINE(p, vStart, vEnd, bClamp)
// RETURN vStart + (u * diff)
//ENDFUNC
/// PURPOSE:
/// Gets the closest point on a plane to a position
/// PARAMS:
/// in - point we want to check how close to the plane
/// pNorm - plane normal
/// pOrg - plane origin
/// RETURNS:
/// Returns the closest point on plane
FUNC VECTOR GET_CLOSEST_POINT_ON_PLANE(VECTOR in, VECTOR pNorm, VECTOR pOrg)
FLOAT D = DOT_PRODUCT(pNorm, pOrg)
FLOAT t = DOT_PRODUCT(pNorm, in) - D
RETURN in - (t * pNorm)
ENDFUNC
/// PURPOSE:
/// Gets the distance from an infinite plane to a point
/// PARAMS:
/// in - point we want to check how close to the plane
/// pNorm - plane normal
/// pOrg - plane origin
/// RETURNS:
/// Returns the distance to closest point on plane
FUNC FLOAT GET_DISTANCE_TO_PLANE(VECTOR in, VECTOR pNorm, VECTOR pOrg)
FLOAT D = DOT_PRODUCT(pNorm, pOrg)
FLOAT t = DOT_PRODUCT(pNorm, in) - D
RETURN t / DOT_PRODUCT(pNorm, pNorm)
ENDFUNC
/// PURPOSE:
/// Tells what side of a plane a point is on
/// PARAMS:
/// pNorm - plane normal
/// pOrg - plane origin
/// v - point we want to check
/// RETURNS:
/// Returns -1 if behind plane, +1 if in front and 0 if on plane
FUNC PLANE_SIDE GET_PLANE_SIDE(VECTOR pNorm, VECTOR pOrg, VECTOR v)
FLOAT dot = DOT_PRODUCT(v - pOrg, pNorm)
IF (dot < 0)
RETURN BEHIND_PLANE
ELIF (dot > 0)
RETURN INFRONT_PLANE
ENDIF
RETURN ON_PLANE
ENDFUNC
/// PURPOSE:
/// Tells where on an infinite plane a given line will intersect
/// PARAMS:
/// out - position where line will intersect (this is overwritten)
/// p1 - line start
/// p2 - lien end
/// pNorm - plane normal
/// pOrg - plane origin
/// RETURNS:
/// If this returns false the line will never touch the plane
FUNC BOOL GET_LINE_PLANE_INTERSECT(VECTOR &out, VECTOR p1, VECTOR p2, VECTOR pNorm, VECTOR pOrg)
VECTOR u = p2 - p1
VECTOR w = p1 - pOrg
FLOAT D = DOT_PRODUCT(pNorm, u)
FLOAT N = -DOT_PRODUCT(pNorm, w)
FLOAT SI
// line is either parallel or doesn't intersect
IF (ABSF(D) < 0.00000001)
RETURN FALSE
ENDIF
SI = N / D
out = p1 + (SI * u)
// no intersection
IF (SI < 0) OR (SI > 1)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Tells whether a line and sphere will intersect
/// PARAMS:
/// p1 - line start
/// p2 - lien end
/// sc - sphere center
/// r - sphere radius
/// RETURNS:
/// If this returns false the line will never touch the sphere
FUNC BOOL DOES_LINE_SPHERE_INTERSECT(VECTOR p1, VECTOR p2, VECTOR sc, FLOAT r)
FLOAT a,b,c
FLOAT bb4ac
VECTOR dp
// horrible vector stuff - i didn't quite understand at school
// i'll simplfy and comment this properly later
dp = p2 - p1
a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z
b = 2 * (dp.x * (p1.x - sc.x) + dp.y * (p1.y - sc.y) + dp.z * (p1.z - sc.z))
c = sc.x * sc.x + sc.y * sc.y + sc.z * sc.z
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z
c -= 2 * (sc.x * p1.x + sc.y * p1.y + sc.z * p1.z)
c -= r * r
bb4ac = b * b - 4 * a * c
IF (ABSF(a) < 0.00001) OR (bb4ac <= 0.0)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Gets Heading given 2 coords
/// PARAMS:
/// oldCoords - source point
/// newCoords - target point
/// invert - this is true (just keep it as true)
/// RETURNS:
/// Heading
FUNC FLOAT GET_HEADING_FROM_COORDS(vector oldCoords,vector newCoords, bool invert=true)
float heading
float dX = newCoords.x - oldCoords.x
float dY = newCoords.y - oldCoords.y
if dY != 0
heading = ATAN2(dX,dY)
ELSE
if dX < 0
heading = -90
ELSE
heading = 90
ENDIF
ENDIF
//flip because for some odd reason the coders think west is a heading of 90 degrees, so this'll match the output of commands such as GET_ENTITY_HEADING()
IF invert = TRUE
heading *= -1.0
//below not necessary but helps for debugging
IF heading < 0
heading += 360.0
ENDIF
ENDIF
RETURN heading
ENDFUNC
/// PURPOSE:
/// Gets Heading from 1 entity to another
/// PARAMS:
/// oldEnd - source entity
/// newEnd - target entity
/// invert - this is true (just keep it as true)
/// RETURNS:
/// Heading
FUNC FLOAT GET_HEADING_FROM_ENTITIES(entity_index oldEnd, entity_index newEnt, bool invert=true)
vector v1,v2
v1 = GET_ENTITY_COORDS(oldEnd,FALSE)
v2 = GET_ENTITY_COORDS(newEnt,FALSE)
RETURN GET_HEADING_FROM_COORDS(v1,v2, invert)
ENDFUNC
/// PURPOSE:
/// Gets Pitch and Heading from a direction vector
/// PARAMS:
/// dir - direction vector
/// pitch - returned pitch
/// head - returned heading
/// invert - this is true (just keep it as true)
PROC GET_PITCH_AND_HEADING_FROM_DIRECTION_VECTOR(VECTOR dir, FLOAT &pitch, FLOAT &head, bool invert=true)
float sq
if dir.y != 0
head = ATAN2(dir.x, dir.y)
ELSE
if dir.x < 0
head = -90
ELSE
head = 90
ENDIF
ENDIF
//flip because for some odd reason the coders think west is a heading of 90 degrees, so this'll match the output of commands such as GET_ENTITY_HEADING()
IF invert = TRUE
head *= -1.0
//below not necessary but helps for debugging
IF head < 0
head += 360.0
ENDIF
ENDIF
// now do pitch
sq = SQRT((dir.x * dir.x) + (dir.y * dir.y))
IF (sq != 0)
pitch = ATAN2(dir.z, sq)
ELSE
IF (dir.z < 0)
pitch = -90
ELSE
pitch = 90
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Gets Pitch and Heading from 1 entity to another
/// PARAMS:
/// oldCoords - source point
/// newCoords - target point
/// pitch - returned pitch
/// head - returned heading
/// invert - this is true (just keep it as true)
PROC GET_PITCH_AND_HEADING_FROM_COORDS(VECTOR oldCoords, VECTOR newCoords, FLOAT &pitch, FLOAT &head, bool invert=true)
VECTOR diff = newCoords - oldCoords
GET_PITCH_AND_HEADING_FROM_DIRECTION_VECTOR(diff, pitch, head, invert)
ENDPROC
/// PURPOSE:
/// Gets Pitch given 2 coords
/// PARAMS:
/// oldCoords - source point
/// newCoords - target point
/// RETURNS:
/// Pitch
FUNC FLOAT GET_PITCH_FROM_COORDS(vector oldCoords,vector newCoords)
float pitch
float dX = newCoords.z - oldCoords.z
float dY = newCoords.y - oldCoords.y
float dZ = newCoords.z - oldCoords.z
float sq
// now do pitch
sq = SQRT((dx * dx) + (dy * dy))
IF (sq != 0)
pitch = ATAN2(dZ, sq)
ELSE
IF (dZ < 0)
pitch = -90
ELSE
pitch = 90
ENDIF
ENDIF
RETURN pitch
ENDFUNC
/// PURPOSE:
/// Is Sphere Occupied - Just an override for IS_AREA_OCCUPIED that takes into account spheres
/// PARAMS:
/// v - sphere center
/// r - sphere radius
/// RETURNS:
FUNC BOOL IS_SPHERE_OCCUPIED(VECTOR v, FLOAT r, BOOL bBuildingFlag, BOOL bVehicleFlag, BOOL bPedFlag, BOOL bObjectFlag, BOOL bDummyFlag, ENTITY_INDEX ExcludeEntityIndex = NULL, BOOL bCheckAlive = FALSE)
//RETURN IS_AREA_OCCUPIED(v - <<r, r, r>>, v + <<r, r, r>>, bBuildingFlag, bVehicleFlag, bPedFlag, bObjectFlag, bDummyFlag, ExcludeEntityIndex, bCheckAlive)
RETURN IS_POSITION_OCCUPIED(v, r, bBuildingFlag, bVehicleFlag, bPedFlag, bObjectFlag, bDummyFlag, ExcludeEntityIndex, bCheckAlive)
ENDFUNC
/// PURPOSE:
/// Just an override for IS_AREA_OCCUPIED that takes into account spheres and only checks for peds
/// PARAMS:
/// v - sphere center
/// r - sphere radius
FUNC BOOL IS_ANY_PED_IN_SPHERE(VECTOR v, FLOAT r, ENTITY_INDEX ExcludeEntityIndex = NULL, BOOL bCheckAlive = TRUE)
RETURN IS_POSITION_OCCUPIED(v, r, FALSE, FALSE, TRUE, FALSE, FALSE, ExcludeEntityIndex, bCheckAlive)
ENDFUNC
//----------------------
// MISC FUNCS
//-----------------------
/// PURPOSE:
/// Enables or Disables all Dispatch Services
/// PARAMS:
/// ok - set true to turn them on
PROC ENABLE_ALL_DISPATCH_SERVICES(BOOL ok = TRUE)
ENABLE_DISPATCH_SERVICE(DT_POLICE_HELICOPTER, ok)
ENABLE_DISPATCH_SERVICE(DT_FIRE_DEPARTMENT, ok)
ENABLE_DISPATCH_SERVICE(DT_SWAT_AUTOMOBILE, ok)
ENABLE_DISPATCH_SERVICE(DT_AMBULANCE_DEPARTMENT, ok)
ENABLE_DISPATCH_SERVICE(DT_POLICE_RIDERS, ok)
ENABLE_DISPATCH_SERVICE(DT_POLICE_VEHICLE_REQUEST, ok)
ENABLE_DISPATCH_SERVICE(DT_POLICE_ROAD_BLOCK, ok)
ENABLE_DISPATCH_SERVICE(DT_POLICE_AUTOMOBILE_WAIT_PULLED_OVER, ok)
ENABLE_DISPATCH_SERVICE(DT_POLICE_AUTOMOBILE_WAIT_CRUISING, ok)
ENABLE_DISPATCH_SERVICE(DT_GANGS, ok)
ENABLE_DISPATCH_SERVICE(DT_SWAT_HELICOPTER, ok)
ENDPROC
/// PURPOSE:
/// Enables or Disables all Ambient Cars and Peds
/// PARAMS:
/// pedok - set true to turn peds on
/// carok - set true to turn cars on
PROC ENABLE_AMBIENT_PEDS_AND_VEHICLES(BOOL pedok = TRUE, BOOL carok = TRUE, BOOL clearpeds = FALSE, BOOL clearcars = FALSE)
IF (pedok = TRUE)
SET_PED_POPULATION_BUDGET(1)
SET_PED_DENSITY_MULTIPLIER_THIS_FRAME(1)
SET_SCENARIO_PED_DENSITY_MULTIPLIER_THIS_FRAME(1, 1)
ELSE
SET_PED_POPULATION_BUDGET(0)
SET_PED_DENSITY_MULTIPLIER_THIS_FRAME(0)
SET_SCENARIO_PED_DENSITY_MULTIPLIER_THIS_FRAME(0, 0)
ENDIF
IF (carok = TRUE)
SET_VEHICLE_POPULATION_BUDGET(1)
SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(1)
SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(1)
ELSE
SET_VEHICLE_POPULATION_BUDGET(0)
SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0)
SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0)
ENDIF
IF IS_ENTITY_OK(PLAYER_PED_ID())
IF clearpeds = TRUE
CLEAR_AREA_OF_PEDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100.0)
ENDIF
IF clearcars = TRUE
CLEAR_AREA_OF_VEHICLES(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100.0)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Draw a circle in debug mode
/// PARAMS:
/// center - circle center
/// radius - circle radius
/// r, g, b, a - red/green/blue/alpha components
/// sides - how smooth the circle is
PROC DRAW_DEBUG_CIRCLE(VECTOR center, FLOAT radius, INT r = 0, INT g = 0, INT b = 255, INT a = 255, INT sides = 32)
INT i
FLOAT ainc = 360.0 / TO_FLOAT(sides)
VECTOR lastpos = center
VECTOR nextpos = center
FLOAT angle = 0
lastpos = center
lastpos.x += (SIN(angle - ainc) * radius)
lastpos.y += (COS(angle - ainc) * radius)
FOR i = 0 TO sides
nextpos = center
nextpos.x += (SIN(angle) * radius)
nextpos.y += (COS(angle) * radius)
DRAW_DEBUG_LINE(lastpos, nextpos, r, g, b, a)
lastpos = nextpos
angle += ainc
ENDFOR
ENDPROC
PROC DRAW_DEBUG_CYLINDER(VECTOR center, FLOAT radius, FLOAT height, INT r = 0, INT g = 0, INT b = 255, INT a = 255, INT sides = 32)
INT i
FLOAT ainc = 360.0 / TO_FLOAT(sides)
VECTOR lastpos = center
VECTOR nextpos = center
FLOAT angle = 0
lastpos = center
lastpos.x += (SIN(angle - ainc) * radius)
lastpos.y += (COS(angle - ainc) * radius)
FOR i = 0 TO sides
nextpos = center
nextpos.x += (SIN(angle) * radius)
nextpos.y += (COS(angle) * radius)
DRAW_DEBUG_LINE(lastpos, nextpos, r, g, b, a)
DRAW_DEBUG_LINE(lastpos + <<0, 0, height>>, nextpos + <<0, 0, height>>, r, g, b, a)
DRAW_DEBUG_LINE(lastpos + <<0, 0, height / 2.0>>, nextpos + <<0, 0, height / 2.0>>, r, g, b, a)
DRAW_DEBUG_LINE(nextpos, nextpos + <<0, 0, height>>, r, g, b, a)
lastpos = nextpos
angle += ainc
ENDFOR
ENDPROC
/// PURPOSE:
/// Draw a circle in debug mode but on the XZ plane (vertically)
/// PARAMS:
/// center - circle center
/// radius - circle radius
/// r, g, b, a - red/green/blue/alpha components
/// sides - how smooth the circle is
PROC DRAW_DEBUG_CIRCLE_VERTICAL(VECTOR center, FLOAT radius, INT r = 0, INT g = 0, INT b = 255, INT a = 255, INT sides = 16)
INT i
FLOAT ainc = 360.0 / TO_FLOAT(sides)
VECTOR lastpos = center
VECTOR nextpos = center
FLOAT angle = 0
lastpos = center
lastpos.x += (SIN(angle - ainc) * radius)
lastpos.z += (COS(angle - ainc) * radius)
FOR i = 0 TO sides
nextpos = center
nextpos.x += (SIN(angle) * radius)
nextpos.z += (COS(angle) * radius)
DRAW_DEBUG_LINE(lastpos, nextpos, r, g, b, a)
lastpos = nextpos
angle += ainc
ENDFOR
ENDPROC
/// PURPOSE:
/// Draw an area in debug mode
/// PARAMS:
/// p1 - area point 1
/// p2 - area point 2
/// width - area width
/// r, g, b, a - red/green/blue/alpha components
PROC DRAW_DEBUG_AREA(VECTOR p1, VECTOR p2, FLOAT width, INT r = 0, INT g = 0, INT b = 255, INT a = 255)
IF (width = 0)
EXIT
ENDIF
VECTOR fwd = NORMALISE_VECTOR(p2 - p1)
VECTOR rt = CROSS_PRODUCT(fwd, <<0, 0, 1>>)
FLOAT w = width / 2.0
VECTOR pa, pb
VECTOR p[8]
INT i
pa = p1
pb = p2
pb.z = p1.z
// draw base
p[0] = pa - (rt * w)
p[1] = pa + (rt * w)
p[2] = pb + (rt * w)
p[3] = pb - (rt * w)
DRAW_DEBUG_LINE(p[0], p[1], r, g, b, a)
DRAW_DEBUG_LINE(p[1], p[2], r, g, b, a)
DRAW_DEBUG_LINE(p[2], p[3], r, g, b, a)
DRAW_DEBUG_LINE(p[3], p[0], r, g, b, a)
// draw top
FOR i = 0 TO 3
p[4 + i] = p[i]
p[4 + i].z = p2.z
ENDFOR
DRAW_DEBUG_LINE(p[4], p[5], r, g, b, a)
DRAW_DEBUG_LINE(p[5], p[6], r, g, b, a)
DRAW_DEBUG_LINE(p[6], p[7], r, g, b, a)
DRAW_DEBUG_LINE(p[7], p[4], r, g, b, a)
// draw connecting bits
DRAW_DEBUG_LINE(p[0], p[4], r, g, b, a)
DRAW_DEBUG_LINE(p[1], p[5], r, g, b, a)
DRAW_DEBUG_LINE(p[2], p[6], r, g, b, a)
DRAW_DEBUG_LINE(p[3], p[7], r, g, b, a)
ENDPROC
/// PURPOSE:
/// Draw an area in debug mode
/// PARAMS:
/// area - angled area
/// r, g, b, a - red/green/blue/alpha components
PROC DEBUG_DRAW_ANGLED_AREA_EX(ANGLED_AREA &area, INT r = 0, INT g = 0, INT b = 255, INT a = 255)
DRAW_DEBUG_AREA(area.vPosition[0], area.vPosition[1], area.fWidth, r, g, b, a)
ENDPROC
/// PURPOSE:
/// Draw lines in vector array from one vector to another
/// PARAMS:
/// area - angled area
/// r, g, b, a - red/green/blue/alpha components
PROC DRAW_DEBUG_VECTOR_ARRAY(VECTOR &array[], INT nPoints, INT r = 0, INT g = 0, INT b = 255, INT a = 255)
INT i
IF (nPoints > COUNT_OF(array))
nPoints = COUNT_OF(array)
ENDIF
REPEAT nPoints i
IF (i > 0)
DRAW_DEBUG_LINE(array[i], array[i - 1], r, g, b, a)
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Works out minimum and maximum given a point and an axis aligned box size
/// PARAMS:
/// center - box center
/// size - box 3size
/// min - returned minimum point
/// max - returned maximum point
PROC CALCULATE_MIN_MAX_FROM_POSITION_AND_DIMENSIONS(VECTOR center, VECTOR size, VECTOR &min, VECTOR &max)
VECTOR halfsize = size / 2.0
min = center - halfsize
max = center + halfsize
ENDPROC
/// PURPOSE:
/// Works out minimum and maximum given a point and radius
/// PARAMS:
/// center - sphere center
/// radius - sphere radius
/// min - returned minimum point
/// max - returned maximum point
PROC CALCULATE_MIN_MAX_FROM_POSITION_AND_RADIUS(VECTOR center, FLOAT radius, VECTOR &min, VECTOR &max)
VECTOR halfsize = <<radius, radius, radius>>
min = center - halfsize
max = center + halfsize
ENDPROC
/// PURPOSE:
/// Expands an angled area by an amount and returns the expanded version
/// PARAMS:
/// a - area to expand
/// exp - expand amount
FUNC ANGLED_AREA EXPAND_ANGLED_AREA(ANGLED_AREA a, FLOAT exp = 1.0)
ANGLED_AREA aOut
VECTOR vNormal = NORMALISE_VECTOR(a.vPosition[1] - a.vPosition[0]) * exp
aOut.vPosition[0] = a.vPosition[0] - vNormal
aOut.vPosition[1] = a.vPosition[1] + vNormal
aOut.fWidth = a.fWidth + (exp * 2.0)
RETURN aOut
ENDFUNC
FUNC VECTOR GET_ANGLED_AREA_CENTER(ANGLED_AREA a)
RETURN INTERPOLATE_VECTOR(a.vPosition[0], a.vPosition[1], 0.5)
ENDFUNC
/// PURPOSE:
/// IS_ENTITY_IN_ANGLED_AREA only checks if the point is the area this checks the extents
/// RETURNS:
///
FUNC BOOL IS_ENTITY_IN_ANGLED_AREA_COMPLEX(ENTITY_INDEX ent, VECTOR v1, VECTOR v2, FLOAT w)
VECTOR v
VECTOR vmin, vmax
IF IS_ENTITY_IN_ANGLED_AREA(ent, v1, v2, w)
RETURN TRUE
ENDIF
IF IS_ENTITY_A_PED(ent)
RETURN FALSE
ENDIF
// only do this over the top check for not peds
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(ent), vmin, vmax)
// check front left
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<vmin.x, vmax.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
// check front
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<0, vmax.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
// check front right
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<vmax.x, vmax.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
// check back left
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<vmin.x, vmin.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
// check back
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<0, vmin.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
// check back right
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ent, <<vmax.x, vmin.y, 0.0>>)
IF IS_POINT_IN_ANGLED_AREA(v, v1, v2, w)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Converts Milliseconds into minutes, seconds and tenths
/// PARAMS:
/// iTotal - time to convert
/// mins - returned minutes
/// secs - returned secs
/// ths - returned tenths of secs
PROC CONVERT_INT_TO_TIME(INT iTotal, INT& mins, INT &secs, INT &ths)
iTotal = ABSI(iTotal)
// this looks broken to me... look at this later
mins = (iTotal - (iTotal % ONE_MINUTE)) / ONE_MINUTE
secs = (iTotal % ONE_MINUTE) / 1000
ths = (iTotal % 1000) / 100
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "Time Convereted:", iTotal, " = ", mins, ":", secs, ".", ths)
#ENDIF
/*
mins = (iTotal / 1000) / 60
secs = (iTotal - (mins * 60 * 1000)) / 1000
ths = (iTotal - ((secs + (mins * 60)) * 1000))
ths /= 100
IF (ths > 9)
ths = 9
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "Time Convereted:", iTotal, " = ", mins, ":", secs, ".", ths)
#ENDIF
*/
ENDPROC
/// PURPOSE:
/// Releases a sound safely and zeros it's reference
/// PARAMS:
/// snd - sound index reference
PROC SAFE_STOP_AND_RELEASE_SOUND_ID(INT &snd)
IF (snd <> -1)
STOP_SOUND(snd)
RELEASE_SOUND_ID(snd)
snd = -1
ENDIF
ENDPROC
/// PURPOSE:
/// Places an entity on the floor
/// PARAMS:
/// pos - new position
/// RETURNS:
/// new grounded position
FUNC VECTOR SET_ENTITY_COORDS_GROUNDED(ENTITY_INDEX ent, VECTOR pos)
FLOAT z
pos.z += 0.15
IF GET_GROUND_Z_FOR_3D_COORD(pos, z)
pos.z = z
ENDIF
IF IS_ENTITY_OK(ent)
SET_ENTITY_COORDS(ent, pos)
ENDIF
RETURN pos
ENDFUNC
/// PURPOSE:
/// Gets heading entity needs to face the player
/// PARAMS:
/// ent - entity to turn
/// RETURNS:
/// new heading
FUNC FLOAT GET_ENTITY_HEADING_FACE_PLAYER(ENTITY_INDEX ent)
RETURN GET_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), GET_ENTITY_COORDS(PLAYER_PED_ID()), TRUE)
ENDFUNC
/// PURPOSE:
/// Sets entity to face the player
/// PARAMS:
/// ent - entity to turn
PROC SET_ENTITY_HEADING_FACE_PLAYER(ENTITY_INDEX ent)
FLOAT head = GET_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), GET_ENTITY_COORDS(PLAYER_PED_ID()), TRUE)
SET_ENTITY_HEADING(ent, head)
ENDPROC
/// PURPOSE:
/// Sets entity to face a coordinate
/// PARAMS:
/// ent - entity to turn
/// pos - position to face
PROC SET_ENTITY_HEADING_FACE_COORDS(ENTITY_INDEX ent, VECTOR pos)
FLOAT head = GET_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), pos, TRUE)
SET_ENTITY_HEADING(ent, head)
ENDPROC
/// PURPOSE:
/// Sets entity to face an entity
/// PARAMS:
/// ent - entity to turn
/// targent - entity to face
PROC SET_ENTITY_HEADING_FACE_ENTITY(ENTITY_INDEX ent, ENTITY_INDEX targent)
FLOAT head = GET_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), GET_ENTITY_COORDS(targent), TRUE)
SET_ENTITY_HEADING(ent, head)
ENDPROC
/// PURPOSE:
/// Sets entity rotation to face an entity
/// PARAMS:
/// ent - entity to turn
/// target - entity to face
PROC SET_ENTITY_ROTATION_FACE_ENTITY(ENTITY_INDEX ent, ENTITY_INDEX target)
FLOAT pitch
FLOAT head
GET_PITCH_AND_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), GET_ENTITY_COORDS(target), pitch, head, true)
SET_ENTITY_ROTATION(ent, <<pitch, 0, head>>)
ENDPROC
/// PURPOSE:
/// Sets entity rotation to face an coordinate
/// PARAMS:
/// ent - entity to turn
/// target - position to face
PROC SET_ENTITY_ROTATION_FACE_COORDS(ENTITY_INDEX ent, VECTOR target)
FLOAT pitch
FLOAT head
GET_PITCH_AND_HEADING_FROM_COORDS(GET_ENTITY_COORDS(ent), target, pitch, head, true)
SET_ENTITY_ROTATION(ent, <<pitch, 0, head>>)
ENDPROC
/// PURPOSE:
/// Tells us if a waypoint index is on screen or not
/// PARAMS:
/// wayname - waypoint recording name
/// ind - point index in waypoint recording
/// rad - tolerance
FUNC BOOL IS_WAYPOINT_INDEX_POINT_VISIBLE(STRING wayname, INT ind = 0, FLOAT rad = 2.0)
VECTOR pos
// get first and second points so we can point vehicle in right direction
IF NOT WAYPOINT_RECORDING_GET_COORD(wayname, ind, pos)
RETURN TRUE
ENDIF
RETURN IS_SPHERE_VISIBLE(pos, rad)
ENDFUNC
/// PURPOSE:
/// Tells us if a vehicle is ruined
/// PARAMS:
/// vehicleID - vehicle
/// chkfire - set this if we include it being on fire
FUNC BOOL IS_VEHICLE_BRUCK_UP(VEHICLE_INDEX VehicleID, BOOL chkfire = TRUE)
IF NOT IS_ENTITY_OK(VehicleID)
RETURN TRUE
ENDIF
IF (GET_ENTITY_HEALTH(VehicleID) = 0)
RETURN TRUE
ENDIF
IF NOT IS_VEHICLE_DRIVEABLE(VehicleID)
RETURN TRUE
ENDIF
IF (chkfire)
IF IS_ENTITY_ON_FIRE(VehicleID)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//----------------------
// COMBAT PARAM FUNCS
//-----------------------
/// PURPOSE:
/// Applies combat parameters to ped
/// PARAMS:
/// ped - ped index
/// cpm - combat param reference
/// bUseAcc2 - set this to true to use accuracy #2
PROC APPLY_COMBAT_PARAMETERS_TO_PED(PED_INDEX ped, COMBAT_PARAMETERS &cpm, BOOL bUseAcc2 = FALSE)
INT iRnd
SET_PED_CHANCE_OF_FIRING_BLANKS(ped, cpm.fNearBlankChance, cpm.fFarBlankChance)
SET_PED_SHOOT_RATE(ped, GET_RANDOM_INT_IN_RANGE(cpm.iMinShootRate, cpm.iMaxShootRate))
SET_PED_FIRING_PATTERN(ped, cpm.hFiringPattern)
SET_COMBAT_FLOAT(ped, CCF_TIME_BETWEEN_BURSTS_IN_COVER, GET_RANDOM_FLOAT_IN_RANGE(cpm.fMinTimeBetweenCoverBurst, cpm.fMaxTimeBetweenCoverBurst))
SET_COMBAT_FLOAT(ped, CCF_TIME_BETWEEN_PEEKS, GET_RANDOM_FLOAT_IN_RANGE(cpm.fMinTimeBetweenPeeks, cpm.fMaxTimeBetweenPeeks))
SET_COMBAT_FLOAT(ped, CCF_BURST_DURATION_IN_COVER, GET_RANDOM_FLOAT_IN_RANGE(cpm.fMinBurstDurationTime, cpm.fMaxBurstDurationTime))
//SET_PED_TARGET_LOSS_RESPONSE(ped, TLR_NEVER_LOSE_TARGET)
IF (bUseAcc2)
SET_COMBAT_FLOAT(ped, CCF_WEAPON_ACCURACY, cpm.fWeaponAccuracy2)
ELSE
SET_COMBAT_FLOAT(ped, CCF_WEAPON_ACCURACY, cpm.fWeaponAccuracy1)
ENDIF
SET_PLAYER_WEAPON_DAMAGE_MODIFIER(PLAYER_ID(), cpm.fPlayerWeaponDamageModifier)
SET_PLAYER_WEAPON_DEFENSE_MODIFIER(PLAYER_ID(), cpm.fPlayerWeaponDefenseModifier)
SET_PLAYER_MELEE_WEAPON_DEFENSE_MODIFIER(PLAYER_ID(), cpm.fPlayerMeleeWeaponDefenseModifier)
SET_PED_COMBAT_ATTRIBUTES(ped, CA_AGGRESSIVE, GET_RANDOM_FLOAT_IN_RANGE() < cpm.fAgressionChance)
SET_PED_COMBAT_ATTRIBUTES(ped, CA_CAN_FLANK, GET_RANDOM_FLOAT_IN_RANGE() < cpm.fFlankChance)
SET_PED_COMBAT_ATTRIBUTES(ped, CA_JUST_SEEK_COVER, GET_RANDOM_FLOAT_IN_RANGE() < cpm.fCoverOnlyChance)
// combat range
IF (cpm.iForcedCombatRange <> -1)
iRnd = cpm.iForcedCombatRange
ELSE
iRnd = GET_RANDOM_INT_IN_RANGE(0, 3)
ENDIF
SWITCH (iRnd)
CASE 0
SET_PED_COMBAT_RANGE(ped, CR_NEAR) // Seeks a defensive position.
BREAK
CASE 1
SET_PED_COMBAT_RANGE(ped, CR_MEDIUM) // Will advance forward in combat
BREAK
CASE 2
SET_PED_COMBAT_RANGE(ped, CR_FAR) // Will retreat if the enemy gets too close
BREAK
DEFAULT
SET_PED_COMBAT_RANGE(ped, CR_MEDIUM) // Will advance forward in combat
BREAK
ENDSWITCH
// combat range
IF (cpm.iForcedCombatLevel <> -1)
iRnd = cpm.iForcedCombatLevel
ELSE
iRnd = GET_RANDOM_INT_IN_RANGE(0, 3)
ENDIF
SWITCH (iRnd)
CASE 0
SET_PED_COMBAT_ABILITY(ped, CAL_POOR)
BREAK
CASE 1
SET_PED_COMBAT_ABILITY(ped, CAL_AVERAGE)
BREAK
CASE 2
SET_PED_COMBAT_ABILITY(ped, CAL_PROFESSIONAL)
BREAK
DEFAULT
SET_PED_COMBAT_ABILITY(ped, CAL_AVERAGE)
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Reset combat parameters
/// PARAMS:
/// cpm - combat param reference
PROC RESET_COMBAT_PARAMETERS(COMBAT_PARAMETERS &cpm)
cpm.hFiringPattern = FIRING_PATTERN_DELAY_FIRE_BY_ONE_SEC
cpm.fWeaponAccuracy1 = 0.0325
cpm.fWeaponAccuracy2 = 0.0325
cpm.fNearBlankChance = 0.36 // default in code
cpm.fFarBlankChance = 0.60 // default in code
cpm.fFlankChance = 0.20
cpm.fCoverOnlyChance = 0.0
cpm.fMinTimeBetweenPeeks = 10.0 // default in code
cpm.fMaxTimeBetweenPeeks = 11.0
cpm.fMinTimeBetweenCoverBurst = 1.25 // default in code
cpm.fMaxTimeBetweenCoverBurst = 2.25
cpm.fMinBurstDurationTime = 2.0 // default in code
cpm.fMaxBurstDurationTime = 2.5
cpm.iMinShootRate = 20
cpm.iMaxShootRate = 50
cpm.iForcedCombatLevel = 0
cpm.iForcedCombatRange = -1
cpm.fPlayerWeaponDamageModifier = 1.0
cpm.fPlayerWeaponDefenseModifier = 1.0
cpm.fPlayerMeleeWeaponDefenseModifier = 1.0
cpm.fAgressionChance = 0.5
ENDPROC
/// PURPOSE:
/// Reset combat parameters
/// PARAMS:
/// cpm - combat param reference
/// nme - display name
#IF IS_DEBUG_BUILD
PROC SETUP_COMBAT_PARAMETERS_WIDGET(COMBAT_PARAMETERS &cpm, STRING nme)
START_WIDGET_GROUP(nme)
ADD_WIDGET_FLOAT_SLIDER("Ped Accuracy Weapon 1", cpm.fWeaponAccuracy1, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Ped Accuracy Weapon 2", cpm.fWeaponAccuracy2, 0.0, 1.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Player Weapon Damage Modifier", cpm.fPlayerWeaponDamageModifier, 0.0, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Player Weapon Defense Modifier", cpm.fPlayerWeaponDefenseModifier, 0.0, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Player Melee Weapon Defense Modifier", cpm.fPlayerMeleeWeaponDefenseModifier, 0.0, 5.0, 0.001)
START_WIDGET_GROUP("Chance")
ADD_WIDGET_FLOAT_SLIDER("Agression Chance", cpm.fAgressionChance, 0.0, 1.0, 0.05)
ADD_WIDGET_FLOAT_SLIDER("Near Blank Chance", cpm.fNearBlankChance, 0.0, 1.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Far Blank Chance", cpm.fFarBlankChance, 0.0, 1.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Flank Chance", cpm.fFlankChance, 0.0, 1.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Cover Only Chance", cpm.fCoverOnlyChance, 0.0, 1.0, 0.01)
ADD_WIDGET_INT_SLIDER("Forced Combat Range", cpm.iForcedCombatRange, -1, 2, 1)
ADD_WIDGET_INT_SLIDER("Forced Combat Level", cpm.iForcedCombatLevel, -1, 2, 1)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Rate")
ADD_WIDGET_INT_SLIDER("Min Shoot Rate", cpm.iMinShootRate, 0, 100, 1)
ADD_WIDGET_INT_SLIDER("Max Shoot Rate", cpm.iMaxShootRate, 1, 100, 1)
ADD_WIDGET_FLOAT_SLIDER("Min Time Between Peeks", cpm.fMinTimeBetweenPeeks, 0.0, 60.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Max Time Between Peeks", cpm.fMaxTimeBetweenPeeks, 0.0, 60.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Min Time Between Cover Burst", cpm.fMinTimeBetweenCoverBurst, 0.0, 60.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Max Time Between Cover Burst", cpm.fMaxTimeBetweenCoverBurst, 0.0, 60.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Min Burst Duration Time", cpm.fMinBurstDurationTime, 0.0, 60.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Max Burst Duration Time", cpm.fMaxBurstDurationTime, 0.0, 60.0, 0.01)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
ENDPROC
#ENDIF
//----------------------
// TIMER FUNCS
//-----------------------
/// PURPOSE:
/// Starts my mission debug timer
PROC START_MISSION_DEBUG_TIMER()
iMissionDebugTime = GET_GAME_TIMER()
ENDPROC
/// PURPOSE:
/// Toggles display of mission debug timer
PROC SHOW_MISSION_DEBUG_TIMER(BOOL ok = FALSE)
bShowDebugMissionTime = ok
ENDPROC
/// PURPOSE:
/// Updates display of mission debug timer
PROC UPDATE_MISSION_DEBUG_TIMER()
iCurrentGameTime = GET_GAME_TIMER()
IF (bShowDebugMissionTime = TRUE)
DRAW_GENERIC_TIMER(iCurrentGameTime - iMissionDebugTime, "TIMER_TIME", 0, TIMER_STYLE_USEMILLISECONDS, -1, PODIUMPOS_NONE, HUDORDER_BOTTOM)
ENDIF
ENDPROC
//----------------------
// SAFE LOADING FUNCS
//-----------------------
/// PURPOSE:
/// Safely loads additional text
/// PARAMS:
/// nme - text block name
/// slot - text block slot
/// loadwait - set this to pause script until loading is complete
/// forceloading - set this force load the text block
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_ADDITIONAL_TEXT(STRING nme, TEXT_BLOCK_SLOTS slot, BOOL loadwait = TRUE, BOOL forceloading = FALSE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
//CLEAR_ADDITIONAL_TEXT(slot, FALSE)
REQUEST_ADDITIONAL_TEXT(nme, slot)
IF HAS_ADDITIONAL_TEXT_LOADED(slot) AND NOT forceloading
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS] - Additional Text:", nme, " in slot:", ENUM_TO_INT(slot)," has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD PENDING] - Additional Text:", nme, " in slot:", ENUM_TO_INT(slot)," has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(slot)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_ADDITIONAL_TEXT_LOADED(slot)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE] - Additional Text:", nme, " in slot:", ENUM_TO_INT(slot)," has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS] - Additional Text:", nme, " in slot:", ENUM_TO_INT(slot)," has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads animation dictionaries
/// PARAMS:
/// nme - anim dict name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_ANIM_DICT(STRING mdl, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_ANIM_DICT(mdl)
IF HAS_ANIM_DICT_LOADED(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS] - Anim Dict:", mdl, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD PENDING] - Anim Dict:", mdl, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_ANIM_DICT_LOADED(mdl)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_ANIM_DICT_LOADED(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: Anim Dict:", mdl, " has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Anim Dict:", mdl, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads audio bank
/// PARAMS:
/// nme - audio bank name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_AUDIO_BANK(STRING mdl, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
IF REQUEST_SCRIPT_AUDIO_BANK(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Bank:", mdl, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Audio Bank:", mdl, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT REQUEST_SCRIPT_AUDIO_BANK(mdl)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT REQUEST_SCRIPT_AUDIO_BANK(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: Audio Bank:", mdl, " has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Bank:", mdl, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads audio stream
/// PARAMS:
/// nme - audio stream name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_AUDIO_STREAM(STRING mdl, BOOL loadwait = TRUE)
BOOL ok
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
ok = LOAD_STREAM(mdl)
IF (ok)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Stream:", mdl, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Audio Stream:", mdl, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Audio Stream:", mdl, " is loading")
#ENDIF
WHILE NOT LOAD_STREAM(mdl)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT LOAD_STREAM(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: Audio Stream:", mdl, " failed to load - Time Out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Stream:", mdl, " loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads audio stream
/// PARAMS:
/// nme - audio stream name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_AUDIO_STREAM_WITH_SOUNDSET(STRING mdl, STRING setname, BOOL loadwait = TRUE)
BOOL ok
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
ok = LOAD_STREAM(mdl, setname)
IF (ok)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Stream:", mdl, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Audio Stream:", mdl, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Audio Stream:", mdl, " is loading")
#ENDIF
WHILE NOT LOAD_STREAM(mdl, setname)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT LOAD_STREAM(mdl, setname)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: Audio Stream:", mdl, " failed to load - Time Out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Audio Stream:", mdl, " loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads model
/// PARAMS:
/// mdl - model name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_MODEL(MODEL_NAMES mdl, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
IF (mdl = DUMMY_MODEL_FOR_SCRIPT)
RETURN FALSE
ENDIF
REQUEST_MODEL (mdl)
IF HAS_MODEL_LOADED(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Model:", GET_MODEL_NAME_FOR_DEBUG(mdl), " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Model:", GET_MODEL_NAME_FOR_DEBUG(mdl), " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_MODEL_LOADED(mdl)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_MODEL_LOADED(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Model:", GET_MODEL_NAME_FOR_DEBUG(mdl), " has failed to load - Time Out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Model:", GET_MODEL_NAME_FOR_DEBUG(mdl), " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads PTFX asset
/// PARAMS:
/// nme - asset name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_PTFX(STRING nme, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_PTFX_ASSET()
IS_STRING_NULL(nme) // release build is crying
IF HAS_PTFX_ASSET_LOADED()
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS] - PTFX Asset:", nme, " has loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD PENDING] - PTFX Asset:", nme, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_PTFX_ASSET_LOADED()
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_PTFX_ASSET_LOADED()
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: PTFX Asset:", nme, " has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: PTFX Asset:", nme, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads texture dictionary
/// PARAMS:
/// mdl - text dictionary name
/// priority - load this as priorty
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_TEXTURE_DICT(STRING mdl, BOOL prority = FALSE, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_STREAMED_TEXTURE_DICT(mdl, prority)
IF HAS_STREAMED_TEXTURE_DICT_LOADED(mdl)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Texture Dictionary:", mdl, " has loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Texture Dictionary:", mdl, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_STREAMED_TEXTURE_DICT_LOADED(mdl)
WAIT(0)
IF (GET_GAME_TIMER() > gt)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Texture Dictionary:", mdl, " has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Texture Dictionary:", mdl, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
PROC SECURE_UNLOAD_TEXTURE_DICT(STRING nme)
IF HAS_STREAMED_TEXTURE_DICT_LOADED(nme)
SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED(nme)
ENDIF
ENDPROC
/// PURPOSE:
/// Safely loads weapon asset
/// PARAMS:
/// nme - asset name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_WEAPON_ASSET(WEAPON_TYPE nme, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_WEAPON_ASSET(nme)
IF HAS_WEAPON_ASSET_LOADED(nme)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Weapon Asset:", GET_WEAPON_NAME(nme), " has loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Weapon Asset:", GET_WEAPON_NAME(nme), " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_WEAPON_ASSET_LOADED(nme)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_WEAPON_ASSET_LOADED(nme)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Weapon Asset:", GET_WEAPON_NAME(nme), " has failed to load - Time out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Weapon Asset:", GET_WEAPON_NAME(nme), " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads vehicle recording
/// PARAMS:
/// num - vehicle recording number
/// nme - vehicle recording name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_VEHICLE_REC(INT num, STRING nme, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_VEHICLE_RECORDING(num, nme)
IF HAS_VEHICLE_RECORDING_BEEN_LOADED(num, nme)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Car Recording:", nme, " ", num, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Car Recording:", nme, " ", num, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT HAS_VEHICLE_RECORDING_BEEN_LOADED(num, nme)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_VEHICLE_RECORDING_BEEN_LOADED(num, nme)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILED]: Car Recording:", nme, " ", num, " loading has timed out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Car Recording:", nme, " ", num, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely loads waypoint recording
/// PARAMS:
/// nme - waypoint recording name
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_WAYPOINT_REC(STRING nme, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
REQUEST_WAYPOINT_RECORDING(nme)
IF GET_IS_WAYPOINT_RECORDING_LOADED(nme)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Waypoint Recording:", nme, " has already been loaded")
#ENDIF
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]: Waypoint Recording:", nme, " has been requested")
#ENDIF
RETURN TRUE
ENDIF
WHILE NOT GET_IS_WAYPOINT_RECORDING_LOADED(nme)
WAIT(0)
IF (GET_GAME_TIMER() > gt)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD FAILED]: Waypoint Recording:", nme, " loading has timed out")
#ENDIF
RETURN FALSE
ENDIF
ENDWHILE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Waypoint Recording:", nme, " has loaded")
#ENDIF
RETURN TRUE
ENDFUNC
PROC SECURE_UNLOAD_WAYPOINT_REC(STRING nme)
IF GET_IS_WAYPOINT_RECORDING_LOADED(nme)
REMOVE_WAYPOINT_RECORDING(nme)
ENDIF
ENDPROC
/// PURPOSE:
/// Safely loads scaleform
/// PARAMS:
/// mdl - waypoint recording name
/// si - scaleform index - this is written to by function
/// loadwait - set this to pause script until loading is complete
/// RETURNS:
/// true if loaded successfully or if is requested
FUNC BOOL SECURE_REQUEST_AND_LOAD_SCALEFORM(STRING mdl, SCALEFORM_INDEX &si, BOOL loadwait = TRUE)
INT gt = GET_GAME_TIMER() + REQUEST_TIMEOUT
IF (si = NULL)
si = REQUEST_SCALEFORM_MOVIE(mdl)
CPRINTLN(DEBUG_MISSION, "[LOAD ALERT]:Scaleform Movie", mdl, "has been requested")
ENDIF
IF HAS_SCALEFORM_MOVIE_LOADED(si)
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Scaleform Movie:", mdl, "has already been loaded")
RETURN TRUE
ENDIF
IF (loadwait = FALSE)
RETURN TRUE
ENDIF
WHILE NOT HAS_SCALEFORM_MOVIE_LOADED(si)
WAIT(0)
IF (GET_GAME_TIMER() > gt) AND NOT HAS_SCALEFORM_MOVIE_LOADED(si)
CPRINTLN(DEBUG_MISSION, "[LOAD FAILURE]: Scaleform Movie:", mdl, " has failed to load - Time out")
RETURN FALSE
ENDIF
ENDWHILE
CPRINTLN(DEBUG_MISSION, "[LOAD SUCCESS]: Scaleform Movie:", mdl, " has loaded")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Safely unloads vehicle reocrding
/// PARAMS:
/// num - vehicle recording number
/// nme - vehicle recording name
PROC SECURE_UNLOAD_VEHICLE_REC(INT num, STRING nme)
// commented out for B*663880
//IF HAS_VEHICLE_RECORDING_BEEN_LOADED(num, nme)
REMOVE_VEHICLE_RECORDING(num, nme)
//ENDIF
ENDPROC
/// PURPOSE:
/// Safely unloads model
/// PARAMS:
/// mdl - model name
PROC SECURE_UNLOAD_MODEL(MODEL_NAMES mdl)
IF (mdl <> DUMMY_MODEL_FOR_SCRIPT)
SET_MODEL_AS_NO_LONGER_NEEDED(mdl)
ENDIF
ENDPROC
/// PURPOSE:
/// Safely unloads animation dictionaries
/// PARAMS:
/// mdl - anim dict name
PROC SECURE_UNLOAD_ANIM_DICT(STRING mdl)
REMOVE_ANIM_DICT (mdl)
ENDPROC
//----------------------
// SPAWNPT FUNCTIONS
//----------------------
/// PURPOSE:
/// Generates a random bool
/// RETURNS:
/// True or False
FUNC BOOL GENERATE_RANDOM_BOOL()
IF GET_RANDOM_INT_IN_RANGE(0, 1999) / 1000 = 1
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDFUNC
/// PURPOSE:
/// Get the closest offscreen point to a given position
/// PARAMS:
/// in - position
/// out - new offscreen position
/// debug - draw debug stuff
/// RETURNS:
/// true if we were successful
FUNC BOOL GET_CLOSEST_OFFSCREEN_POINT(VECTOR in, VECTOR &out, BOOL debug = FALSE)
VECTOR lend
VECTOR intersect
VECTOR lstart = GET_GAMEPLAY_CAM_COORD()
VECTOR plyrPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
FLOAT oplength
FLOAT adjlength
FLOAT zvalue = GET_GAMEPLAY_CAM_RELATIVE_HEADING() + GET_ENTITY_HEADING(PLAYER_PED_ID())
// if point is off screen just return point
IF NOT IS_SPHERE_VISIBLE(in, 0.25)
out = in
RETURN TRUE
ENDIF
// work out start and end of line (get point miles in front of camera)
lstart.z = plyrPos.z
lend = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(lstart, zvalue, <<0, 300.0, 0>>)
IF (debug = TRUE)
DRAW_DEBUG_LINE_WITH_TWO_COLOURS(lstart, lend)
ENDIF
IF (debug = TRUE)
DRAW_DEBUG_LINE_WITH_TWO_COLOURS(lstart, in)
DRAW_DEBUG_SPHERE(in, 0.5, 0, 255, 0, 64)
ENDIF
// calculate nearest point on line to point
intersect = GET_CLOSEST_POINT_ON_LINE(in, lstart, lend)
IF (debug = TRUE)
DRAW_DEBUG_SPHERE(intersect, 0.5, 0, 255, 0, 64)
ENDIF
adjlength = GET_DISTANCE_BETWEEN_COORDS(lstart, intersect)
oplength = adjlength * TAN(GET_GAMEPLAY_CAM_FOV())
// check side
VECTOR v1 = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(lstart, zvalue, <<oplength, adjlength, 0>>)
VECTOR v2 = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(lstart, zvalue, <<-oplength, adjlength, 0>>)
out = v1
IF GET_LINE_MAGNITUDE_SQUARED(v2, in) < GET_LINE_MAGNITUDE_SQUARED(v1, in)
out = v2
ENDIF
IF (debug = TRUE)
DRAW_DEBUG_SPHERE(out, 0.5, 0, 255, 0, 64)
DRAW_DEBUG_LINE_WITH_TWO_COLOURS(intersect, out)
ENDIF
RETURN TRUE
ENDFUNC
///------------------------------------------------------------------------------
/// FUNCTION: GET_CLOSEST_OFFSCREEN_PED_SPAWNPOINT()
/// PURPOSE: GETS CLOSEST OFFSCREEN POINT TO A POSITION
///------------------------------------------------------------------------------
/// PURPOSE:
/// Gets the closest off screen ped spawn point to a position
/// PARAMS:
/// in - position
/// out - new offscreen position
/// safecheck - use safe spawn point check
/// pavecheck - use pavement check
/// RETURNS:
/// true if we were successful
FUNC BOOL GET_CLOSEST_OFFSCREEN_PED_SPAWNPOINT(VECTOR in, VECTOR &out, BOOL safecheck = TRUE, BOOL pavecheck = FALSE)
VECTOR tmp
FLOAT z
IF NOT GET_CLOSEST_OFFSCREEN_POINT(in, out, FALSE)
RETURN FALSE
ENDIF
IF (safecheck)
IF NOT GET_SAFE_COORD_FOR_PED(out, pavecheck, tmp)
RETURN FALSE
ENDIF
out = tmp
RETURN NOT IS_SPHERE_VISIBLE(out, 0.25)
ENDIF
IF NOT GET_GROUND_Z_FOR_3D_COORD(out, z)
RETURN FALSE
ENDIF
out.z = z
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Gets the closest off screen car spawn point
/// PARAMS:
/// in - desired position
/// out - new spawn point position (overwritten)
/// head - new heading
/// heightTol - if the position is less than x meters from out - fail
/// debug - draw debug stuff
/// RETURNS:
/// true on success
FUNC BOOL GET_CLOSEST_OFFSCREEN_CAR_SPAWNPOINT(VECTOR in, VECTOR &out, FLOAT &head, FLOAT heightTol = 15.0, BOOL debug = FALSE)
VECTOR tmp
INT iNodeAddr
IF NOT GET_CLOSEST_OFFSCREEN_POINT(in, out, debug)
RETURN FALSE
ENDIF
tmp = out
IF NOT GET_RANDOM_VEHICLE_NODE( tmp, 20.0, 1, FALSE, FALSE, out, iNodeAddr)
RETURN FALSE
ENDIF
GET_SPAWN_COORDS_FOR_VEHICLE_NODE( iNodeAddr, GET_ENTITY_COORDS(PLAYER_PED_ID()), out, head)
IF IS_SPHERE_VISIBLE(out, 0.125)
RETURN FALSE
ENDIF
tmp = GET_ENTITY_COORDS(PLAYER_PED_ID())
IF (ABSF(tmp.z - out.z) > heightTol)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Generates a spawn point around position
/// PARAMS:
/// in - desired position
/// out - new position
/// range - minimum range of spawn point
/// safecheck - use safe spawn point check
/// pavecheck - use pavement check
/// RETURNS:
/// true on success
FUNC BOOL GENERATE_SPAWN_POINT_AROUND_POSITION(VECTOR in, VECTOR &out, FLOAT range, BOOL safechk = FALSE, BOOL pavecheck = FALSE)
FLOAT zrot
VECTOR pos
pos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(in, GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0), <<0, range, 0>>)
IF GET_GROUND_Z_FOR_3D_COORD(pos, zrot)
pos.z = zrot
ENDIF
out = pos
IF (safechk = FALSE)
RETURN TRUE
ENDIF
RETURN GET_SAFE_COORD_FOR_PED(pos, pavecheck, out)
ENDFUNC
/// PURPOSE:
/// Generates a ped spawn point within an axial aligned box
/// PARAMS:
/// min - min corner of area box
/// max - max corner of area box
/// out - new position
/// safecheck - use safe spawn point check
/// pavecheck - use pavement check
/// RETURNS:
/// true on success
FUNC BOOL GENERATE_SPAWN_POINT_IN_AREA(VECTOR min, VECTOR max, VECTOR &out, BOOL safechk = FALSE, BOOL pavecheck = FALSE)
FLOAT zrot
VECTOR pos
VECTOR diff
diff = max - min
pos = min
IF (diff.x > 0)
pos.x += GET_RANDOM_FLOAT_IN_RANGE(0, diff.x)
ENDIF
IF (diff.y > 0)
pos.y += GET_RANDOM_FLOAT_IN_RANGE(0, diff.y)
ENDIF
IF (diff.z > 0)
pos.z += GET_RANDOM_FLOAT_IN_RANGE(0, diff.z)
ENDIF
IF GET_GROUND_Z_FOR_3D_COORD(pos, zrot)
pos.z = zrot
ENDIF
out = pos
IF (safechk = FALSE)
RETURN TRUE
ENDIF
RETURN GET_SAFE_COORD_FOR_PED(pos, pavecheck, out)
ENDFUNC
/// PURPOSE:
/// Generates a ped spawn point in range of player
/// PARAMS:
/// out - new position
/// range - desired ranged
/// safechk - use safe coord check
/// pavecheck - use pavement check (if safechk is off this is ignored)
/// RETURNS:
/// True on success
FUNC BOOL GENERATE_SPAWN_POINT_AROUND_PLAYER(VECTOR &out, FLOAT range, BOOL safechk = FALSE, BOOL pavecheck = FALSE)
FLOAT zrot
VECTOR pos
pos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0), <<0, range, 0>>)
IF GET_GROUND_Z_FOR_3D_COORD(pos, zrot)
pos.z = zrot
ENDIF
out = pos
IF (safechk = FALSE)
RETURN TRUE
ENDIF
RETURN GET_SAFE_COORD_FOR_PED(pos, pavecheck, out)
ENDFUNC
/// PURPOSE:
/// Generates a ped spawn point in range of player but in front of player
/// PARAMS:
/// out - new position
/// range - desired ranged
/// safechk - use safe coord check
/// pavecheck - use pavement check (if safechk is off this is ignored)
/// RETURNS:
/// True on success
FUNC BOOL GENERATE_SPAWN_POINT_IN_FRONT_OF_PLAYER(VECTOR &out, FLOAT range, BOOL safechk = FALSE, BOOL pavecheck = FALSE)
FLOAT angle
FLOAT zrot
VECTOR pos
VECTOR camPos
camPos = GET_GAMEPLAY_CAM_COORD()
zrot = GET_GAMEPLAY_CAM_RELATIVE_HEADING() + GET_ENTITY_HEADING(PLAYER_PED_ID())
angle = (GET_GAMEPLAY_CAM_FOV() / 2.0) + GET_RANDOM_FLOAT_IN_RANGE(0.0, 8.0)
pos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(campos, GET_RANDOM_FLOAT_IN_RANGE(zrot - angle, zrot + angle), <<0, range, 0>>)
IF GET_GROUND_Z_FOR_3D_COORD(pos, zrot)
pos.z = zrot
ENDIF
out = pos
IF (safechk = FALSE)
RETURN TRUE
ENDIF
RETURN GET_SAFE_COORD_FOR_PED(pos, pavecheck, out)
ENDFUNC
/// PURPOSE:
/// Generates a ped spawn point in range of player but in front of player within a cone
/// PARAMS:
/// out - new position
/// range - desired ranged
/// angle - angle of cone
/// safechk - use safe coord check
/// pavecheck - use pavement check (if safechk is off this is ignored)
/// RETURNS:
/// True on success
FUNC BOOL GENERATE_SPAWN_POINT_IN_FRONT_OF_PLAYER_CONE(VECTOR &out, FLOAT range, FLOAT angle, BOOL safechk = FALSE, BOOL pavecheck = FALSE)
FLOAT zrot
VECTOR pos
VECTOR camPos
camPos = GET_GAMEPLAY_CAM_COORD()
zrot = GET_GAMEPLAY_CAM_RELATIVE_HEADING() + GET_ENTITY_HEADING(PLAYER_PED_ID())
angle /= 2.0
pos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(campos, GET_RANDOM_FLOAT_IN_RANGE(zrot - angle, zrot + angle), <<0, range, 0>>)
IF GET_GROUND_Z_FOR_3D_COORD(pos, zrot)
pos.z = zrot
ENDIF
out = pos
IF (safechk = FALSE)
RETURN TRUE
ENDIF
RETURN GET_SAFE_COORD_FOR_PED(pos, pavecheck, out)
ENDFUNC
/// PURPOSE:
/// Generate a ped spawm point in front of player but off screen
/// PARAMS:
/// out - new position
/// range - distance away from player
/// right - pick the left or right side of screen
/// pavecheck - use the pavement check
/// RETURNS:
/// True on Success
FUNC BOOL GENERATE_SPAWN_POINT_IN_FRONT_OF_PLAYER_OFF_VIEWCONE(VECTOR &out, FLOAT range, BOOL right = TRUE, BOOL pavecheck = FALSE)
FLOAT zvalue
FLOAT oplength
VECTOR camPos
VECTOR tmp
INT i = 0
camPos = GET_GAMEPLAY_CAM_COORD()
zvalue = GET_GAMEPLAY_CAM_RELATIVE_HEADING() + GET_ENTITY_HEADING(PLAYER_PED_ID())
// this is the offscreen position [on camera plane]
oplength = (range * TAN(GET_GAMEPLAY_CAM_FOV() / 2.0)) + 1
// now check along the edge in 2.5 meter increments to get a point properly off screen
FOR i = 0 TO 4
IF (right = TRUE)
tmp = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(campos, zvalue, <<oplength, range, 0>>)
ELSE
tmp = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(campos, zvalue, <<-oplength, range, 0>>)
ENDIF
IF GET_SAFE_COORD_FOR_PED(tmp, pavecheck, out)
IF NOT IS_SPHERE_VISIBLE(out, 0.125)
RETURN TRUE
ENDIF
ENDIF
oplength += 2.5
ENDFOR
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Generate a cae spawm point in front of player but off screen
/// PARAMS:
/// out - new position
/// head - new heading
/// range - distance away from player
/// right - pick the left or right side of screen
/// RETURNS:
/// True on Success
FUNC BOOL GENERATE_CAR_SPAWN_POINT_IN_FRONT_OF_PLAYER_OFF_VIEWCONE(VECTOR &out, FLOAT &head, FLOAT range, BOOL right = TRUE)
VECTOR tmp
INT i
IF NOT GENERATE_SPAWN_POINT_IN_FRONT_OF_PLAYER_OFF_VIEWCONE(tmp, range, right)
RETURN FALSE
ENDIF
IF GET_CLOSEST_VEHICLE_NODE_WITH_HEADING(GET_ENTITY_COORDS(PLAYER_PED_ID()), out, head)
IF NOT IS_SPHERE_VISIBLE(out, 1.0)
RETURN TRUE
ENDIF
ENDIF
FOR i = 1 TO 6
IF GET_NTH_CLOSEST_VEHICLE_NODE_FAVOUR_DIRECTION(tmp, GET_ENTITY_COORDS(PLAYER_PED_ID()), i, out, head)
IF NOT IS_SPHERE_VISIBLE(out, 1.0)
RETURN TRUE
ENDIF
ENDIF
ENDFOR
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Given 2 points works out which point I am more facing
/// PARAMS:
/// ent - entity
/// pt1 - point 1
/// pt2 - point 2
/// RETURNS:
/// closest point i am facing
FUNC VECTOR GET_ENTITY_FACING_POINT(ENTITY_INDEX ent, VECTOR pt1, VECTOR pt2)
VECTOR pt1toent
VECTOR pt2toent
VECTOR entfwd
FLOAT angle1
FLOAT angle2
entfwd = GET_ENTITY_FORWARD_VECTOR(ent)
pt1toent = NORMALISE_VECTOR(pt1 - GET_ENTITY_COORDS(ent))
pt2toent = NORMALISE_VECTOR(pt2 - GET_ENTITY_COORDS(ent))
angle1 = ABSF(GET_ANGLE_BETWEEN_2D_VECTORS(pt1toent.x, pt1toent.y, entfwd.x, entfwd.y))
angle2 = ABSF(GET_ANGLE_BETWEEN_2D_VECTORS(pt2toent.x, pt2toent.y, entfwd.x, entfwd.y))
IF (angle2 < angle1)
RETURN pt2
ENDIF
RETURN pt1
ENDFUNC
/// PURPOSE:
/// Works if distance between 2 points is less then range
/// PARAMS:
/// stt - point 1
/// end - point 2
/// range - distance
/// RETURNS:
/// true or false
FUNC BOOL IS_IN_RANGE_QUICK(VECTOR stt, VECTOR end, FLOAT range)
VECTOR v = end - stt
RETURN (v.x * v.x + v.y * v.y + v.z * v.z) <= (range * range)
ENDFUNC
//----------------------
// GENERAL FUNCTIONS
//----------------------
/// PURPOSE:
/// Tells if a ped has been killed by a head shot
/// PARAMS:
/// pedID - ped ID
/// RETURNS:
/// True or False
FUNC BOOL CHECK_HEADSHOT(PED_INDEX pedID)
IF NOT DOES_ENTITY_EXIST(pedID)
RETURN FALSE
ENDIF
PED_BONETAG ePedBonetag = BONETAG_NULL
IF IS_ENTITY_DEAD(pedID) OR IS_PED_INJURED(pedID)
IF NOT GET_PED_LAST_DAMAGE_BONE(pedID, ePedBonetag)
RETURN FALSE
ENDIF
RETURN ePedBonetag = BONETAG_HEAD OR ePedBonetag = BONETAG_NECK
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tells if a ped has been crippled (shot in the legs)
/// PARAMS:
/// pedID - ped ID
/// RETURNS:
/// True or False
FUNC BOOL CHECK_CRIPPLED(PED_INDEX pedID)
IF NOT DOES_ENTITY_EXIST(pedID)
RETURN FALSE
ENDIF
PED_BONETAG ePedBonetag = BONETAG_NULL
IF IS_ENTITY_DEAD(pedID) OR IS_PED_INJURED(pedID)
IF NOT GET_PED_LAST_DAMAGE_BONE(pedID, ePedBonetag)
RETURN FALSE
ENDIF
RETURN (ePedBonetag = BONETAG_L_CALF) OR (ePedBonetag = BONETAG_R_CALF) OR (ePedBonetag = BONETAG_R_THIGH) OR (ePedBonetag = BONETAG_L_THIGH)
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tells if a ped has been executed (died while trying to get up)
/// PARAMS:
/// pedID - ped ID
/// RETURNS:
/// True or False
FUNC BOOL CHECK_EXECUTION(PED_INDEX pedID)
IF NOT DOES_ENTITY_EXIST(pedID)
RETURN FALSE
ENDIF
RETURN IS_PED_GETTING_UP(pedID)
ENDFUNC
/// PURPOSE:
/// Gets a list of peds using the ped scanner
/// PARAMS:
/// ped - ped to check
/// array - array to write list of peds to
/// range - distance to check
/// vRoadRange - ignored peds who are further away from road than this
/// vRoadZDist - ignore peds who's z dist is this diffrent from the road
/// misped - include mission peds
/// incar - include peds in cars
/// RETURNS:
/// # of peds found
FUNC INT GET_PEDS_NEAR_PED(PED_INDEX ped, PED_INDEX& array[], FLOAT range = 60.0, FLOAT vRoadRange = 0.0, FLOAT vRoadZDist = 5.0, BOOL misped = FALSE, BOOL incar = FALSE)
INT i
INT cnt
INT ind = 0
VECTOR tmp
VECTOR pedpos
PED_INDEX tmpArray[25]
IF NOT IS_ENTITY_OK(ped)
RETURN 0
ENDIF
range = range
cnt = GET_PED_NEARBY_PEDS(ped, tmpArray)
IF (cnt > COUNT_OF(tmpArray))
SCRIPT_ASSERT("[WARNING]:GET_PEDS_NEAR_PED - There are more in range than in the temp array")
ENDIF
IF (vRoadRange = 0.0)
i = 0
WHILE (i < cnt)
IF IS_ENTITY_OK(tmpArray[i])
IF (misped = FALSE) AND NOT IS_ENTITY_A_MISSION_ENTITY(tmpArray[i])
IF (incar = FALSE) AND NOT IS_PED_IN_ANY_VEHICLE(tmpArray[i])
IF NOT IS_PED_USING_ANY_SCENARIO(tmpArray[i])
array[ind] = tmpArray[i]
ind ++
ENDIF
ENDIF
ENDIF
ENDIF
i ++
ENDWHILE
ELSE
i = 0
WHILE (i < cnt)
IF IS_ENTITY_OK(tmpArray[i])
IF (misped = FALSE) AND NOT IS_ENTITY_A_MISSION_ENTITY(tmpArray[i])
IF (incar = FALSE) AND NOT IS_PED_IN_ANY_VEHICLE(tmpArray[i])
IF NOT IS_PED_USING_ANY_SCENARIO(tmpArray[i])
pedpos = GET_ENTITY_COORDS(tmpArray[i])
IF NOT GET_CLOSEST_VEHICLE_NODE(pedpos, tmp)
array[ind] = tmpArray[i]
ind ++
ELIF GET_DISTANCE_BETWEEN_COORDS(pedpos, tmp) < vRoadRange
IF (ABSF(pedpos.z - tmp.z) <= vRoadZDist)
array[ind] = tmpArray[i]
ind ++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
i ++
ENDWHILE
ENDIF
RETURN ind
ENDFUNC
/// PURPOSE:
/// Returns an array of everyone in the vehicle
/// PARAMS:
/// vehicle -
/// pedArray - array of ped indexs in vehicles. MAX_VEHICLE_SEATS=16 in VehicleDefines.h
/// numPeds - number of peds found and written to pedArray
/// RETURNS: true if any peds where found
///
FUNC BOOL TRY_GET_PEDS_IN_VEHICLE(VEHICLE_INDEX vehicle, PED_INDEX& pedArray[MAX_PASSENGERS_IN_VEHICLE], INT& numPeds)
numPeds = 0
INT iMaxSeats = (GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(vehicle) + 1) //Add 1 for the driver
IF iMaxSeats > MAX_PASSENGERS_IN_VEHICLE
CASSERTLN(DEBUG_SYSTEM, "Number of seats in vehicle exceeds", MAX_PASSENGERS_IN_VEHICLE, ". This is not supported.")
iMaxSeats = MAX_PASSENGERS_IN_VEHICLE
ENDIF
INT i
PED_INDEX VehPed
REPEAT iMaxSeats i
VehPed = GET_PED_IN_VEHICLE_SEAT(vehicle, INT_TO_ENUM(VEHICLE_SEAT, i-1))
IF IS_ENTITY_OK(VehPed)
pedArray[numPeds] = VehPed
numPeds++
ENDIF
ENDREPEAT
RETURN numPeds > 0
ENDFUNC
FUNC BOOL IS_PED_PLAYER_OR_PLAYERS_MATE(PED_INDEX ped)
IF (ped = PLAYER_PED_ID())
RETURN TRUE
ENDIF
IF IS_PED_IN_GROUP(ped)
IF GET_PED_GROUP_INDEX(ped) = GET_PLAYER_GROUP(PLAYER_ID())
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Forces all peds in cars near the ped to run away
/// PARAMS:
/// ped - ped we are running away from
/// radius - distance to check
/// checkDir - if we do this then check direction
/// angle -
PROC FORCE_VEHICLE_OCCUPANTS_NEAR_PED_FLEE(PED_INDEX ped, FLOAT radius = 10.0, BOOL checkDir = FALSE, FLOAT angle = 20.0)
INT cnt
INT i, n
INT totalseats
VECTOR dirToPed
PED_INDEX fleePed
SEQUENCE_INDEX seqTask
VEHICLE_INDEX tmpArray[32]
BOOL ok
// scan for vehicles near player
cnt = GET_PED_NEARBY_VEHICLES(ped, tmpArray)
IF (cnt = 0)
EXIT
ENDIF
// loop through vehicles if they are in radius tell occupants to run away
REPEAT cnt i
IF IS_ENTITY_OK(tmpArray[i])
IF NOT IS_THIS_MODEL_A_HELI(GET_ENTITY_MODEL(tmpArray[i]))
IF VDIST2(GET_ENTITY_COORDS(tmpArray[i]), GET_ENTITY_COORDS(ped)) <= (radius * radius)
ok = TRUE
IF (checkDir)
dirToPed = NORMALISE_VECTOR(GET_ENTITY_COORDS(ped) - GET_ENTITY_COORDS(tmpArray[i]))
ok = (DOT_PRODUCT(dirToPed, GET_ENTITY_FORWARD_VECTOR(tmpArray[i])) < COS(angle))
ENDIF
IF (ok)
// driver
fleePed = GET_PED_IN_VEHICLE_SEAT(tmpArray[i])
IF IS_ENTITY_OK(fleePed)
IF NOT IS_PED_PLAYER_OR_PLAYERS_MATE(fleePed)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(fleePed, TRUE)
OPEN_SEQUENCE_TASK(seqTask)
TASK_LEAVE_ANY_VEHICLE(NULL)
TASK_SMART_FLEE_PED(NULL, ped, 300.0, -1, FALSE)
CLOSE_SEQUENCE_TASK(seqTask)
TASK_PERFORM_SEQUENCE(fleePed, seqTask)
CLEAR_SEQUENCE_TASK(seqTask)
ENDIF
ENDIF
// passengers
n = 0
totalseats = GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(tmpArray[i])
REPEAT totalseats n
fleePed = GET_PED_IN_VEHICLE_SEAT(tmpArray[i], INT_TO_ENUM(VEHICLE_SEAT, n))
IF IS_ENTITY_OK(fleePed)
IF NOT IS_PED_PLAYER_OR_PLAYERS_MATE(fleePed)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(fleePed, TRUE)
OPEN_SEQUENCE_TASK(seqTask)
TASK_LEAVE_ANY_VEHICLE(NULL)
TASK_SMART_FLEE_PED(NULL, ped, 300.0, -1, FALSE)
CLOSE_SEQUENCE_TASK(seqTask)
TASK_PERFORM_SEQUENCE(fleePed, seqTask)
CLEAR_SEQUENCE_TASK(seqTask)
ENDIF
ENDIF
ENDREPEAT
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Tells us if a vehicle has free seats
/// PARAMS:
/// vehicle - vehicle index
/// seat - seat enum (the first free seat, this is overwritten)
/// numFreeSeats - # of seats free (the first free seat, this is overwritten)
/// driverAlso - do we include the driver
/// stopCheck - if a vehicle is moving and this is set, this function will fail
/// RETURNS:
/// True if a seat is remaninig
FUNC BOOL GET_VEHICLE_HAS_FREE_SEATS(VEHICLE_INDEX vehicle, VEHICLE_SEAT& seat, INT& numFreeSeats, BOOL driverAlso = TRUE, BOOL stopCheck = TRUE)
BOOL ret = FALSE
numFreeSeats = GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(vehicle) - GET_VEHICLE_NUMBER_OF_PASSENGERS(vehicle)
IF NOT IS_ENTITY_DEAD(vehicle)
IF (stopCheck) AND NOT IS_VEHICLE_STOPPED(vehicle)
RETURN FALSE
ENDIF
IF driverAlso AND IS_VEHICLE_SEAT_FREE(vehicle, VS_DRIVER)
seat = VS_DRIVER
ret = TRUE
ELSE
INT i
REPEAT GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(vehicle) i
IF IS_VEHICLE_SEAT_FREE(vehicle, INT_TO_ENUM(VEHICLE_SEAT, i))
seat = INT_TO_ENUM(VEHICLE_SEAT, i)
RETURN TRUE
ENDIF
ENDREPEAT
ENDIF
ENDIF
RETURN ret
ENDFUNC
/// PURPOSE:
/// Creates a ped in a vehicle and automatically gives them a chair
/// PARAMS:
/// pedModel - ped model
/// veh - vehicle to put them in
/// wpn - a weapon to give them
/// hatePlayer - set this to set peds relationship hash to RELGROUPHASH_HATES_PLAYER
/// blockTemp - set this turn off temporary events
/// pedType - ped type
/// RETURNS:
/// the ped index of the new ped or null if there are no chairs
FUNC PED_INDEX CREATE_PED_INSIDE_VEHICLE_AUTO_SEAT(MODEL_NAMES pedModel, VEHICLE_INDEX veh, WEAPON_TYPE wpn = WEAPONTYPE_INVALID, BOOL hatePlayer = FALSE, BOOL blockTemp = FALSE, PED_TYPE pedType = PEDTYPE_MISSION)
INT num
PED_INDEX ped
VEHICLE_SEAT seat
IF NOT GET_VEHICLE_HAS_FREE_SEATS(veh, seat, num)
RETURN NULL
ENDIF
ped = CREATE_PED_INSIDE_VEHICLE(veh, pedType, pedModel, seat)
IF NOT DOES_ENTITY_EXIST(ped)
RETURN NULL
ENDIF
IF (wpn <> WEAPONTYPE_INVALID) AND (wpn <> WEAPONTYPE_UNARMED)
GIVE_WEAPON_TO_PED(ped, wpn, INFINITE_AMMO, TRUE)
ENDIF
IF (hatePlayer)
SET_PED_RELATIONSHIP_GROUP_HASH(ped, RELGROUPHASH_HATES_PLAYER)
ENDIF
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(ped, blockTemp)
RETURN ped
ENDFUNC
PROC NET_SET_ENTITY_INVINCIBLE(ENTITY_INDEX ent, BOOL bOk = TRUE)
IF IS_ENTITY_OK(ent)
IF (g_bInMultiplayer)
IF NETWORK_HAS_CONTROL_OF_ENTITY(ent)
SET_ENTITY_INVINCIBLE(ent, bOK)
ENDIF
ELSE
SET_ENTITY_INVINCIBLE(ent, bOK)
ENDIF
ENDIF
ENDPROC
PROC SET_VEHICLE_AND_OCCUPANTS_INVINCIBLE(VEHICLE_INDEX veh, BOOL bOK = TRUE)
NET_SET_ENTITY_INVINCIBLE(veh, bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_DRIVER), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_FRONT_RIGHT), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_BACK_LEFT), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_BACK_RIGHT), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_LEFT_1), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_RIGHT_1), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_LEFT_2), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_RIGHT_2), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_LEFT_3), bOK)
NET_SET_ENTITY_INVINCIBLE(GET_PED_IN_VEHICLE_SEAT(veh, VS_EXTRA_RIGHT_3), bOK)
ENDPROC
/// PURPOSE:
/// Does a shifting ground z check
/// PARAMS:
/// pos - position
/// outz - new z
/// it - number of times to try shifting
/// RETURNS:
/// true if ground z is found
FUNC BOOL REPEAT_GET_GROUND_Z(VECTOR pos, FLOAT &outz, INT it = 1)
INT I
FOR I = 0 TO it
IF GET_GROUND_Z_FOR_3D_COORD(pos, outz)
RETURN TRUE
ENDIF
pos.z += 0.5
ENDFOR
RETURN FALSE
ENDFUNC
FUNC BOOL DOES_PLAYER_HAVE_THIS_MONEY(INT iCash)
IF NETWORK_IS_GAME_IN_PROGRESS()
RETURN GET_PLAYER_CASH(PLAYER_ID()) >= iCash
ENDIF
SWITCH (GET_CURRENT_PLAYER_PED_ENUM())
CASE CHAR_TREVOR
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_TREVOR) >= iCash
CASE CHAR_MICHAEL
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_MICHAEL) >= iCash
CASE CHAR_FRANKLIN
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_FRANKLIN) >= iCash
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Gets bank balance of current player
/// RETURNS:
///
FUNC INT GET_CURRENT_PLAYER_PED_ACCOUNT_BALANCE()
IF NETWORK_IS_GAME_IN_PROGRESS()
RETURN GET_PLAYER_CASH(PLAYER_ID())
ENDIF
SWITCH (GET_CURRENT_PLAYER_PED_ENUM())
CASE CHAR_TREVOR
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_TREVOR)
CASE CHAR_MICHAEL
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_MICHAEL)
CASE CHAR_FRANKLIN
RETURN GET_ACCOUNT_BALANCE(BANK_ACCOUNT_FRANKLIN)
ENDSWITCH
RETURN 0
ENDFUNC
PROC CHARGE_CURRENT_PLAYER_PED_ACCOUNT_BALANCE(INT amnt, BANK_ACCOUNT_ACTION_SOURCE_BAAC bac = BAAC_UNLOGGED_SMALL_ACTION)
INT cash
IF NETWORK_IS_GAME_IN_PROGRESS()
cash = GET_PLAYER_CASH(PLAYER_ID())
IF (cash > 0)
IF (cash >= amnt)
GIVE_LOCAL_PLAYER_FM_CASH(-amnt)
ELSE
GIVE_LOCAL_PLAYER_FM_CASH(-cash)
ENDIF
ENDIF
ELSE
DEBIT_BANK_ACCOUNT(GET_CURRENT_PLAYER_PED_ENUM(), bac, amnt)
ENDIF
ENDPROC
PROC CHARGE_PLAYER_PED_ACCOUNT_BALANCE(PED_INDEX hPed, INT amnt, BANK_ACCOUNT_ACTION_SOURCE_BAAC bac = BAAC_UNLOGGED_SMALL_ACTION)
IF NOT IS_ENTITY_OK(hPed)
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
EXIT
ELSE
enumCharacterList eChar = GET_PLAYER_PED_ENUM(hPed)
IF eChar = NO_CHARACTER
eChar = GET_NPC_PED_ENUM(hPed)
ENDIF
DEBIT_BANK_ACCOUNT(eChar, bac, amnt)
ENDIF
ENDPROC
/// PURPOSE:
/// Clears a cylinder of stuff
/// PARAMS:
/// v1 - position 1
/// v2 - position 2
/// rad - radius
/// ped - clear peds
/// car - clear cars
/// obj - clear objects
PROC CLEAR_CYLINDER_OF_FIRE(VECTOR v1, VECTOR v2, FLOAT rad, BOOL bClearProj = TRUE)
FLOAT dist = GET_DISTANCE_BETWEEN_COORDS(v1, v2)
VECTOR v = v1
VECTOR norm = NORMALISE_VECTOR(v2 - v1)
FLOAT f
WHILE f < dist
STOP_FIRE_IN_RANGE(v, rad)
IF (bClearProj)
CLEAR_AREA_OF_PROJECTILES(v, rad)
ENDIF
v += norm * (rad / 2.0)
f += (rad / 2.0)
ENDWHILE
ENDPROC
/// PURPOSE:
/// Clears a cylinder of stuff
/// PARAMS:
/// v1 - position 1
/// v2 - position 2
/// rad - radius
/// ped - clear peds
/// car - clear cars
/// obj - clear objects
PROC CLEAR_CYLINDER_OF_ENTITIES(VECTOR v1, VECTOR v2, FLOAT rad, BOOL ped = FALSE, BOOL car = FALSE, BOOL obj = FALSE, BOOL fire = FALSE, BOOL prj = TRUE)
FLOAT dist = GET_DISTANCE_BETWEEN_COORDS(v1, v2)
FLOAT f
VECTOR v = v1
VECTOR norm = NORMALISE_VECTOR(v2 - v1)
WHILE f < dist
IF (ped)
CLEAR_AREA_OF_PEDS(v, rad)
ENDIF
IF (obj)
CLEAR_AREA_OF_OBJECTS(v, rad)
ENDIF
IF (car)
CLEAR_AREA_OF_VEHICLES(v, rad)
ENDIF
IF (fire)
STOP_FIRE_IN_RANGE(v, rad)
ENDIF
IF (prj)
CLEAR_AREA_OF_PROJECTILES(v, rad)
ENDIF
v += norm * (rad / 2.0)
f += (rad / 2.0)
ENDWHILE
ENDPROC
/// PURPOSE:
/// Block Scenaios and Ambient
/// PARAMS:
/// sb - reference to block index - keep this index you need to call it with UNBLOCK_SCENARIOS_AND_AMBIENT to rese tit
PROC BLOCK_SCENARIOS_AND_AMBIENT(SCENARIO_BLOCKING_INDEX &sb, BOOL bClearPeds = FALSE)
// Disable all peds...
SET_PED_POPULATION_BUDGET(0)
SET_REDUCE_PED_MODEL_BUDGET(TRUE)
// Traffic and cops
SET_VEHICLE_POPULATION_BUDGET(0)
SET_REDUCE_VEHICLE_MODEL_BUDGET(TRUE)
SET_DISPATCH_COPS_FOR_PLAYER(PLAYER_ID(), FALSE)
SET_CREATE_RANDOM_COPS(FALSE)
// Turn on the slipstream effect
SET_ENABLE_VEHICLE_SLIPSTREAMING(TRUE)
// Block all scenarios
sb = ADD_SCENARIO_BLOCKING_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 315.0>>)
// Needed to disable scenarios at docks
SET_SCENARIO_TYPE_ENABLED("DRIVE", FALSE)
// Remove vehicle gens
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 315.0>>, FALSE)
REMOVE_VEHICLES_FROM_GENERATORS_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 315.0>>)
IF IS_ENTITY_OK(PLAYER_PED_ID()) AND (bClearPeds = TRUE)
CLEAR_AREA_OF_PEDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), 500) // B*930668 - make sure there are no ambient peds still mooching around
ENDIF
ENDPROC
/// PURPOSE:
/// Unblock Scenaios and Ambient
/// PARAMS:
/// sb - reference to block index
PROC UNBLOCK_SCENARIOS_AND_AMBIENT(SCENARIO_BLOCKING_INDEX sb)
// Restore peds
SET_REDUCE_PED_MODEL_BUDGET(FALSE)
SET_PED_POPULATION_BUDGET(3)
// Traffic and cops
SET_REDUCE_VEHICLE_MODEL_BUDGET(FALSE)
SET_VEHICLE_POPULATION_BUDGET(3)
SET_DISPATCH_COPS_FOR_PLAYER(PLAYER_ID(), TRUE)
SET_CREATE_RANDOM_COPS(TRUE)
// Turn on the slipstream effect
SET_ENABLE_VEHICLE_SLIPSTREAMING(FALSE)
// Restore scenarios and vehicle gens
REMOVE_SCENARIO_BLOCKING_AREA(sb)
SET_SCENARIO_TYPE_ENABLED("DRIVE", TRUE)
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<<-7000.0, -7000.0, -100.0>>, <<7000.0, 7000.0, 315.0>>, TRUE)
ENDPROC
/// PURPOSE:
/// Turns off ambient peds and vehicles scenarios everything - call this every frame
PROC NO_AMBIENT_MALARKY_THIS_FRAME()
SET_PED_DENSITY_MULTIPLIER_THIS_FRAME(0)
SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0)
SET_SCENARIO_PED_DENSITY_MULTIPLIER_THIS_FRAME(0, 0)
SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0)
SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0)
ENDPROC
/// PURPOSE:
/// Given an array of vectors get the closest index to v
/// PARAMS:
/// v - point to test
/// array - vector array
/// RETURNS:
/// index of closest vector
FUNC INT GET_CLOSEST_INDEX_TO_POINT_IN_VECTOR_ARRRY(VECTOR v, VECTOR& array[])
INT i, ind = 0
FLOAT dist, mindist = -1.0
REPEAT COUNT_OF(array) i
dist = GET_DISTANCE_BETWEEN_COORDS(v, array[i])
IF (dist < mindist) OR (mindist = -1.0)
ind = i
mindist = dist
ENDIF
ENDREPEAT
RETURN ind
ENDFUNC
/// PURPOSE:
/// Returns a position from a static blip
/// PARAMS:
/// blip - blip enum
/// RETURNS:
/// Vector
FUNC VECTOR GET_POSITION_FROM_STATIC_BLIP(STATIC_BLIP_NAME_ENUM blip)
INT iIndex = ENUM_TO_INT(blip)
RETURN g_GameBlips[iIndex].vCoords[0]
ENDFUNC
/// PURPOSE:
/// Catmull Rom Evaulation given 4 points - give us a spline point beteen p1 and p2
/// PARAMS:
/// p0 -
/// p1 -
/// p2 -
/// p3 -
/// t -
/// RETURNS:
///
FUNC VECTOR CALCULATE_SPLINE_POINT(VECTOR& p0, VECTOR& p1, VECTOR& p2, VECTOR& p3, FLOAT t)
VECTOR ret
FLOAT t2 = t * t
FLOAT t3 = t2 * t
//CPRINTLN(DEBUG_AMBIENT, "CALCULATE_SPLINE_POINT - START")
ret.x = 0.5 * ((2.0 * p1.x) +
(-p0.x + p2.x) * t +
(2.0 * p0.x - 5.0 * p1.x + 4 * p2.x - p3.x) * t2 +
(-p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x) * t3)
//CPRINTLN(DEBUG_AMBIENT, " RET X", ret.x)
ret.y = 0.5 * ((2.0 * p1.y) +
(-p0.y + p2.y) * t +
(2.0 * p0.y - 5.0 * p1.y + 4 * p2.y - p3.y) * t2 +
(-p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y) * t3)
//CPRINTLN(DEBUG_AMBIENT, " RET Y", ret.y)
ret.z = 0.5 * ((2.0 * p1.z) +
(-p0.z + p2.z) * t +
(2.0 * p0.z - 5.0 * p1.z + 4 * p2.z - p3.z) * t2 +
(-p0.z + 3.0 * p1.z - 3.0 * p2.z + p3.z) * t3)
//CPRINTLN(DEBUG_AMBIENT, " RET Z", ret.z)
//CPRINTLN(DEBUG_AMBIENT, "CALCULATE_SPLINE_POINT - END")
RETURN ret
ENDFUNC
/// PURPOSE:
/// Gets the position from a static blip
/// PARAMS:
/// blip - blip enum
/// RETURNS:
/// Positon as Vector
FUNC VECTOR GET_STATIC_BLIP_COORDS(STATIC_BLIP_NAME_ENUM blip)
INT ind = ENUM_TO_INT(blip)
RETURN g_GameBlips[ind].vCoords[0]
ENDFUNC
PROC CHECK_AND_CLEAR_HELP()
IF IS_HELP_MESSAGE_BEING_DISPLAYED()
CLEAR_HELP()
ENDIF
ENDPROC
FUNC BOOL IS_ENTITY_SMALLER_THAN_MODEL(ENTITY_INDEX veh, MODEL_NAMES mdl)
VECTOR vmin, vmax
VECTOR mmin, mmax
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(veh), vmin, vmax)
GET_MODEL_DIMENSIONS(mdl, mmin, mmax)
IF ABSF(vmax.x - vmin.x) > ABSF(mmax.x - mmin.x)
RETURN FALSE
ENDIF
IF ABSF(vmax.y - vmin.y) > ABSF(mmax.y - mmin.y)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC