892 lines
25 KiB
Plaintext
892 lines
25 KiB
Plaintext
/*
|
|
* Irresistible Gaming 2018
|
|
* Developed by Lorenc
|
|
* Module: helpers.inc
|
|
* Purpose: functions that help scripting
|
|
*/
|
|
|
|
/* ** Includes ** */
|
|
#include < YSI\y_va >
|
|
|
|
/* ** Macros ** */
|
|
#define function%1(%2) forward%1(%2); public%1(%2)
|
|
#define RandomEx(%0,%1) (random((%1) - (%0)) + (%0))
|
|
#define HOLDING(%0) ((newkeys & (%0)) == (%0))
|
|
#define PRESSED(%0) (((newkeys & (%0)) == (%0)) && ((oldkeys & (%0)) != (%0)))
|
|
#define RELEASED(%0) (((newkeys & (%0)) != (%0)) && ((oldkeys & (%0)) == (%0)))
|
|
#define SendUsage(%0,%1) (SendClientMessageFormatted(%0,-1,"{FFAF00}[USAGE]{FFFFFF} " # %1))
|
|
#define SendError(%0,%1) (SendClientMessageFormatted(%0,-1,"{F81414}[ERROR]{FFFFFF} " # %1))
|
|
#define SendServerMessage(%0,%1) (SendClientMessageFormatted(%0,-1,"{C0C0C0}[SERVER]{FFFFFF} " # %1))
|
|
#define SendClientMessageToAllFormatted(%0) (SendClientMessageFormatted(INVALID_PLAYER_ID, %0))
|
|
#define sprintf(%1) (format(g_szSprintfBuffer, sizeof(g_szSprintfBuffer), %1), g_szSprintfBuffer)
|
|
#define SetObjectInvisible(%0) (SetDynamicObjectMaterialText(%0, 0, " ", 140, "Arial", 64, 1, -32256, 0, 1))
|
|
#define fRandomEx(%1,%2) (floatrandom(%2-%1)+%1)
|
|
#define strmatch(%1,%2) (!strcmp(%1,%2,true))
|
|
#define Beep(%1) PlayerPlaySound(%1, 1137, 0.0, 0.0, 0.0)
|
|
#define StopSound(%1) PlayerPlaySound(%1,1186,0.0,0.0,0.0)
|
|
#define erase(%0) (%0[0]='\0')
|
|
#define positionToString(%0) (%0==1?("st"):(%0==2?("nd"):(%0==3?("rd"):("th"))))
|
|
#define SetPlayerPosEx(%0,%1,%2,%3,%4) SetPlayerPos(%0,%1,%2,%3),SetPlayerInterior(%0,%4)
|
|
#define mysql_single_query(%0) mysql_tquery(dbHandle,(%0),"","")
|
|
#define points_format(%0) (number_format(%0, .prefix = '\0', .decimals = 2))
|
|
#define bool_to_string(%0) (%0 == true ? (COL_GREEN # "YES" # COL_WHITE) : (COL_RED # "NO" # COL_WHITE))
|
|
|
|
// Defines
|
|
#define KEY_AIM (128)
|
|
#define thread function // used to look pretty for mysql
|
|
|
|
/* ** Variables ** */
|
|
stock szSmallString[ 32 ];
|
|
stock szNormalString[ 144 ];
|
|
stock szBigString[ 256 ];
|
|
stock szLargeString[ 1024 ];
|
|
stock szHugeString[ 2048 ];
|
|
stock szMassiveString[ 4096 ];
|
|
stock g_szSprintfBuffer[ 1024 ];
|
|
stock tmpVariable;
|
|
|
|
/* ** Function Hooks ** */
|
|
stock __svrticks__GetTickCount( )
|
|
{
|
|
static
|
|
offset = 0; // store the static value here
|
|
|
|
new
|
|
curr_tickcount = GetTickCount( );
|
|
|
|
if ( curr_tickcount < 0 && offset == 0 )
|
|
{
|
|
offset = curr_tickcount * -1;
|
|
print( "\n\n*** NEGATIVE TICK COUNT DETECTED... FIXING GetTickCount( )" );
|
|
}
|
|
return curr_tickcount + offset;
|
|
}
|
|
|
|
#if defined _ALS_GetTickCount
|
|
#undef GetTickCount
|
|
#else
|
|
#define _ALS_GetTickCount
|
|
#endif
|
|
|
|
#define GetTickCount __svrticks__GetTickCount
|
|
|
|
/* ** Functions ** */
|
|
stock SendClientMessageFormatted( playerid, colour, const format[ ], va_args<> )
|
|
{
|
|
static
|
|
out[ 144 ];
|
|
|
|
va_format( out, sizeof( out ), format, va_start<3> );
|
|
|
|
if ( playerid == INVALID_PLAYER_ID ) {
|
|
return SendClientMessageToAll( colour, out );
|
|
} else {
|
|
return SendClientMessage( playerid, colour, out );
|
|
}
|
|
}
|
|
|
|
// purpose: send client message to all rcon admins
|
|
stock SendClientMessageToRCON( colour, const format[ ], va_args<> )
|
|
{
|
|
static
|
|
out[ 144 ];
|
|
|
|
va_format( out, sizeof( out ), format, va_start<2> );
|
|
|
|
foreach ( new i : Player ) if ( IsPlayerAdmin( i ) ) {
|
|
SendClientMessage( i, colour, out );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// purpose: trim a string
|
|
stock trimString( strSrc[ ] )
|
|
{
|
|
new
|
|
strPos
|
|
;
|
|
for( strPos = strlen( strSrc ); strSrc[ strPos ] <= ' '; )
|
|
strPos--;
|
|
|
|
strSrc[ strPos + 1 ] = EOS;
|
|
|
|
for( strPos = 0; strSrc[ strPos ] <= ' '; )
|
|
strPos++;
|
|
|
|
strdel( strSrc, 0, strPos );
|
|
}
|
|
|
|
// purpose: clear chat for player
|
|
stock Player_Clearchat( playerid )
|
|
{
|
|
for ( new j = 0; j < 30; j ++ ) {
|
|
SendClientMessage( playerid, -1, " " );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// purpose: get distance between players
|
|
stock Float: GetDistanceBetweenPlayers( iPlayer1, iPlayer2, &Float: fDistance = Float: 0x7F800000, bool: bAllowNpc = false )
|
|
{
|
|
static
|
|
Float: fX, Float: fY, Float: fZ;
|
|
|
|
if ( ! bAllowNpc && ( IsPlayerNPC( iPlayer1 ) || IsPlayerNPC( iPlayer2 ) ) ) // since this command is designed for players
|
|
return fDistance;
|
|
|
|
if( GetPlayerVirtualWorld( iPlayer1 ) == GetPlayerVirtualWorld( iPlayer2 ) && GetPlayerPos( iPlayer2, fX, fY, fZ ) )
|
|
fDistance = GetPlayerDistanceFromPoint( iPlayer1, fX, fY, fZ );
|
|
|
|
return fDistance;
|
|
}
|
|
|
|
// purpose: sets float precision (0.2313131 = 0.2300000)
|
|
stock Float: SetFloatPrecision( Float: fValue, iPrecision ) {
|
|
new
|
|
Float: fFinal,
|
|
Float: fFraction = floatfract( fValue )
|
|
;
|
|
|
|
fFinal = fFraction * floatpower( 10.0, iPrecision );
|
|
fFinal -= floatfract( fFinal );
|
|
fFinal /= floatpower( 10.0, iPrecision );
|
|
|
|
return ( fFinal + fValue - fFraction );
|
|
}
|
|
|
|
// purpose: get distance between 2d points
|
|
stock Float: GetDistanceFromPointToPoint( Float: fX, Float: fY, Float: fX1, Float: fY1 )
|
|
return Float: floatsqroot( floatpower( fX - fX1, 2 ) + floatpower( fY - fY1, 2 ) );
|
|
|
|
// purpose: get distance between 3d points
|
|
stock Float: GetDistanceBetweenPoints( Float: x1, Float: y1, Float: z1, Float: x2, Float: y2, Float: z2 )
|
|
return VectorSize( x1 - x2, y1 - y2, z1 - z2 );
|
|
|
|
// purpose: return raw distance without square root
|
|
stock Float: GetDistanceFromPlayerSquared( playerid, Float: x1, Float: y1, Float: z1 ) {
|
|
new
|
|
Float: x2, Float: y2, Float: z2;
|
|
|
|
if( !GetPlayerPos( playerid, x2, y2, z2 ) )
|
|
return FLOAT_INFINITY;
|
|
|
|
x1 -= x2;
|
|
x1 *= x1;
|
|
y1 -= y2;
|
|
y1 *= y1;
|
|
z1 -= z2;
|
|
z1 *= z1;
|
|
return ( x1 + y1 + z1 );
|
|
}
|
|
|
|
// purpose: random float number support
|
|
stock Float: floatrandom( Float:max )
|
|
return floatmul( floatdiv( float( random( cellmax ) ), float( cellmax - 1 ) ), max );
|
|
|
|
// purpose: replace a character
|
|
stock strreplacechar(string[], oldchar, newchar)
|
|
{
|
|
new matches;
|
|
if (ispacked(string)) {
|
|
if (newchar == '\0') {
|
|
for(new i; string{i} != '\0'; i++) {
|
|
if (string{i} == oldchar) {
|
|
strdel(string, i, i + 1);
|
|
matches++;
|
|
}
|
|
}
|
|
} else {
|
|
for(new i; string{i} != '\0'; i++) {
|
|
if (string{i} == oldchar) {
|
|
string{i} = newchar;
|
|
matches++;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (newchar == '\0') {
|
|
for(new i; string[i] != '\0'; i++) {
|
|
if (string[i] == oldchar) {
|
|
strdel(string, i, i + 1);
|
|
matches++;
|
|
}
|
|
}
|
|
} else {
|
|
for(new i; string[i] != '\0'; i++) {
|
|
if (string[i] == oldchar) {
|
|
string[i] = newchar;
|
|
matches++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
// purpose: replaces a phrase in a string with whatever specified (credit Slice)
|
|
stock strreplace(string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1, maxlength = sizeof(string)) {
|
|
// No need to do anything if the limit is 0.
|
|
if (limit == 0)
|
|
return 0;
|
|
|
|
new
|
|
sublen = strlen(search),
|
|
replen = strlen(replacement),
|
|
bool:packed = ispacked(string),
|
|
maxlen = maxlength,
|
|
len = strlen(string),
|
|
count = 0
|
|
;
|
|
|
|
|
|
// "maxlen" holds the max string length (not to be confused with "maxlength", which holds the max. array size).
|
|
// Since packed strings hold 4 characters per array slot, we multiply "maxlen" by 4.
|
|
if (packed)
|
|
maxlen *= 4;
|
|
|
|
// If the length of the substring is 0, we have nothing to look for..
|
|
if (!sublen)
|
|
return 0;
|
|
|
|
// In this line we both assign the return value from "strfind" to "pos" then check if it's -1.
|
|
while (-1 != (pos = strfind(string, search, ignorecase, pos))) {
|
|
// Delete the string we found
|
|
strdel(string, pos, pos + sublen);
|
|
|
|
len -= sublen;
|
|
|
|
// If there's anything to put as replacement, insert it. Make sure there's enough room first.
|
|
if (replen && len + replen < maxlen) {
|
|
strins(string, replacement, pos, maxlength);
|
|
|
|
pos += replen;
|
|
len += replen;
|
|
}
|
|
|
|
// Is there a limit of number of replacements, if so, did we break it?
|
|
if (limit != -1 && ++count >= limit)
|
|
break;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// purpose: copy a string from a source to a destination
|
|
/*stock strcpy(dest[], const source[], maxlength=sizeof dest) {
|
|
strcat((dest[0] = EOS, dest), source, maxlength);
|
|
}*/
|
|
|
|
// purpose: get unattached player object index
|
|
stock Player_GetUnusedAttachIndex( playerid )
|
|
{
|
|
for ( new i = 0; i < MAX_PLAYER_ATTACHED_OBJECTS; i ++ )
|
|
if ( ! IsPlayerAttachedObjectSlotUsed( playerid, i ) )
|
|
return i;
|
|
|
|
return cellmin;
|
|
}
|
|
|
|
// purpose: convert integer into dollar string (large credit to Slice - i just added a prefix parameter)
|
|
stock number_format( { _, Float, Text3D, Menu, Text, DB, DBResult, bool, File }: variable, prefix = '\0', decimals = -1, thousand_seperator = ',', decimal_point = '.', tag = tagof( variable ) )
|
|
{
|
|
static
|
|
s_szReturn[ 32 ],
|
|
s_szThousandSeparator[ 2 ] = { ' ', EOS },
|
|
s_iDecimalPos,
|
|
s_iChar,
|
|
s_iSepPos
|
|
;
|
|
|
|
if ( tag == tagof( bool: ) )
|
|
{
|
|
if ( variable )
|
|
memcpy( s_szReturn, "true", 0, 5 * ( cellbits / 8 ) );
|
|
else
|
|
memcpy( s_szReturn, "false", 0, 6 * ( cellbits / 8 ) );
|
|
|
|
return s_szReturn;
|
|
}
|
|
else if ( tag == tagof( Float: ) )
|
|
{
|
|
if ( decimals == -1 )
|
|
decimals = 8;
|
|
|
|
format( s_szReturn, sizeof( s_szReturn ), "%.*f", decimals, variable );
|
|
}
|
|
else
|
|
{
|
|
format( s_szReturn, sizeof( s_szReturn ), "%d", variable );
|
|
|
|
if ( decimals > 0 )
|
|
{
|
|
strcat( s_szReturn, "." );
|
|
|
|
while ( decimals-- )
|
|
strcat( s_szReturn, "0" );
|
|
}
|
|
}
|
|
|
|
s_iDecimalPos = strfind( s_szReturn, "." );
|
|
|
|
if ( s_iDecimalPos == -1 )
|
|
s_iDecimalPos = strlen( s_szReturn );
|
|
else
|
|
s_szReturn[ s_iDecimalPos ] = decimal_point;
|
|
|
|
if ( s_iDecimalPos >= 4 && thousand_seperator )
|
|
{
|
|
s_szThousandSeparator[ 0 ] = thousand_seperator;
|
|
|
|
s_iChar = s_iDecimalPos;
|
|
s_iSepPos = 0;
|
|
|
|
while ( --s_iChar > 0 )
|
|
{
|
|
if ( ++s_iSepPos == 3 && s_szReturn[ s_iChar - 1 ] != '-' )
|
|
{
|
|
strins( s_szReturn, s_szThousandSeparator, s_iChar );
|
|
|
|
s_iSepPos = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( prefix != '\0' )
|
|
{
|
|
static
|
|
prefix_string[ 2 ];
|
|
|
|
prefix_string[ 0 ] = prefix;
|
|
strins( s_szReturn, prefix_string, s_szReturn[ 0 ] == '-' ); // no point finding -
|
|
}
|
|
return s_szReturn;
|
|
}
|
|
|
|
#define cash_format(%0) \
|
|
(number_format(%0, .prefix = '$'))
|
|
|
|
// purpose: find a random element in sample space, excluding [a, b, c, ...]
|
|
stock randomExcept( except[ ], len = sizeof( except ), available_element_value = -1 ) {
|
|
|
|
new bool: any_available_elements = false;
|
|
|
|
// we will check if there are any elements that are not in except[]
|
|
for ( new x = 0; x < len; x ++ ) if ( except[ x ] == available_element_value ) {
|
|
any_available_elements = true;
|
|
break;
|
|
}
|
|
|
|
// if all elements are included in except[], prevent continuing otherwise it will infinite loop
|
|
if ( ! any_available_elements ) {
|
|
return -1;
|
|
}
|
|
|
|
new random_number = random( len );
|
|
|
|
// use recursion to find another element
|
|
for ( new x = 0; x < len; x ++ ) {
|
|
if ( random_number == except[ x ] ) {
|
|
return randomExcept( except, len );
|
|
}
|
|
}
|
|
return random_number;
|
|
}
|
|
|
|
// purpose: generate a random string up to a length
|
|
stock randomString( strDest[ ], strLen = 10 ) {
|
|
while ( strLen -- ) {
|
|
strDest[ strLen ] = random( 2 ) ? ( random( 26 ) + ( random( 2 ) ? 'a' : 'A' ) ) : ( random( 10 ) + '0' );
|
|
}
|
|
}
|
|
|
|
// purpose: check if a string contains an IP address
|
|
stock textContainsIP(const string[])
|
|
{
|
|
#if defined _regex_included
|
|
static
|
|
RegEx: rCIP;
|
|
|
|
if ( ! rCIP ) {
|
|
rCIP = regex_build( "(.*?)([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})(.*?)" );
|
|
}
|
|
return regex_match_exid( string, rCIP );
|
|
#else
|
|
#warning "You are not using a regex plugin for textContainsIP!"
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
// purpose: get the driver of a vehicle
|
|
stock GetVehicleDriver( vehicleid )
|
|
{
|
|
foreach(new i : Player)
|
|
if ( IsPlayerInVehicle( i, vehicleid ) && GetPlayerState( i ) == PLAYER_STATE_DRIVER )
|
|
return i;
|
|
|
|
return INVALID_PLAYER_ID;
|
|
}
|
|
|
|
// purpose: check if there's an even number of ~ in a string
|
|
stock IsSafeGameText(const string[])
|
|
{
|
|
new count;
|
|
for(new num, len = strlen(string); num < len; num++)
|
|
{
|
|
if (string[num] == '~')
|
|
{
|
|
if ((num + 1) < len)
|
|
{
|
|
if (string[(num + 1)] == '~') return false;
|
|
}
|
|
count += 1;
|
|
}
|
|
}
|
|
if ((count % 2) > 0) return false;
|
|
return true;
|
|
}
|
|
|
|
// purpose: censor a string up to n characters
|
|
stock CensoreString( query[ ], characters = 5 )
|
|
{
|
|
static
|
|
szString[ 256 ];
|
|
|
|
format( szString, 256, query );
|
|
strdel( szString, 0, characters );
|
|
|
|
for( new i = 0; i < characters; i++ )
|
|
strins( szString, "*", 0 );
|
|
|
|
return szString;
|
|
}
|
|
|
|
// purpose: return current date as DD/MM/YYYY
|
|
stock getCurrentDate( )
|
|
{
|
|
static
|
|
Year, Month, Day,
|
|
szString[ 11 ]
|
|
;
|
|
|
|
getdate( Year, Month, Day );
|
|
format( szString, sizeof( szString ), "%02d/%02d/%d", Day, Month, Year );
|
|
return szString;
|
|
}
|
|
|
|
// purpose: return current time as HH:MM:SS
|
|
stock getCurrentTime( )
|
|
{
|
|
static
|
|
Hour, Minute, Second,
|
|
szString[ 11 ]
|
|
;
|
|
|
|
gettime( Hour, Minute, Second );
|
|
format( szString, sizeof( szString ), "%02d:%02d:%02d", Hour, Minute, Second );
|
|
return szString;
|
|
}
|
|
|
|
// purpose: check if a player is in water (credit: SuperViper)
|
|
stock IsPlayerInWater(playerid)
|
|
{
|
|
new animationIndex = GetPlayerAnimationIndex(playerid);
|
|
return (animationIndex >= 1538 && animationIndex <= 1544 && animationIndex != 1542);
|
|
}
|
|
|
|
// purpose: return a random argument
|
|
stock randarg( ... )
|
|
return getarg( random( numargs( ) ) );
|
|
|
|
// purpose: remove a weapon(s) from a player (credit: ryder`?)
|
|
stock RemovePlayerWeapon(playerid, ...)
|
|
{
|
|
new iArgs = numargs();
|
|
while(--iArgs)
|
|
{
|
|
SetPlayerAmmo(playerid, getarg(iArgs), 0);
|
|
}
|
|
}
|
|
|
|
// purpose: check if a weapon id is a melee weapon id
|
|
stock IsMeleeWeapon(value) {
|
|
static const valid_values[2] = {
|
|
65535, 28928
|
|
};
|
|
if (0 <= value <= 46) {
|
|
return (valid_values[value >>> 5] & (1 << (value & 31))) || false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// purpose: check if a specific vehicle is upside down
|
|
stock IsVehicleUpsideDown(vehicleid)
|
|
{
|
|
new
|
|
Float: q_W,
|
|
Float: q_X,
|
|
Float: q_Y,
|
|
Float: q_Z
|
|
;
|
|
GetVehicleRotationQuat(vehicleid, q_W, q_X, q_Y, q_Z);
|
|
return (120.0 < atan2(2.0 * ((q_Y * q_Z) + (q_X * q_W)), (-(q_X * q_X) - (q_Y * q_Y) + (q_Z * q_Z) + (q_W * q_W))) > -120.0);
|
|
}
|
|
|
|
// purpose: convert seconds into a human readable string (credit: BlackLite?)
|
|
stock secondstotime(seconds, const delimiter[] = ", ", start = 0, end = -1)
|
|
{
|
|
static const times[] = {
|
|
1,
|
|
60,
|
|
3600,
|
|
86400,
|
|
604800,
|
|
2419200,
|
|
29030400
|
|
};
|
|
|
|
static const names[][] = {
|
|
"second",
|
|
"minute",
|
|
"hour",
|
|
"day",
|
|
"week",
|
|
"month",
|
|
"year"
|
|
};
|
|
|
|
static string[128];
|
|
|
|
if (!seconds)
|
|
{
|
|
string = "N/A";
|
|
return string;
|
|
}
|
|
|
|
erase(string);
|
|
|
|
for(new i = start != 0 ? start : (sizeof(times) - 1); i != end; i--)
|
|
{
|
|
if (seconds / times[i])
|
|
{
|
|
if (string[0])
|
|
{
|
|
format(string, sizeof(string), "%s%s%d %s%s", string, delimiter, (seconds / times[i]), names[i], ((seconds / times[i]) == 1) ? ("") : ("s"));
|
|
}
|
|
else
|
|
{
|
|
format(string, sizeof(string), "%d %s%s", (seconds / times[i]), names[i], ((seconds / times[i]) == 1) ? ("") : ("s"));
|
|
}
|
|
seconds -= ((seconds / times[i]) * times[i]);
|
|
}
|
|
}
|
|
return string;
|
|
}
|
|
|
|
// purpose: check if a string is bad for textdraws / crashy
|
|
stock textContainsBadTextdrawLetters( const string[ ] )
|
|
{
|
|
for( new i, j = strlen( string ); i < j; i++ )
|
|
{
|
|
if ( string[ i ] == '.' || string[ i ] == '*' || string[ i ] == '^' || string[ i ] == '~' )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// purpose: check if a valid skin id was selected
|
|
stock IsValidSkin( skinid ) {
|
|
return ! ( skinid == 74 || skinid > 311 || skinid < 0 );
|
|
}
|
|
|
|
// purpose: check if a string is hexidecimal (credit: dracoblue)
|
|
stock isHex(str[])
|
|
{
|
|
new
|
|
i,
|
|
cur;
|
|
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) i = 2;
|
|
while (str[i])
|
|
{
|
|
cur = str[i++];
|
|
if (!(('0' <= cur <= '9') || ('A' <= cur <= 'F') || ('a' <= cur <= 'f'))) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// purpose: check if a player has a weapon on them
|
|
stock IsWeaponInAnySlot( playerid, weaponid )
|
|
{
|
|
new
|
|
szWeapon, szAmmo;
|
|
|
|
GetPlayerWeaponData( playerid, GetWeaponSlot( weaponid ), szWeapon, szAmmo );
|
|
return ( szWeapon == weaponid && szAmmo > 0 );
|
|
}
|
|
|
|
// purpose: check if a player is within an area (min, max)
|
|
stock IsPlayerInArea( playerid, Float: minx, Float: maxx, Float: miny, Float: maxy )
|
|
{
|
|
static
|
|
Float: X, Float: Y, Float: Z;
|
|
|
|
if ( GetPlayerPos( playerid, X, Y, Z ) )
|
|
return ( X > minx && X < maxx && Y > miny && Y < maxy );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// purpose (deprecated): moves the player a smige so that objects can load
|
|
stock SyncObject( playerid, Float: offsetX = 0.005, Float: offsetY = 0.005, Float: offsetZ = 0.005 )
|
|
{
|
|
static
|
|
Float: X, Float: Y, Float: Z;
|
|
|
|
if ( GetPlayerPos( playerid, X, Y, Z ) )
|
|
SetPlayerPos( playerid, X + offsetX, Y + offsetY, Z + offsetZ );
|
|
}
|
|
|
|
// purpose: check if a point is within an area
|
|
stock IsPointInArea( Float: X, Float: Y, Float: Z, Float: minx, Float: maxx, Float: miny, Float: maxy, Float: minz, Float: maxz )
|
|
return ( X > minx && X < maxx && Y > miny && Y < maxy && Z > minz && Z < maxz );
|
|
|
|
// purpose: convert a string into hexidecimal number (credit: DracoBlue)
|
|
stock HexToInt( string[ ] )
|
|
{
|
|
if ( isnull( string ) )
|
|
return 0;
|
|
|
|
new
|
|
cur = 1,
|
|
res = 0
|
|
;
|
|
|
|
for( new i; string[ i ] != EOS; ++i )
|
|
{
|
|
string[ i ] = ( 'a' <= string[ i ] <= 'z' ) ? ( string[ i ] += 'A' - 'a' ) : ( string[ i ] );
|
|
}
|
|
|
|
for( new i = strlen( string ); i > 0; i-- )
|
|
{
|
|
res += string[ i - 1 ] < 58 ? ( cur * ( string[ i - 1 ] - 48 ) ) : ( cur * ( string[ i - 1 ] - 65 + 10 ) );
|
|
cur *= 16;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// purpose: get the closest vehicle id to the player
|
|
stock GetClosestVehicle(playerid, except = INVALID_VEHICLE_ID, &Float: distance = Float: 0x7F800000) {
|
|
new
|
|
i,
|
|
Float: X,
|
|
Float: Y,
|
|
Float: Z
|
|
;
|
|
if (GetPlayerPos(playerid, X, Y, Z)) {
|
|
new
|
|
Float: dis,
|
|
closest = INVALID_VEHICLE_ID
|
|
;
|
|
while(i != MAX_VEHICLES) {
|
|
if (0.0 < (dis = GetVehicleDistanceFromPoint(++i, X, Y, Z)) < distance && i != except) {
|
|
distance = dis;
|
|
closest = i;
|
|
}
|
|
}
|
|
return closest;
|
|
}
|
|
return INVALID_VEHICLE_ID;
|
|
}
|
|
|
|
// purpose: check if a point is near to another point
|
|
stock IsPointToPoint(Float: fRadius, Float: fX1, Float: fY1, Float: fZ1, Float: fX2, Float: fY2, Float: fZ2)
|
|
return ((-fRadius < floatabs(fX2 - fX1) < fRadius) && (-fRadius < floatabs(fY2 - fY1) < fRadius) && (-fRadius < floatabs(fZ2 - fZ1) < fRadius));
|
|
|
|
// purpose: get the X, Y in front of a player at N distance
|
|
stock GetXYInFrontOfPlayer(playerid, &Float:x, &Float:y, &Float:z, Float:distance)
|
|
{
|
|
new Float: a;
|
|
GetPlayerPos(playerid, x, y, z);
|
|
GetPlayerFacingAngle(playerid, a);
|
|
if (GetPlayerVehicleID( playerid ))
|
|
{
|
|
GetVehicleZAngle(GetPlayerVehicleID( playerid ), a);
|
|
}
|
|
x += (distance * floatsin(-a, degrees));
|
|
y += (distance * floatcos(-a, degrees));
|
|
}
|
|
|
|
// purpose: change a vehicle's model with an object id ... doozy function
|
|
stock ChangeVehicleModel( vehicleid, objectid, Float: offset = 0.0 )
|
|
{
|
|
new
|
|
iObject
|
|
;
|
|
iObject = CreateDynamicObject( objectid, 0.0, 0.0, 0.0, 0, 0, 0 );
|
|
AttachDynamicObjectToVehicle( iObject, vehicleid, 0, 0, 0, 0, 0, 0 + offset );
|
|
LinkVehicleToInterior( vehicleid, 12 );
|
|
}
|
|
|
|
// purpose: make an object face a specific point
|
|
stock SetObjectFacePoint(iObjectID, Float: fX, Float: fY, Float: fOffset, bool: bDynamic = false )
|
|
{
|
|
new
|
|
Float: fOX,
|
|
Float: fOY,
|
|
Float: fRZ
|
|
;
|
|
if ( bDynamic )
|
|
{
|
|
if (GetDynamicObjectPos(iObjectID, fOX, fOY, fRZ))
|
|
{
|
|
fRZ = atan2(fY - fOY, fX - fOX) - 90.0;
|
|
|
|
GetDynamicObjectRot(iObjectID, fX, fY, fOX);
|
|
SetDynamicObjectRot(iObjectID, fX, fY, fRZ + fOffset);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetObjectPos(iObjectID, fOX, fOY, fRZ))
|
|
{
|
|
fRZ = atan2(fY - fOY, fX - fOX) - 90.0;
|
|
|
|
GetObjectRot(iObjectID, fX, fY, fOX);
|
|
SetObjectRot(iObjectID, fX, fY, fRZ + fOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
// purpose: convert seconds into a MM:SS format e.g 10:00 ... good for racing
|
|
stock TimeConvert( seconds )
|
|
{
|
|
static
|
|
szTime[ 32 ]
|
|
;
|
|
format( szTime, sizeof( szTime ), "%02d:%02d", floatround( seconds / 60 ), seconds - floatround( ( seconds / 60 ) * 60 ) );
|
|
return szTime;
|
|
}
|
|
|
|
// purpose: make the player face a specific point
|
|
stock SetPlayerFacePoint(playerid, Float: fX, Float: fY, Float: offset = 0.0)
|
|
{
|
|
static
|
|
Float: X,
|
|
Float: Y,
|
|
Float: Z,
|
|
Float: face
|
|
;
|
|
if (GetPlayerPos(playerid, X, Y, Z))
|
|
{
|
|
face = atan2(fY - Y, fX - X) - 90.0;
|
|
SetPlayerFacingAngle(playerid, face + offset);
|
|
}
|
|
}
|
|
|
|
// purpose: get the closest player to the player
|
|
stock GetClosestPlayer( playerid, &Float: distance = FLOAT_INFINITY ) {
|
|
new
|
|
iCurrent = INVALID_PLAYER_ID,
|
|
Float: fX, Float: fY, Float: fZ, Float: fTmp,
|
|
world = GetPlayerVirtualWorld( playerid )
|
|
;
|
|
|
|
if ( GetPlayerPos( playerid, fX, fY, fZ ) )
|
|
{
|
|
foreach(new i : Player)
|
|
{
|
|
if ( i != playerid )
|
|
{
|
|
if ( GetPlayerState( i ) != PLAYER_STATE_SPECTATING && GetPlayerVirtualWorld( i ) == world )
|
|
{
|
|
if ( 0.0 < ( fTmp = GetDistanceFromPlayerSquared( i, fX, fY, fZ ) ) < distance ) // Y_Less mentioned there's no need to sqroot
|
|
{
|
|
distance = fTmp;
|
|
iCurrent = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return iCurrent;
|
|
}
|
|
|
|
// purpose: place a player in a vehicle with an available seat
|
|
stock PutPlayerInEmptyVehicleSeat( vehicleid, playerid )
|
|
{
|
|
new
|
|
vModel = GetVehicleModel( vehicleid ),
|
|
bool: bNonAvailable[ 16 char ],
|
|
seats = 0xF
|
|
;
|
|
|
|
if ( !IsValidVehicle( vehicleid ) )
|
|
return -1;
|
|
|
|
if ( vModel == 425 || vModel == 481 || vModel == 520 || vModel == 519 || vModel == 509 || vModel == 510 || vModel == 476 )
|
|
return -1;
|
|
|
|
foreach(new iPlayer : Player)
|
|
{
|
|
if ( IsPlayerInVehicle( iPlayer, vehicleid ) )
|
|
{
|
|
new iVehicle = GetPlayerVehicleSeat( iPlayer );
|
|
seats = GetVehicleSeatCount( GetVehicleModel( iVehicle ) );
|
|
|
|
if ( seats == 0xF )
|
|
return -1; // Just so the player aint bugged.
|
|
|
|
if ( iVehicle >= 0 && iVehicle <= seats ) bNonAvailable{ iVehicle } = true;
|
|
}
|
|
}
|
|
for( new i = 1; i < sizeof( bNonAvailable ); i++ )
|
|
{
|
|
if ( !bNonAvailable{ i } ) {
|
|
SetPlayerVirtualWorld( playerid, GetVehicleVirtualWorld( vehicleid ) );
|
|
SetPlayerInterior( playerid, 0 ); // All vehicles are in interior ID 0, unless a stupid did this :|
|
|
PutPlayerInVehicle( playerid, vehicleid, i );
|
|
break;
|
|
}
|
|
}
|
|
return seats;
|
|
}
|
|
|
|
// purpose: get the player id from a name
|
|
stock GetPlayerIDFromName( const pName[ ] )
|
|
{
|
|
foreach(new i : Player)
|
|
{
|
|
if ( strmatch( pName, ReturnPlayerName( i ) ) )
|
|
return i;
|
|
}
|
|
return INVALID_PLAYER_ID;
|
|
}
|
|
|
|
// purpose (deprecated): quickly write/append a line to a file
|
|
stock AddFileLogLine( const file[ ], input[ ] )
|
|
{
|
|
new
|
|
File: fHandle;
|
|
|
|
fHandle = fopen(file, io_append);
|
|
fwrite(fHandle, input);
|
|
fclose(fHandle);
|
|
return 1;
|
|
}
|
|
|
|
// purpose: check if a string is numeric
|
|
stock IsNumeric(const str[ ])
|
|
{
|
|
new len = strlen(str);
|
|
|
|
if (!len) return false;
|
|
for(new i; i < len; i++)
|
|
{
|
|
if (!('0' <= str[i] <= '9')) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// purpose: set a server rule
|
|
stock SetServerRule( const rule[ ], const value[ ] ) {
|
|
return SendRconCommand( sprintf( "%s %s", rule, value ) );
|
|
} |