[PlayerStats]: Added new module.

This commit is contained in:
JerryALT 2024-04-07 15:46:48 +03:00
parent 22ecd2c816
commit 3f8b1a231f
17 changed files with 724 additions and 41 deletions

View File

@ -124,6 +124,33 @@ LANG_ENGLISH "Kills"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_ENGLISH "Total Play Time"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_ENGLISH "Melee Kills"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_ENGLISH "Vehicle Killed"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_ENGLISH "Explosives Kills"
REFERENCE MENU_CAREER_ACCURACY
LANG_ENGLISH "Accuracy"
REFERENCE MENU_CAREER_SP_STATS
LANG_ENGLISH "Singleplayer Stats"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_ENGLISH "Campaign Completed"
REFERENCE MENU_CAREER_INTEL
LANG_ENGLISH "Intel"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_ENGLISH "Achievements"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_ENGLISH "Campaign Progress"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_ENGLISH "D H M S"

View File

@ -124,6 +124,33 @@ LANG_FRENCH "Tu
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_FRENCH "Temps total de jeu"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_FRENCH "Éliminations au corps à corps"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_FRENCH "Véhicules détruits"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_FRENCH "Éliminations aux explosifs"
REFERENCE MENU_CAREER_ACCURACY
LANG_FRENCH "Précision"
REFERENCE MENU_CAREER_SP_STATS
LANG_FRENCH "Statistiques solo"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_FRENCH "Campagne terminée"
REFERENCE MENU_CAREER_INTEL
LANG_FRENCH "Renseignements"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_FRENCH "Succès débloqués"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_FRENCH "Avancement de la campagne"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_FRENCH "J H M S"

View File

@ -130,6 +130,33 @@ LANG_GERMAN "Absch"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_GERMAN "Gesamte Spielzeit"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_GERMAN "Nahkampf-Tötungen"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_GERMAN "Fahrzeuge zerstört"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_GERMAN "Explosiv-Tötungen"
REFERENCE MENU_CAREER_ACCURACY
LANG_GERMAN "Genauigkeit"
REFERENCE MENU_CAREER_SP_STATS
LANG_GERMAN "Einzelspieler-Statistiken"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_GERMAN "Kampagne abgeschlossen"
REFERENCE MENU_CAREER_INTEL
LANG_GERMAN "Informationen"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_GERMAN "Errungenschaften"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_GERMAN "Kampagnenfortschritt"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_GERMAN "T S M S"

View File

@ -124,6 +124,33 @@ LANG_ITALIAN "Uccisioni"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_ITALIAN "Tempo di gioco totale"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_ITALIAN "Uccisioni con corpo a corpo"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_ITALIAN "Veicoli distrutti"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_ITALIAN "Uccisioni con esplosivi"
REFERENCE MENU_CAREER_ACCURACY
LANG_ITALIAN "Precisione"
REFERENCE MENU_CAREER_SP_STATS
LANG_ITALIAN "Statistiche giocatore singolo"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_ITALIAN "Campagna completata"
REFERENCE MENU_CAREER_INTEL
LANG_ITALIAN "Informazioni"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_ITALIAN "Obiettivi sbloccati"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_ITALIAN "Progresso campagna"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_ITALIAN "G O M S"

View File

@ -124,6 +124,33 @@ LANG_PORTUGUESE "Kills"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_PORTUGUESE "Total Play Time"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_PORTUGUESE "Melee Kills"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_PORTUGUESE "Vehicle Killed"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_PORTUGUESE "Explosives Kills"
REFERENCE MENU_CAREER_ACCURACY
LANG_PORTUGUESE "Accuracy"
REFERENCE MENU_CAREER_SP_STATS
LANG_PORTUGUESE "Singleplayer Stats"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_PORTUGUESE "Campaign Completed"
REFERENCE MENU_CAREER_INTEL
LANG_PORTUGUESE "Intel"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_PORTUGUESE "Achievements"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_PORTUGUESE "Campaign Progress"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_PORTUGUESE "D H M S"

View File

@ -121,6 +121,33 @@ LANG_RUSSIAN "
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_RUSSIAN "Èãðîâîå âðåìÿ"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_RUSSIAN "Óáèéñòâà â áëèæíåì áîþ"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_RUSSIAN "Óíè÷òîæåííûå òðàíñïîðòíûå ñðåäñòâà"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_RUSSIAN "Óáèéñòâà âçðûâ÷àòêîé"
REFERENCE MENU_CAREER_ACCURACY
LANG_RUSSIAN "Òî÷íîñòü"
REFERENCE MENU_CAREER_SP_STATS
LANG_RUSSIAN "Ñòàòèñòèêà îäèíî÷íîé èãðû"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_RUSSIAN "Êàìïàíèèÿ çàâåðøåíà"
REFERENCE MENU_CAREER_INTEL
LANG_RUSSIAN "Ñâåäåíèÿ"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_RUSSIAN "Äîñòèæåíèÿ"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_RUSSIAN "Ïðîãðåññ êàìïàíèè"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_RUSSIAN "Ä × Ì Ñ"

View File

@ -114,6 +114,33 @@ LANG_SLOVAK "Kills"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_SLOVAK "Total Play Time"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_SLOVAK "Melee Kills"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_SLOVAK "Vehicle Killed"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_SLOVAK "Explosives Kills"
REFERENCE MENU_CAREER_ACCURACY
LANG_SLOVAK "Accuracy"
REFERENCE MENU_CAREER_SP_STATS
LANG_SLOVAK "Singleplayer Stats"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_SLOVAK "Campaign Completed"
REFERENCE MENU_CAREER_INTEL
LANG_SLOVAK "Intel"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_SLOVAK "Achievements"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_SLOVAK "Campaign Progress"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_SLOVAK "D H M S"

View File

@ -125,6 +125,33 @@ LANG_SPANISH "Asesinatos"
REFERENCE MENU_CAREER_PLAYTIMESP
LANG_SPANISH "Tiempo total de juego"
REFERENCE MENU_CAREER_KILLS_MELEE
LANG_SPANISH "Muertes cuerpo a cuerpo"
REFERENCE MENU_CAREER_KILLS_VEHICLES
LANG_SPANISH "Vehículos destruidos"
REFERENCE MENU_CAREER_KILLS_EXPLOSIVES
LANG_SPANISH "Muertes por explosivos"
REFERENCE MENU_CAREER_ACCURACY
LANG_SPANISH "Precisión"
REFERENCE MENU_CAREER_SP_STATS
LANG_SPANISH "Estadísticas de un jugador"
REFERENCE MENU_CAREER_SP_COMPLETED
LANG_SPANISH "Campaña completada"
REFERENCE MENU_CAREER_INTEL
LANG_SPANISH "Información"
REFERENCE MENU_CAREER_ACHIEVEMENT_UNLOCKED
LANG_SPANISH "Logros desbloqueados"
REFERENCE MENU_CAREER_SP_PROGRESS
LANG_SPANISH "Progreso de campaña"
REFERENCE MENU_SP_STAT_TIME_FORMAT
LANG_SPANISH "D H M S"

View File

@ -279,8 +279,8 @@
CHOICE_DBUTTON_VIS( 5, "@MENU_ARCADEMODE", when( dvarInt( mis_01 ) < 20 && !localvarBool( ui_hideBack ) ); )
// CHOICE_BUTTON_VIS( 5, "@MENU_ARCADEMODE", open popmenu_arcade; LOCAL_ARCADE_RESET, when( dvarInt( mis_01 ) >= 20 && !localvarBool( ui_hideBack ) ); )
// CHOICE_DBUTTON_VIS( 5, "@MENU_ARCADEMODE", when( dvarInt( mis_01 ) < 20 && !localvarBool( ui_hideBack ) ); )
CHOICE_BUTTON_VIS( 6, "@IW3SP_MOD_LOC_MENU_ACHIEVEMENTS", uiScript achievement_progressbar; open achievements; LOCAL_ARCADE_RESET, when( !localvarBool( ui_hideBack ) ); )
//CHOICE_BUTTON_VIS( 6, "@IW3SP_MOD_LOC_MENU_STATS", open stats; LOCAL_ARCADE_RESET, when( !localvarBool( ui_hideBack ) ); )
//CHOICE_BUTTON_VIS( 6, "@IW3SP_MOD_LOC_MENU_ACHIEVEMENTS", uiScript achievement_progressbar; open achievements; LOCAL_ARCADE_RESET, when( !localvarBool( ui_hideBack ) ); )
CHOICE_BUTTON_VIS( 6, "@IW3SP_MOD_LOC_MENU_STATS", uiScript get_career_info; open stats; LOCAL_ARCADE_RESET, when( !localvarBool( ui_hideBack ) ); )
CHOICE_SEPARATOR_VIS( CHOICE_SEP_1, when( !localvarBool( ui_hideBack ) ); )
CHOICE_BUTTON_VIS( 7, "@MENU_CONTROLS", open iw3sp_mod_controls_pc_main /*open options_look*/;, when( !localvarBool( ui_hideBack ) ); )
CHOICE_BUTTON_VIS( 8, "@MENU_OPTIONS", open options_graphics;, when( !localvarBool( ui_hideBack ) ); )

View File

@ -77,14 +77,15 @@ itemDef { \
visible visArg \
decoration }
#define PREPROC_VALUE_TEXT( ptext, itemNumber, px_offset, pcolor ) \
PREPROC_VALUE_TEXT_VIS( ptext, itemNumber, px_offset, pcolor, 1, ITEM_ALIGN_MIDDLE_RIGHT )
#define PREPROC_VALUE_TEXT( pname, ptext, itemNumber, px_offset, pcolor ) \
PREPROC_VALUE_TEXT_VIS( pname, ptext, itemNumber, px_offset, pcolor, 1, ITEM_ALIGN_MIDDLE_RIGHT )
#define PREPROC_VALUE_TEXT_LEFT_ALIGNED( ptext, itemNumber, px_offset, pcolor ) \
PREPROC_VALUE_TEXT_VIS( ptext, itemNumber, px_offset, pcolor, 1, ITEM_ALIGN_MIDDLE_LEFT )
#define PREPROC_VALUE_TEXT_LEFT_ALIGNED( pname, ptext, itemNumber, px_offset, pcolor ) \
PREPROC_VALUE_TEXT_VIS( pname, ptext, itemNumber, px_offset, pcolor, 1, ITEM_ALIGN_MIDDLE_LEFT )
#define PREPROC_VALUE_TEXT_VIS( ptext, itemNumber, px_offset, pcolor, visArg, alignment ) \
#define PREPROC_VALUE_TEXT_VIS( pname, ptext, itemNumber, px_offset, pcolor, visArg, alignment ) \
itemDef { \
name pname \
text ptext; \
type ITEM_TYPE_TEXT \
rect ORIGIN_LABEL_ITEM( itemNumber ) (PLAYERSTATS_WIDTH) LABEL_ITEM_SPACING RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP \
@ -98,6 +99,7 @@ itemDef { \
visible visArg \
decoration }
/*
itemDef
{
type ITEM_TYPE_TEXT
@ -112,6 +114,7 @@ itemDef { \
visible 1
decoration
}
*/
// UI art
PREPROC_SHADER_DRAW_ALIGNED( -4 12 (PLAYERSTATS_WIDTH+8) 326 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", FRAME_BG_COLOR, 0, 0, 0 0 0 0 )
@ -150,24 +153,39 @@ itemDef { \
//kills
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_KILLS", 1)
PREPROC_VALUE_TEXT( 228, 1, -24, LABEL_TITLECOLOR )
PREPROC_VALUE_TEXT( "kills", "", 1, -24, LABEL_TITLECOLOR )
//headshots
PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_HEADSHOTS", 2 )
PREPROC_VALUE_TEXT( 228, 2, -24, LABEL_TEXTCOLOR )
PREPROC_VALUE_TEXT( "headshots", "", 2, -24, LABEL_TEXTCOLOR )
//melee kills
PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_KILLS_MELEE", 3 )
PREPROC_VALUE_TEXT( "kills_melee", "", 3, -24, LABEL_TEXTCOLOR )
//vehicle kills
// PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_KILLS_VEHICLES", 4 )
// PREPROC_VALUE_TEXT( "kills_vehicle", "", 4, -24, LABEL_TEXTCOLOR )
//explosives kills
PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_KILLS_EXPLOSIVES", 4 )
PREPROC_VALUE_TEXT( "kills_explosives", "", 4, -24, LABEL_TEXTCOLOR )
//deaths
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_DEATHS", 3)
PREPROC_VALUE_TEXT( 228, 3, -24, LABEL_TITLECOLOR )
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_DEATHS", 5)
PREPROC_VALUE_TEXT( "deaths", "", 5, -24, LABEL_TITLECOLOR )
PREPROC_DIVIDER( 4 )
//accuracy
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_ACCURACY", 6)
PREPROC_VALUE_TEXT( "accuracy", "", 6, -24, LABEL_TITLECOLOR )
PREPROC_DIVIDER( 7 )
//play time (add as the last element in player info)
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_PLAYTIMESP", 5)
PREPROC_VALUE_TEXT( "0:00:00:00", 5, -24, LABEL_TITLECOLOR )
PREPROC_LABEL_TIME("@IW3SP_MOD_LOC_MENU_SP_STAT_TIME_FORMAT", 4.4)
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_PLAYTIMESP", 8)
PREPROC_VALUE_TEXT( "playedtime", "", 8, -24, LABEL_TITLECOLOR )
PREPROC_DIVIDER( 6 )
PREPROC_DIVIDER( 9 )
//for sliders
//145(18) - 185 (40) - 8
@ -181,33 +199,69 @@ itemDef { \
//289(18) - 439 (40) - 16
//307(18) - 479 (40) - 17
PREPROC_LABEL("Campaign Progress", 7)
PREPROC_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_SP_STATS", 10)
PREPROC_SUB_LABEL( "Recruit Progress:", 8 )
PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 145 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+147), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_SP_COMPLETED", 11 )
PREPROC_VALUE_TEXT( "difficulty", "", 11, -24, LABEL_TEXTCOLOR )
PREPROC_SUB_LABEL( "Regular Progress:", 9 )
PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 163 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+165), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
PREPROC_SUB_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_INTEL", 12 )
PREPROC_VALUE_TEXT( "intels", "", 12, -24, LABEL_TEXTCOLOR )
PREPROC_SUB_LABEL( "Hardened Progress:", 10 )
PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 181 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+183), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
PREPROC_SUB_LABEL("@IW3SP_MOD_LOC_MENU_CAREER_ACHIEVEMENT_UNLOCKED", 13)
PREPROC_VALUE_TEXT( "achievements", "", 13, -24, LABEL_TEXTCOLOR )
PREPROC_SUB_LABEL( "Veteran Progress:", 11 )
PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 199 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+201), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
PREPROC_DIVIDER( 14 )
PREPROC_DIVIDER( 12 )
PREPROC_LABEL( "@IW3SP_MOD_LOC_MENU_CAREER_SP_PROGRESS", 15 )
PREPROC_VALUE_TEXT( "campaign_progress", "", 15, -24, LABEL_TITLECOLOR )
//PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 271 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
//PREPROC_SHADER_DRAW_ADV_VIS( "campaign_progressbar", (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+273), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
PREPROC_LABEL("Intel Items", 13)
PREPROC_VALUE_TEXT( 17, 13, -24, LABEL_TITLECOLOR )
PREPROC_LABEL("Achievement Unlocked", 14)
PREPROC_VALUE_TEXT( 35, 14, -24, LABEL_TITLECOLOR )
//#define PREPROC_SHADER_DRAW_ADV_VIS( pname, px, py, pw, ph, pshader, pcolor, pborder, pbordersize, pbordercolor, visArg )
PREPROC_DIVIDER( 15 )
//itemDef
//{
// name "campaign_progressbar"
// style WINDOW_STYLE_SHADER
// rect 0 0 0 12 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP
// exp rect X( PLAYERSTATS_X+202 )
// exp rect Y( PLAYERSTATS_Y+273 )
// forecolor 1 0.9 0.5 0.6
// exp material( "gradient_fadein" );
// border 0
// bordersize 1
// bordercolor 1 1 1 1
// visible visArg
// decoration
//}
PREPROC_SUB_LABEL( "Campaign Progress:", 16 )
PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 289 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+291), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
// OLD!!!!
// PREPROC_SUB_LABEL( "Recruit Progress:", 8 )
// PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 145 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
// PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+147), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
// PREPROC_SUB_LABEL( "Regular Progress:", 9 )
// PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 163 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
// PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+165), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
// PREPROC_SUB_LABEL( "Hardened Progress:", 10 )
// PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 181 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
// PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+183), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
// PREPROC_SUB_LABEL( "Veteran Progress:", 11 )
// PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 199 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
// PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+201), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )
//PREPROC_DIVIDER( 12 )
// PREPROC_LABEL("Intel Items", 13)
// PREPROC_VALUE_TEXT( "intels", 17, 13, -24, LABEL_TITLECOLOR )
// PREPROC_LABEL("Achievement Unlocked", 14)
// PREPROC_VALUE_TEXT( "achievements", 35, 14, -24, LABEL_TITLECOLOR )
//PREPROC_DIVIDER( 15 )
// PREPROC_SUB_LABEL( "Campaign Progress:", 16 )
// PREPROC_SHADER_DRAW_ALIGNED_VIS( 200 289 60 14 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, ORIGIN_PLAYERSTATS, "white", 0.1 0.1 0.1 0.35, 1, 1, 1 1 1 0.2, 1 )
// PREPROC_SHADER_DRAW_ADV_VIS( (PLAYERSTATS_X+202), /*167*/(PLAYERSTATS_Y+291), 50, 12, "gradient_fadein", 1 0.9 0.5 0.6, 0, 1, 1 1 1 1 rect 0 0 0 0 RIGHTITEM_ALIGN VERTICAL_ALIGN_TOP, 1 )

View File

@ -26,9 +26,9 @@
style WINDOW_STYLE_FILLED
border 0
soundloop "music_mainmenu_mp"
onOpen { /*uiScript get_career_info*/ }
onEsc { close stats;}
onClose {open main;}
onOpen { focusfirst; /*uiScript get_career_info*/ }
onEsc { close stats; }
onClose { open main; }
#include "ui/blurredbg.inc"
#include "ui_mp/navcontrols.inc"

View File

@ -65,6 +65,7 @@ namespace Components
Register(new Markdown());
Register(new Changelog());
Register(new Paintball());
Register(new PlayerStats());
Pregame = false;
// Make sure preDestroy is called when the game shuts down

View File

@ -83,3 +83,4 @@ namespace Components
#include "Modules/GUI/Markdown.hpp"
#include "Modules/Changelog.hpp"
#include "Modules/Paintball.hpp"
#include "Modules/PlayerStats.hpp"

View File

@ -0,0 +1,316 @@
#include "STDInc.hpp"
namespace Components
{
void PlayerStats::ChangeItemDefText(const char* menuName, const char* itemDefName, const char* value)
{
Game::menuDef_t* menu = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MENU, menuName).menu;
if (!menu) return;
for (auto i = 0; i < menu->itemCount; i++)
{
if (menu->items[i] && menu->items[i]->window.name)
{
if (!_stricmp(menu->items[i]->window.name, itemDefName))
{
menu->items[i]->text = value;
}
}
}
}
const char* PlayerStats::getHighestCompletedDifficulty(const float stat_easy, const float stat_regular, const float stat_hardened, const float stat_veteran)
{
if (stat_easy == 0.0f || stat_regular == 0.0f || stat_hardened == 0.0f || stat_veteran == 0.0f)
return "MENU_NOT_STARTED";
if (stat_veteran == 100.0f)
return "MENU_VETERAN";
else if (stat_hardened == 100.0f)
return "MENU_HARDENED";
else if (stat_regular == 100.0f)
return "MENU_REGULAR";
else if (stat_easy == 100.0f)
return "MENU_RECRUIT";
else
return "MENU_IN_PROGRESS";
}
double PlayerStats::CalculateAccuracy(uint32_t bullets_fired, uint32_t bullets_hit)
{
if (bullets_fired != 0)
return static_cast<double>(bullets_hit) / bullets_fired * 100.0;
else
return 0.0;
}
float PlayerStats::getStatProgression(const std::string& difficulty_string, int difficulty)
{
int levels = 0;
size_t max_missions = std::min(difficulty_string.size(), static_cast<size_t>(21));
for (size_t i = 0; i < max_missions; ++i) {
if (static_cast<int>(difficulty_string[i] - '0') >= difficulty) {
levels++;
}
}
float completion = static_cast<float>(levels) / max_missions * 100;
return completion;
}
float PlayerStats::getStatEasy(const std::string& difficulty_string)
{
return getStatProgression(difficulty_string, 1);
}
float PlayerStats::getStatRegular(const std::string& difficulty_string)
{
return getStatProgression(difficulty_string, 2);
}
float PlayerStats::getStatHardened(const std::string& difficulty_string)
{
return getStatProgression(difficulty_string, 3);
}
float PlayerStats::getStatVeteran(const std::string& difficulty_string)
{
return getStatProgression(difficulty_string, 4);
}
float PlayerStats::getStatIntel(int intelCount, int totalIntelItems)
{
return static_cast<float>(intelCount) / totalIntelItems * 100;
}
int PlayerStats::getTotalPercentCompleteSP()
{
float stat_easy = getStatEasy(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_regular = getStatRegular(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_hardened = getStatHardened(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_veteran = getStatVeteran(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_intel = getStatIntel(GetStruct("career", "intel"), 30);
Achievements::achievement_file_t file{};
Achievements::GetAchievementsData(&file);
int achievements_earned = Achievements::GetEarnedAchievementCount(&file);
// Calculate completion progress based on various factors
float total_progress = 0.0;
// Completion progress based on difficulty completion
total_progress += (0.1 / 1) * stat_easy;
total_progress += (0.1 / 1) * stat_regular;
total_progress += (0.1 / 1) * stat_hardened;
total_progress += (0.5 / 1) * stat_veteran;
// Intel completion progress
total_progress += (0.15 / 1) * stat_intel;
// Achievement completion progress
total_progress += (0.15 / 38) * achievements_earned;
// Clamp total progress to 100%
total_progress = std::min(total_progress, 100.0f);
// Convert total progress to integer
return static_cast<int>(total_progress);
}
uint32_t PlayerStats::CalculateDays(uint32_t totalMilliseconds) {
return totalMilliseconds / (1000 * 60 * 60 * 24);
}
uint32_t PlayerStats::CalculateHours(uint32_t totalMilliseconds) {
totalMilliseconds %= (1000 * 60 * 60 * 24);
return totalMilliseconds / (1000 * 60 * 60);
}
uint32_t PlayerStats::CalculateMinutes(uint32_t totalMilliseconds) {
totalMilliseconds %= (1000 * 60 * 60);
return totalMilliseconds / (1000 * 60);
}
uint32_t PlayerStats::CalculateSeconds(uint32_t totalMilliseconds) {
totalMilliseconds %= (1000 * 60);
return totalMilliseconds / 1000;
}
void PlayerStats::DefaultStats()
{
const auto path = GetPlayerStatsPath();
Utils::IO::RemoveFile(path);
}
std::string PlayerStats::GetPlayerStatsPath()
{
auto fileBuffer = Utils::IO::ReadFile("players/profiles/active.txt");
if (fileBuffer.empty())
return "";
std::string game_folder = std::format("{}\\players\\profiles\\{}\\stats.json", Dvars::Functions::Dvar_FindVar("fs_basepath")->current.string, fileBuffer.c_str());
return game_folder;
}
nlohmann::json PlayerStats::ReadPlayerStats()
{
const auto path = GetPlayerStatsPath();
if (!Utils::IO::FileExists(path))
{
return {};
}
try
{
const auto data = Utils::IO::ReadFile(path);
return nlohmann::json::parse(data);
}
catch (const std::exception& e)
{
Game::Com_Printf(0, "Failed to parse config file: %s\n", e.what());
Utils::IO::WriteFile(path, "{}", false);
}
return {};
}
void PlayerStats::ResetData()
{
PlayerStats::DefaultStats();
}
void PlayerStats::WriteData(const nlohmann::json& json)
{
try
{
const auto path = GetPlayerStatsPath();
const auto str = json.dump(4);
Utils::IO::WriteFile(path, str, false);
}
catch (const std::exception& e)
{
Game::Com_Printf(0, "Failed to write config file: %s\n", e.what());
}
}
void PlayerStats::PlayTimeStart()
{
Scheduler::Loop([]
{
static uint32_t lastUpdateTime = timeGetTime();
uint32_t currentTime = timeGetTime();
uint32_t elapsedTime = currentTime - lastUpdateTime;
uint32_t playTimeSP = GetStruct("career", "playTimeSP");
playTimeSP += elapsedTime;
SetStruct("career", "playTimeSP", playTimeSP);
lastUpdateTime = currentTime;
}, Scheduler::Pipeline::MAIN, 1000ms);
}
void __declspec(naked) PlayerStats::Com_Init_Try_Block_Function_Stub()
{
const static uint32_t retn_addr = 0x535220;
__asm
{
mov dword ptr ds:[0xF8E004], ebx;
call PlayTimeStart;
jmp retn_addr;
}
}
PlayerStats::PlayerStats()
{
Command::Add("reset_stats_json", [](Command::Params*)
{
ResetData();
});
GSC::AddFunction("StatsGetFromStruct", []
{
const auto json_struct = Game::Scr_GetString(0);
const auto field = Game::Scr_GetString(1);
const auto value = GetStruct(json_struct, field);
return Game::Scr_AddInt(value);
}, false);
GSC::AddFunction("StatsSetFromStruct", []
{
const auto json_struct = Game::Scr_GetString(0);
const auto field = Game::Scr_GetString(1);
const auto value = Game::Scr_GetInt(2);
SetStruct(json_struct, field, value);
}, false);
UIScript::Add("get_career_info", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
//stats vars
uint32_t var_bullets_fired = GetStruct("career", "bullets_fired");
uint32_t var_bullets_hit = GetStruct("career", "bullets_hit");
uint32_t var_deaths = GetStruct("career", "deaths");
uint32_t var_headshots = GetStruct("career", "headshots");
uint32_t var_kills = GetStruct("career", "kills");
uint32_t var_kills_melee = GetStruct("career", "kills_melee");
uint32_t var_kills_explosives = GetStruct("career", "kills_explosives");
uint32_t var_playTimeSP = GetStruct("career", "playTimeSP");
uint32_t var_intel = GetStruct("career", "intel");
uint32_t var_days = CalculateDays(var_playTimeSP);
uint32_t var_hours = CalculateHours(var_playTimeSP);
uint32_t var_minutes = CalculateMinutes(var_playTimeSP);
uint32_t var_seconds = CalculateSeconds(var_playTimeSP);
float stat_easy = getStatEasy(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_regular = getStatRegular(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_hardened = getStatHardened(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
float stat_veteran = getStatVeteran(Dvars::Functions::Dvar_FindVar("mis_difficulty")->current.string);
Achievements::achievement_file_t file{};
Achievements::GetAchievementsData(&file);
int var_achievements_earned = Achievements::GetEarnedAchievementCount(&file);
auto var_accuracy = CalculateAccuracy(var_bullets_fired, var_bullets_hit);
int total_progress = getTotalPercentCompleteSP();
// For menu showcase
const char* kills = Utils::String::VA_NEW("%d", var_kills);
const char* kills_melee = Utils::String::VA_NEW("%d", var_kills_melee);
const char* kills_explosives = Utils::String::VA_NEW("%d", var_kills_explosives);
const char* headshots = Utils::String::VA_NEW("%d", var_headshots);
const char* deaths = Utils::String::VA_NEW("%d", var_deaths);
const char* bullets_fired = Utils::String::VA_NEW("%d", var_bullets_fired);
const char* bullets_hit = Utils::String::VA_NEW("%d", var_bullets_hit);
const char* intel = Utils::String::VA_NEW("%d/%d", var_intel, 30);
const char* timestamp = Utils::String::VA_NEW("%u:%02u:%02u:%02u", var_days, var_hours, var_minutes, var_seconds);
const char* achievements_earned = Utils::String::VA_NEW("%d/%d", var_achievements_earned, Achievements::ACHIEVEMENT_TOTAL_COUNT);
const char* accuracy = Utils::String::VA_NEW("%.0f%%", var_accuracy);
const char* difficulty = getHighestCompletedDifficulty(stat_easy, stat_regular, stat_hardened, stat_veteran);
const char* total_percent_sp = Utils::String::VA_NEW("%d%%", total_progress);
ChangeItemDefText("stats", "kills", kills);
ChangeItemDefText("stats", "headshots", headshots);
ChangeItemDefText("stats", "kills_melee", kills_melee);
ChangeItemDefText("stats", "kills_explosives", kills_explosives);
ChangeItemDefText("stats", "deaths", deaths);
ChangeItemDefText("stats", "accuracy", accuracy);
//-----------------------------------------------------------
ChangeItemDefText("stats", "playedtime", timestamp);
//-----------------------------------------------------------
ChangeItemDefText("stats", "difficulty", Game::UI_SafeTranslateString(difficulty));
ChangeItemDefText("stats", "intels", intel);
ChangeItemDefText("stats", "achievements", achievements_earned);
//-----------------------------------------------------------
ChangeItemDefText("stats", "campaign_progress", total_percent_sp);
//-----------------------------------------------------------
});
Utils::Hook::Nop(0x53521A, 6);
Utils::Hook(0x53521A, Com_Init_Try_Block_Function_Stub, HOOK_JUMP).install()->quick();
}
PlayerStats::~PlayerStats()
{
}
}

View File

@ -0,0 +1,80 @@
#pragma once
namespace Components
{
class PlayerStats : public Component
{
public:
static std::string JsonToString(const nlohmann::json& j)
{
return j.dump();
}
static nlohmann::json Get(const std::string& key)
{
const auto cfg = ReadPlayerStats();
if (!cfg.is_object() || !cfg.contains(key) || !cfg[key].is_null())
{
Set(key, defaultValue);
return cfg[key];
}
return cfg[key];
}
static nlohmann::json GetStruct(const std::string& name, const std::string& field)
{
const auto cfg = ReadPlayerStats();
if (!cfg.is_object() || !cfg.contains(name) || !cfg[name].is_object() || !cfg[name].contains(field) || cfg[name][field].is_null())
{
SetStruct(name, field, defaultValue); // You may want to handle default value differently
return defaultValue;
}
return cfg[name][field];
}
static void Set(const std::string& key, const nlohmann::json& value)
{
auto cfg = ReadPlayerStats();
cfg[key] = value;
WriteData(cfg);
}
static void SetStruct(const std::string& name, const std::string& field, const nlohmann::json& value)
{
auto cfg = ReadPlayerStats();
cfg[name][field] = value;
WriteData(cfg);
}
PlayerStats();
~PlayerStats();
private:
inline static int defaultValue = 0;
static uint32_t CalculateSeconds(uint32_t totalMilliseconds);
static uint32_t CalculateMinutes(uint32_t totalMilliseconds);
static uint32_t CalculateHours(uint32_t totalMilliseconds);
static uint32_t CalculateDays(uint32_t totalMilliseconds);
static std::string GetPlayerStatsPath();
static nlohmann::json ReadPlayerStats();
static void WriteData(const nlohmann::json& json);
static void ResetData();
static void DefaultStats();
static void PlayTimeStart();
static void ChangeItemDefText(const char* menuName, const char* itemDefName, const char* value);
static const char* getHighestCompletedDifficulty(const float stat_easy, const float stat_regular, const float stat_hardened, const float stat_veteran);
static double CalculateAccuracy(uint32_t bullets_fired, uint32_t bullets_hit);
static float getStatProgression(const std::string& difficulty_string, int difficulty);
static float getStatEasy(const std::string& difficulty_string);
static float getStatRegular(const std::string& difficulty_string);
static float getStatHardened(const std::string& difficulty_string);
static float getStatVeteran(const std::string& difficulty_string);
static float getStatIntel(int intelCount, int totalIntelItems);
static int getTotalPercentCompleteSP();
static void Com_Init_Try_Block_Function_Stub();
};
}

View File

@ -7,6 +7,20 @@ namespace Utils
{
namespace String
{
const char* VA_NEW(const char* fmt, ...)
{
static char g_vaBuffer[64][65536];
static int g_vaNextBufferIndex = 0;
va_list ap;
va_start(ap, fmt);
char* dest = g_vaBuffer[g_vaNextBufferIndex];
vsnprintf(g_vaBuffer[g_vaNextBufferIndex], 65536, fmt, ap);
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % 64;
va_end(ap);
return dest;
}
const char* VA(const char* fmt, ...)
{
static VAProvider<4, 100> globalProvider;

View File

@ -73,6 +73,7 @@ namespace Utils
};
const char* VA(const char* fmt, ...);
const char* VA_NEW(const char* fmt, ...);
template <typename Arg> // This should display a nice "nullptr" instead of a number
static void SanitizeFormatArgs(Arg& arg)