diff options
Diffstat (limited to 'gmod/visual_player.cpp')
| -rw-r--r-- | gmod/visual_player.cpp | 308 |
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 |
