Загрузка данных
#include < amxmisc >
#include < fakemeta >
#include < reapi >
#include < json >
#define MAX_SPAWN_POINTS 128
#define INVALID_SPAWN -1
enum _: SpawnData
{
Float: data_origin[ 3 ],
Float: data_v_angle[ 3 ]
};
new Array: m_aSpawnPointsVec,
Array: m_aDefaultSpawnPointsVec;
new m_iLastSpawnId = INVALID_SPAWN,
m_iSpawnCount,
m_iDefaultSpawnCount,
bool: m_bUsingCustomSpawns;
new m_szMapName[ 32 ],
m_szFilePath[ PLATFORM_MAX_PATH ];
public plugin_precache( )
{
register_plugin( "Spawn points", "0.0.1", "oxsi. x Vision" );
}
public plugin_init( )
{
m_aSpawnPointsVec = ArrayCreate( SpawnData );
m_aDefaultSpawnPointsVec = ArrayCreate( );
if ( m_iSpawnCount > 0 )
@Active_CustomSpawnPoints( );
if ( !m_bUsingCustomSpawns )
@Load_DefaultSpawnPoints( );
RegisterHookChain( RG_CSGameRules_GetPlayerSpawnSpot, "@CSGameRules_GetPlayerSpawnSpot_Pre", false );
register_clcmd( "say /spawns", "@Open_SpawnPoints_Menu" );
register_menucmd( register_menuid( "@Display_SpawnPoints_Menu" ), ( 1 << 0 | 1 << 1 | 1 << 9 ), "@Handler_SpawnPoints_Menu" );
}
public plugin_cfg( )
{
@Load_CustomSpawnPoints( );
server_print( "Map: %s | Points: %d | Custom: %s", m_szMapName, m_iSpawnCount, m_bUsingCustomSpawns ? "yes" : "no" );
}
public plugin_end( )
{
ArrayDestroy( m_aSpawnPointsVec );
ArrayDestroy( m_aDefaultSpawnPointsVec );
}
@Open_SpawnPoints_Menu( id )
{
return @Display_SpawnPoints_Menu( id );
}
@Display_SpawnPoints_Menu( id )
{
new menu[ 512 ], key = ( 1 << 9 ),
len = add( menu, charsmax( menu ), "\ySpawn points^n^n" );
add( menu[ len ], charsmax( menu ) - len, "\y1. \wAdd points at current position.^n" );
key |= ( 1 << 0 );
add( menu[ len ], charsmax( menu ) - len, "^n^n\y0. \wExit" );
return show_menu( id, key, menu, -1, "@Display_SpawnPoints_Menu" );
}
@Handler_SpawnPoints_Menu( id, key )
{
switch ( key )
{
case 0: @Add_SpawnPoint( id );
case 9: return;
}
}
@CSGameRules_GetPlayerSpawnSpot_Pre( id )
{
if ( TEAM_TERRORIST > get_member( id, m_iTeam ) > TEAM_CT )
return HC_CONTINUE;
new spot = @Select_SpawnPoint( id );
if ( is_nullent( spot ) )
return HC_CONTINUE;
new Float: origin[ 3 ], Float: angles[ 3 ], Float: v_angle[ 3 ];
get_entvar( spot, var_origin, origin );
get_entvar( spot, var_angles, angles );
get_entvar( spot, var_v_angle, v_angle );
origin[ 2 ] += 1.0;
set_entvar( id, var_origin, origin );
set_entvar( id, var_angles, angles );
set_entvar( id, var_v_angle, v_angle );
set_entvar( id, var_velocity, NULL_VECTOR );
set_entvar( id, var_punchangle, NULL_VECTOR );
set_entvar( id, var_fixangle, 1 );
SetHookChainReturn( ATYPE_INTEGER, spot );
return HC_SUPERCEDE;
}
@Select_SpawnPoint( id )
{
if ( m_iDefaultSpawnCount <= 0 )
return 0;
new spot, Float: origin[ 3 ];
for ( new attempt = 0; attempt < m_iDefaultSpawnCount; attempt++ )
{
m_iLastSpawnId++;
if ( m_iLastSpawnId >= m_iDefaultSpawnCount )
m_iLastSpawnId = 0;
spot = ArrayGetCell( m_aDefaultSpawnPointsVec, m_iLastSpawnId );
if ( is_nullent( spot ) )
continue;
get_entvar( spot, var_origin, origin );
if ( !@is_hull_vacant( id, origin ) )
continue;
return spot;
}
return 0;
}
@Load_CustomSpawnPoints( )
{
get_mapname( m_szMapName, charsmax( m_szMapName ) );
new cfgsDir[ PLATFORM_MAX_PATH ];
get_localinfo( "amxx_configsdir", cfgsDir, charsmax( cfgsDir ) );
if ( !dir_exists( cfgsDir ) )
{
set_fail_state( "Directory '%s' not found.", cfgsDir );
return;
}
formatex( m_szFilePath, charsmax( m_szFilePath ), "%s/spawns.json", cfgsDir );
if ( !file_exists( m_szFilePath ) )
{
set_fail_state( "File '%s' not found.", m_szFilePath );
return;
}
new JSON: root = json_parse( m_szFilePath, true );
if ( root == Invalid_JSON || !json_is_object( root ) )
{
json_free( root );
set_fail_state( "Parsing file '%s' error.", m_szFilePath );
return;
}
new JSON: points = json_object_get_value( root, m_szMapName );
if ( points == Invalid_JSON || !json_is_object( points ) )
{
json_free( points );
return;
}
new count = json_array_get_count( points );
for ( new i = 0; i < count && i < MAX_SPAWN_POINTS; i++ )
{
new JSON: point = json_array_get_value( points, i );
if ( point == Invalid_JSON || !json_is_object( point ) )
{
json_free( point );
continue;
}
new JSON: origin = json_object_get_value( point, "origin" );
new JSON: v_angle = json_object_get_value( point, "v_angle" );
if ( origin == Invalid_JSON || v_angle == Invalid_JSON || !json_is_array( origin ) || !json_is_array( v_angle ) || json_array_get_count( origin ) < 3 || json_array_get_count( v_angle ) < 3 )
{
json_free( origin );
json_free( v_angle );
json_free( point );
continue;
}
new data[ SpawnData ];
for ( new axis = 0; axis < 3; axis++ )
{
data[ data_origin ][ axis ] = json_array_get_real( origin, axis );
data[ data_v_angle ][ axis ] = json_array_get_real( v_angle, axis );
}
ArrayPushArray( m_aSpawnPointsVec, data );
m_iSpawnCount = ArraySize( m_aSpawnPointsVec );
json_free( origin );
json_free( v_angle );
json_free( point );
}
json_free( points );
json_free( root );
}
bool: @Save_CustomSpawnPoints( )
{
new JSON: root;
if ( file_exists( m_szFilePath ) )
root = json_parse( m_szFilePath, true );
else
root = Invalid_JSON;
if ( root == Invalid_JSON || !json_is_object( root ) )
{
json_free( root );
root = json_init_object( );
}
if ( m_iSpawnCount == 0 )
json_object_remove( root, m_szMapName );
else
{
new JSON: points = json_init_array( );
for ( new i = 0; i < m_iSpawnCount; i++ )
{
new data[ SpawnData ];
ArrayGetArray( m_aSpawnPointsVec, i, data );
new JSON: point = json_init_object( );
new JSON: origin = json_init_array( );
new JSON: v_angle = json_init_array( );
for ( new axis = 0; axis < 3; axis++ )
{
json_array_append_real( origin, data[ data_origin ][ axis ] );
json_array_append_real( v_angle, data[ data_v_angle ][ axis ] );
}
json_object_set_value( point, "origin", origin );
json_object_set_value( point, "v_angle", v_angle );
json_array_append_value( points, point );
json_free( origin );
json_free( v_angle );
json_free( point );
}
json_object_set_value( root, m_szMapName, points );
json_free( points );
}
new bool: succes = json_serial_to_file( root, m_szFilePath, true );
json_free( root );
if ( !succes )
log_amx( "Failed to write %s", m_szFilePath );
return succes;
}
@Load_DefaultSpawnPoints( )
{
new entity = NULLENT;
while ( ( entity = rg_find_ent_by_class( entity, "info_player_start", true ) ) > 0 )
ArrayPushCell( m_aDefaultSpawnPointsVec, entity );
entity = NULLENT;
while ( ( entity = rg_find_ent_by_class( entity, "info_player_deathmatch", true ) ) > 0 )
ArrayPushCell( m_aDefaultSpawnPointsVec, entity );
m_iDefaultSpawnCount = ArraySize( m_aDefaultSpawnPointsVec );
m_bUsingCustomSpawns = false;
}
bool: @Active_CustomSpawnPoints( )
{
for ( new i = 0; i < m_iSpawnCount; i++ )
{
new data[ SpawnData ];
ArrayGetArray( m_aSpawnPointsVec, i, data );
new entity = rg_create_entity( "info_player_deathmatch" );
if ( is_nullent( entity ) )
continue;
set_entvar( entity, var_origin, data[ data_origin ] );
set_entvar( entity, var_angles, data[ data_v_angle ] );
rg_round_respawn( entity );
if ( is_nullent( entity ) )
continue;
ArrayPushCell( m_aDefaultSpawnPointsVec, entity );
}
if ( m_iDefaultSpawnCount > 0 )
{
m_bUsingCustomSpawns = true;
return true;
}
return false;
}
@Add_SpawnPoint( id )
{
if ( !is_user_alive( id ) )
{
client_print( id, print_chat, "You can't add a spawn point." );
return;
}
if ( m_iSpawnCount >= MAX_SPAWN_POINTS )
{
client_print( id, print_chat, "Maximum number of spawn points reached." );
return;
}
new data[ SpawnData ], Float: angles[ 3 ];
get_entvar( id, var_origin, data[ data_origin ] );
get_entvar( id, var_angles, angles );
get_entvar( id, var_v_angle, data[ data_v_angle ] );
ArrayPushArray( m_aSpawnPointsVec, data );
if ( !@Save_CustomSpawnPoints( ) )
{
ArrayDeleteItem( m_aSpawnPointsVec, ArraySize( m_aSpawnPointsVec ) - 1 );
client_print( id, print_chat, "Save failed." );
return;
}
client_print( id, print_chat, "Point saved. It will activate next map." );
}
bool: @is_hull_vacant( id, Float: origin[ 3 ] )
{
engfunc( EngFunc_TraceHull, origin, origin, 0, HULL_HUMAN, id, 0 );
return !get_tr2( 0, TR_StartSolid ) && !get_tr2( 0, TR_AllSolid ) && get_tr2( 0, TR_InOpen );
}