summaryrefslogtreecommitdiff
path: root/gmod/visual_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gmod/visual_player.cpp')
-rw-r--r--gmod/visual_player.cpp308
1 files changed, 308 insertions, 0 deletions
diff --git a/gmod/visual_player.cpp b/gmod/visual_player.cpp
new file mode 100644
index 0000000..fb65458
--- /dev/null
+++ b/gmod/visual_player.cpp
@@ -0,0 +1,308 @@
+#include <algorithm>
+
+#include "visual.hpp"
+#include "context.hpp"
+#include "base_cheat.hpp"
+#include "renderer.hpp"
+#include "input_system.hpp"
+#include "math.hpp"
+
+/*
+ Change hook where grabbing lua related from RenderView to CEngineVGui::Paint to see if that works.
+ I do all my drawing in Paint and should not crash( I never crash ).
+*/
+
+namespace features
+{
+
+ struct box_t
+ {
+ int x, y, w, h;
+ };
+
+ box_t get_box( c_base_player* ent, matrix3x4& frame ) {
+ const matrix3x4& matrix = frame;
+
+ vec3_t min = ent->m_vecMins( );
+ vec3_t max = ent->m_vecMaxs( );
+
+ std::array< vec3_t, 8 > point_list = {
+ vec3_t{ min.x, min.y, min.z },
+ vec3_t{ min.x, max.y, min.z },
+ vec3_t{ max.x, max.y, min.z },
+ vec3_t{ max.x, min.y, min.z },
+ vec3_t{ max.x, max.y, max.z },
+ vec3_t{ min.x, max.y, max.z },
+ vec3_t{ min.x, min.y, max.z },
+ vec3_t{ max.x, min.y, max.z }
+ };
+
+ std::array< float, 8 > x_points;
+ std::array< float, 8 > y_points;
+
+ for( auto& it : point_list ) {
+ vec3_t backup = it;
+ for( int i{ }; i < 3; ++i ) {
+ it[ i ] = backup.dot( ( const vec3_t& )( matrix[ i ] ) ) + matrix[ i ][ 3 ];
+ }
+ }
+
+ for( size_t i{ }; i < 8; ++i ) {
+ vec2_t w2s = util::screen_transform( point_list[ i ] );
+ x_points[ i ] = w2s.x;
+ y_points[ i ] = w2s.y;
+ }
+
+ std::sort( x_points.begin( ), x_points.end( ) );
+ std::sort( y_points.begin( ), y_points.end( ) );
+
+ int x = ( int )x_points.front( );
+ int w = ( int )x_points.back( ) - x;
+
+ int y = ( int )y_points.front( );
+ int h = ( int )y_points.back( ) - y;
+
+ return { x, y, w, h };
+ }
+
+ void c_visuals::store_data( ) {
+ g_ctx.m_lua = g_gmod.m_lua_shared( )->GetLuaInterface( LUA_CLIENT );
+ if( !g_ctx.m_lua )
+ return;
+
+ m_data.m_matrix = *( VMatrix* )( 0x18C * 2 + *( uintptr_t* )( ( uintptr_t )g_gmod.m_engine_render( ) + 0xDC ) - 0x44 );
+
+ const auto local_id = g_gmod.m_engine( )->GetLocalPlayer( );
+
+ for( int i{ 1 }; i <= g_gmod.m_globals->m_maxclients; ++i ) {
+ auto ent = g_gmod.m_entlist( )->GetClientEntity< >( i );
+ if( !ent || !ent->is_valid( ) )
+ continue;
+
+ auto& data = m_data.m_player.at( i );
+
+ if( g_settings.visuals.ignore_teamcolor ) {
+ data.m_team_color = ent->get_team_color( );
+ }
+
+ if( i == local_id )
+ continue;
+
+ data.m_coordinate_frame = ent->m_CoordinateFrame( );
+
+ if( g_settings.visuals.skeleton ) {
+ ent->ce( )->SetupBones( data.m_matrix, 128, 0x100, g_gmod.m_globals->m_curtime ); // yep, 256 is the max bone count in gmod, but i doubt it's used for anything.
+ }
+
+ if( g_settings.visuals.rank || g_settings.visuals.spec_list ) {
+ data.m_rank = ent->get_rank( );
+ }
+ }
+ }
+
+ void c_visuals::spectator_list( ) {
+ if( !g_settings.visuals.spec_list )
+ return;
+
+ int cur_pos{ };
+ player_info_t info{ };
+ char buffer[ 128 ]{ };
+ std::vector< const char* > list_of_names{ };
+
+ const int local_id = g_gmod.m_engine( )->GetLocalPlayer( );
+
+ for( int i{ 1 }; i <= g_gmod.m_globals->m_maxclients; ++i ) {
+ if( i == local_id )
+ continue;
+
+ auto ent = g_gmod.m_entlist( )->GetClientEntity< >( i );
+ if( !ent )
+ continue;
+
+ if( !g_gmod.m_engine( )->GetPlayerInfo( i, &info ) )
+ continue;
+
+ auto target = ent->get_observer_target( );
+ if( !target )
+ continue;
+
+ if( target->ce( )->GetIndex( ) != local_id )
+ continue;
+
+ sprintf_s( buffer, "%s - (%s)", info.name, m_data.m_player.at( i ).m_rank.c_str( ) );
+
+ list_of_names.push_back( buffer );
+ }
+
+ int screen_w, screen_h;
+ g_gmod.m_engine( )->GetScreenSize( screen_w, screen_h );
+
+ if( g_settings.misc.watermark ) {
+ cur_pos = 20;
+ }
+
+ for( const auto& it : list_of_names ) {
+ draw_string( screen_w - 3, cur_pos, ALIGN_RIGHT, true, clr_t( 255, 255, 255 ), it );
+ cur_pos += 10;
+ }
+ }
+
+
+ void c_visuals::draw_players( ) {
+ const auto local_id = g_gmod.m_engine( )->GetLocalPlayer( );
+ const auto local_team_color = m_data.m_player.at( local_id ).m_team_color;
+
+ for( int i{ 1 }; i <= g_gmod.m_globals->m_maxclients; ++i ) {
+ if( i == local_id )
+ continue;
+
+ auto ent = g_gmod.m_entlist( )->GetClientEntity< >( i );
+ if( !ent || !ent->is_valid( ) )
+ continue;
+
+ auto& data = m_data.m_player.at( i );
+
+ if( g_settings.visuals.ignore_team &&
+ g_ctx.m_local->m_iTeamNum( ) == ent->m_iTeamNum( ) )
+ continue;
+
+ if( g_settings.visuals.ignore_teamcolor &&
+ local_team_color == data.m_team_color )
+ continue;
+
+ //clr_t col = ent->m_iTeamNum( ) == g_ctx.m_local->m_iTeamNum( ) ?
+ // g_settings.visuals.box_friendly : g_settings.visuals.box_enemy;
+
+ clr_t col = g_settings.visuals.box_enemy;
+
+ auto box = get_box( ent, data.m_coordinate_frame );
+ int health = ent->m_iHealth( );
+ int bottom_pos = 0;
+
+ if( g_settings.visuals.skeleton( ) ) {
+ //clr_t col = ent->m_iTeamNum( ) == g_ctx.m_local->m_iTeamNum( ) ? g_settings.visuals.skeleton_friendly : g_settings.visuals.skeleton_enemy;
+ clr_t col = g_settings.visuals.skeleton_enemy;
+
+ auto hdr = g_gmod.m_model_info( )->GetStudiomodel( ent->ce( )->GetModel( ) );
+ if( hdr ) {
+ for( size_t bone{ }; bone < hdr->numbones; ++bone ) {
+ auto b = hdr->get_bone( bone );
+ if( b && b->flags & 0x100 && b->parent != -1 ) {
+ vec3_t child = vec3_t{ data.m_matrix[ bone ][ 0 ][ 3 ], data.m_matrix[ bone ][ 1 ][ 3 ], data.m_matrix[ bone ][ 2 ][ 3 ] };
+ vec3_t parent = vec3_t{ data.m_matrix[ b->parent ][ 0 ][ 3 ], data.m_matrix[ b->parent ][ 1 ][ 3 ], data.m_matrix[ b->parent ][ 2 ][ 3 ] };
+
+ auto child_screen = util::screen_transform( child );
+ auto parent_screen = util::screen_transform( parent );
+
+ draw_line( child_screen, parent_screen, col );
+ }
+ }
+ }
+ }
+
+ if( g_settings.visuals.box( ) ) {
+ draw_rect( box.x + 1, box.y + 1, box.w - 2, box.h - 2, clr_t( 0, 0, 0, 180 ) );
+ draw_rect( box.x, box.y, box.w, box.h, col );
+ }
+
+ if( g_settings.visuals.health( ) ) {
+ auto fill = box.h - 1;
+ fill *= std::clamp( health, 0, 100 ) * 0.01f;
+
+ auto hp_col = clr_t(
+ std::min< int >( 510 * ( 100 - health ) / 100, 255 ),
+ std::min< int >( 510 * health / 100, 255 ),
+ 0,
+ 255 );
+
+ draw_filled_rect( box.x - 4, box.y, 3, box.h + 1, clr_t( 0, 0, 0, 170 ) );
+ draw_filled_rect( box.x - 3, box.y + box.h - fill, 1, fill, hp_col );
+
+ if( health != 100 )
+ draw_string( box.x - 2, box.y + 1 + box.h - fill - 3, ALIGN_CENTER, false, clr_t( 255, 255, 255, 255 ), "%d", health );
+ }
+
+ if( g_settings.visuals.name( ) ) {
+ draw_string( box.x + box.w / 2, box.y - 12, ALIGN_CENTER, true,
+ clr_t( 255, 255, 255, 255 ), ent->get_info( ).name );
+ }
+
+ if( g_settings.visuals.weapon( ) ) {
+ auto weapon = ent->get_weapon( );
+ if( weapon ) {
+ std::string wep_str = weapon->get_print_name( );
+ if( !wep_str.empty( ) ) {
+ std::transform( wep_str.begin( ), wep_str.end( ), wep_str.begin( ), ::tolower ); // lowercase gang
+
+ draw_string( box.x + box.w / 2, box.y + box.h + 3 + bottom_pos, ALIGN_CENTER, true,
+ clr_t( 255, 255, 255, 255 ), wep_str.c_str( ) ); // font is a little ugly
+
+ bottom_pos += 11;
+ }
+ }
+ }
+
+ if( g_settings.visuals.rank( ) ) {
+ auto rank = data.m_rank;
+ if( !rank.empty( ) ) {
+ draw_string( box.x + box.w / 2, box.y + box.h + 3 + bottom_pos, ALIGN_CENTER, true,
+ clr_t( 255, 255, 255, 255 ), rank.c_str( ) );
+
+ bottom_pos += 11;
+ }
+ }
+
+ //if( g_settings.visuals.ammo ) { m_iClip1 just returns the max clip??? doesn't work.
+ // if( auto weapon = ent->get_weapon( ) ) { // hacker codes 8)
+ // draw_string( box.x + box.w / 2, box.y + box.h + 3 + bottom_pos, ALIGN_CENTER, true,
+ // clr_t( 255, 255, 255, 255 ), "%d / %d", weapon->m_iClip1( ), m_stored_data.at( i ).m_max_clip1 );
+ // }
+ //}
+ }
+ }
+
+ void c_visuals::operator()( ) {
+ g_ctx.m_lua = g_gmod.m_lua_shared( )->GetLuaInterface( LUA_CLIENT );
+ if( !g_ctx.m_lua )
+ return;
+
+ switch( g_settings.visuals.activation_type( ) ) {
+ case 0:
+ g_settings.visuals.active = false;
+ break;
+ case 1:
+ g_settings.visuals.active = true;
+ break;
+ case 2:
+ g_settings.visuals.active = g_input.is_key_pressed( g_settings.visuals.key );
+ break;
+ case 3:
+ {
+ static bool held = false;
+ bool pressed = g_input.is_key_pressed( g_settings.visuals.key );
+ if( pressed ) {
+ if( !held )
+ g_settings.visuals.active ^= 1;
+ held = true;
+ }
+ else held = false;
+ }
+ break;
+ default:
+ g_settings.visuals.active = false;
+ break;
+ }
+
+ if( g_ctx.run_frame( ) ) {
+ spectator_list( );
+ g_cheat.m_playerlist( );
+ if( g_settings.visuals.active ) {
+ draw_players( );
+ }
+ }
+ }
+
+ VMatrix& c_visuals::get_matrix( ) {
+ return m_data.m_matrix;
+ }
+} \ No newline at end of file