Salve, in questa nuova guida spiegherò meglio come modificare la grafica del gioco.
Detto ciò, consiglio inizialmente di rimpicciolire il font del testo, così la GUI darà meno fastidio poichè più piccola (io in genere gioco a bassa risoluzione).
Andate nella Solution Explorer ed aprite "proxyIDirect3DDevice9.cpp". Qui modificheremo la maggior parte delle cose grafiche (come ho già detto).
Allora modifichiamo leggermente il font...
Andiamo alla linea 61 e sostituiamo il codice:
CODICE
CD3DFont *pD3DFont = new CD3DFont( "Calibri", 9, FCR_BOLD );
CD3DFont *pD3DFont_sampStuff = new CD3DFont( "Calibri", 9, FCR_BOLD );
CD3DFont *pD3DFontFixed = new CD3DFont( "Calibri", 9, FCR_BOLD );
CD3DFont *pD3DFontFixedSmall = new CD3DFont( "Small Fonts", 8, FCR_BOLD );
CD3DFont *pD3DFontChat = new CD3DFont( "Calibri", 9, FCR_BOLD );
CD3DFont *pD3DFontDebugWnd = new CD3DFont( "Calibri", 9, FCR_BOLD );
#define MENU_ROWS 23
Come potete vedere, ho anche alzato il numero di righe a 23.
Ora andiamo a modificare le barre della vita e della salute dei giocatori. Credo che a noi qualche informazione in più faccia comodo (Ping e Score).
Per aggiungere del testo che ci faccia visualizzare questi due dati andiamo alla riga 885, dove vedremo che viene definito il callback che gestisce le tag dei giocatori (struct playerTagInfo).
Probabilmente leggendolo non ci capirete una mazza. Questo codice inizialmente legge i dati della pool (piscina, boh non so come tradurlo) che sarebbe l'insieme dei dati dei giocatori. Quindi legge l'intera pool e scarta i giocatori che non si vedono nello schermo (converte le coordinate dei giocatori da 3d a 2d sullo schermo e se sono fuori dallo schermo le scarta).
Se passiamo alla fine (Ln 1330), possiamo vedere che vengono gestiti i testi che riguardano la salute del giocatore, la sua armatura, il suo nome e il suo ID.
Allora noi aggiungiamoci quello che vogliamo! Sotto la riga 1330 dovete sostituire un bel po' di codice:
CODICE
if ( !g_Players )
{
_snprintf_s( buf, sizeof(buf)-1, "H: %d, A: %d", (int)iterPed->GetHealth(), (int)iterPed->GetArmor() );
pD3DFontFixedSmall->PrintShadow( g_playerTagInfo[iGTAID].tagPosition.fX + 8.0f, playerBaseY - h + 10.0f, D3DCOLOR_ARGB(130, 0xFF, 0x6A, 0), buf );
}
else
{
uint32_t samp_info = ( uint32_t ) g_SAMP;
uint32_t func = g_dwSAMP_Addr + SAMP_FUNCUPDATESCOREBOARDDATA;
__asm mov ecx, samp_info
__asm call func
_snprintf_s( buf, sizeof(buf)-1, "H: %d, A: %d", (int)g_Players->pRemotePlayer[iSAMPID]->pPlayerData->fActorHealth, (int)g_Players->pRemotePlayer[iSAMPID]->pPlayerData->fActorArmor );
pD3DFontFixedSmall->PrintShadow( g_playerTagInfo[iGTAID].tagPosition.fX + 8.0f, playerBaseY - h + 10.0f, D3DCOLOR_ARGB(130, 0xFF, 0x6A, 0), buf );
_snprintf_s( buf, sizeof(buf)-1, "P: %d, S: %d", (int)g_Players->pRemotePlayer[iSAMPID]->iPing, (int)g_Players->pRemotePlayer[iSAMPID]->iScore );
pD3DFontFixedSmall->PrintShadow( g_playerTagInfo[iGTAID].tagPosition.fX + 8.0f, playerBaseY - h, D3DCOLOR_ARGB(130, 0xFF, 0x6A, 0), buf );
h = pD3DFont_sampStuff->DrawHeight() - 1;
_snprintf_s( buf, sizeof(buf)-1, "%s (%d)", getPlayerName(iSAMPID), iSAMPID );
w = pD3DFont_sampStuff->DrawLength( buf );
pD3DFont_sampStuff->PrintShadow( g_playerTagInfo[iGTAID].tagPosition.fX, playerBaseY - h - 10.0f, samp_color_get( iSAMPID, 0xDD000000 ), buf );
}
Come potete vedere dalla riga 1330, cerca se la struttura della pool dei giocatori di SA:MP NON contiene dati (c'è un if con un punto esclamativo prima della condizione, quindi è una negazione), quindi se non ne contiene va a leggere i dati da GTA:San Andreas, altrimenti legge quelli della struttura di SA:MP, che sono più sincronizzati.
Ovviamente, essendo una struttura di GTA:San Andreas, va a leggere i dati dei semplici pedoni, quindi serve per il singleplayer. Per il multiplayer è meglio affidarci ai dati che SA:MP ci offre.
Noi quindi sotto all'else ci abbiamo aggiunto il nostro codice, poichè è la negazione della negazione (se non è vero che la struttura di SA:MP non contiene dati), quindi se ha dati possiamo leggerli, quindi inseriamo il codice che legge ping e punteggio.
Per poter leggere il ping si deve aggiornare la scoreboard, quindi le prime quattro righe dopo l'else sono preposte a questo.
La funzione "_snprintf_s" serve per creare stringhe formattate, ovvero stringhe variabili nel tempo. Il ping cambia, il punteggio anche. Quindi noi leggiamo quei dati, li inseriamo in una stringa e li stampiamo con la funzione sottostante (pD3DFontFixedSmall->PrintShadow).
Nella funzione "_snprintf_s" i parametri sono questi:
- Variabile in formato char che contiene la stringa, di nome buf;
- Quantità di testo da sovrascrivere, le char si definiscono con "char NOMEVARIAIBLE[NUMEROLETTERE]", quindi io posso dirgli di formattare il testo solo in parte, ma noi invece lo sovrascriviamo del tutto. Al posto di prendere il valore che sta tra le parentesi quadre (se volete leggerlo andate sopra alla parola buf, cliccate col pulsante destro e selezionate "Go to definition" oppue "Vai alla definizione", cioè "char buf[256];") è preferibile inserire una variabile che legge direttamente il dato, se cambiamo valore alla stringa non è più lo stesso. Inoltre se non ci ricordiamo il numero 256 ma ci ricordiamo il nome della variabile andiamo sempre sul sicuro.
Nel nostro caso la dimensione è sizeof(buf)-1, ovvero 256-1 = 255. Infatti nella dichiarazione inseriamo il valore massimo, però i valori partono da 0 e non da 1, quindi i valori vann da 0 a 255, per un totale di 256.
- Il terzo parametro invece è il nostro testo. Sembra un testo strano se lo leggete:
"%d" è un parametro che indica che il valore che deve prendere lo deve leggere da una variabile. la d indica che la variabile è un numero intero. Per poter stampare numeri con la virgola dobbiamo usare %f (float), altrimenti con %d il numero lo leggeremmo troncato. Il punteggio e il ping sono due numeri interi.
- Ora abbiamo due parametri, ovvero le variabili di cui stavo parlando.
CITAZIONE
(int)g_Players->pRemotePlayer[iSAMPID]->pPlayerData->fActorHealth,
(int)g_Players->pRemotePlayer[iSAMPID]->pPlayerData->fActorArmor
Quindi legge i dati dal giocatore remoto avente come id "iSAMPID" (è stato calcolato prima), entra nella struttra "pPlayerData" e legge le variabili "fActorHealth" e "fActorArmor" (sono due float, noi le convertiamo in int mettendo il prefisso (int) per convertire). Se voi cancellate il pezzo finale, ovvero il nome della variabile (fActorHealth) e il simbolo di maggiore (che con il trattino fa una freccia), visualizzeremo tutte le variabili della struttura pPlayerData. Possiamo usare quella che vogliamo.
Ovviamente dobbiamo renderci conto di che variabili sono, le stringhe di indicano con %s ad esempio. Inoltre la struttura "pPlayerData" contiene altre strutture, tipo aimData, quindi aimData è seguito da un punto e da una variabile. Il punto si usa per una struttura semplice, la freccia invece quando accediamo ad un puntatore che funge come struttura.
Queste sono magari cose che capirete più avanti.
Il ping e il punteggio sono due variabili contenute in pRemotePlayer[iSAMPID], come potete vedere dal codice in alto.
Ah, non avevo detto che tra un parametro e l'altro si mette la virgola e che tra una virgola e un parametro si può andare a capo.
Io ho tolto gli spazi e ho fatto tutto attaccato.
La funzione sotto invece richiama un font ed esegue una delle funzioni che contiene, ovvero PrintShadow, quindi stampa il testo di quel font. Di che parametri ha bisogno?
Beh, innanzitutto le coordinate sullo schermo, quindi il primo parametro è X e il secondo Y (sono in float), il terzo è il colore, mentre il quarto è la stringa buf.
Come potete vedere, ho tolto al secondo paramerto quel "+ 10.00f" perchè voglio alzare di 10.00f il testo, in maniera che non si sovrapponga a quello della salute e dell'armatura.
La funzione "D3DCOLOR_ARGB(130, 0xFF, 0x6A, 0)", definisce un colore (credo) arancione. I valori sono scritti in esadecimale, si capisce perchè sono costituiti dal prefisso 0x e un valore contenente numeri e lettere comprese tra A ed F. Per convertire il numero possiamo usare la calcolatrice di windows... Comunque sia, potete volentieri cambiare il colore, non è necessario che i valori siano in esadecimale, potete mettere in numeri in decimale (come Alpha, l'opacità, che vale 130).
Andate alla riga 1307, e sostituite questo codice con quello nuovo:
CODICE
render->D3DBox( g_playerTagInfo[iGTAID].tagPosition.fX + ESP_tag_player_D3DBox_pixelOffsetX, playerBaseY + ESP_tag_player_D3DBox_pixelOffsetY, 100.0f, 6.0f, D3DCOLOR_ARGB(180, 0, 0, 0) );
render->D3DBox( g_playerTagInfo[iGTAID].tagPosition.fX + ESP_tag_player_D3DBox_pixelOffsetX, playerBaseY + ESP_tag_player_D3DBox_pixelOffsetY, vh, 6.0f, color );
if ( va > 0.0f )
{
if ( va > 100.0f ) va = 100.0f;
va /= 1.0f;
render->D3DBox( g_playerTagInfo[iGTAID].tagPosition.fX + ESP_tag_player_D3DBox_pixelOffsetX, playerBaseY + ESP_tag_player_D3DBox_pixelOffsetY, va, 6.0f, D3DCOLOR_ARGB(111, 0, 0, 0) );
render->D3DBox( g_playerTagInfo[iGTAID].tagPosition.fX + ESP_tag_player_D3DBox_pixelOffsetX, playerBaseY + ESP_tag_player_D3DBox_pixelOffsetY, va, 6.0f, D3DCOLOR_ARGB(111, 220, 220, 220) );
}
Questo ridurrà leggermente la dimensione delle barre della salute e dell'armatura, potrebbero dare leggermente fastidio così grandi come sono già...
A questo punto passiamo alle barre dei veicoli.
Andiamo alla riga 1501 e sostituiamo il codice:
CODICE
render->D3DBox( screenPosition.fX + ESP_tag_vehicle_D3DBox_pixelOffsetX, screenPosition.fY + ESP_tag_vehicle_pixelOffsetY + ESP_tag_vehicle_D3DBox_pixelOffsetY, 100.0f, 6.0f, D3DCOLOR_ARGB(48, 0, 0, 0) );
render->D3DBox( screenPosition.fX + ESP_tag_vehicle_D3DBox_pixelOffsetX, screenPosition.fY + ESP_tag_vehicle_pixelOffsetY + ESP_tag_vehicle_D3DBox_pixelOffsetY, vh, 6.0f, vcolor );
Ora andate alla riga 1507 e mettete questo:
CODICE
pD3DFontFixedSmall->PrintShadow( screenPosition.fX + 4.0f, screenPosition.fY - h + 6.0f + ESP_tag_vehicle_pixelOffsetY, D3DCOLOR_ARGB(90, 0, 255, 0), buf );
Serve per correggere il testo in relazione alla barra.
Ora andate alla riga 3559. Qui sotto vengono definite 2 funzioni per la barra. Ma i calcoli li fa per avere la barra sottostante. Quindi noi faremo 2 definizioni simili, per avere quella in alto.
Per farlo dobbiamo ricreare una variabile X, visto che questa definisce la posizione delle funzioni rispetto la barra in alto.
Quindi andate alla riga 3594, incollate questo:
CODICE
#define HUD_TEXT2( x2, color, text2 ) \
pD3DFont->PrintShadow( 1.0f + (x2), + 3, (color), \
(text2) ); \
( x2 ) += pD3DFont->DrawLength( text2 );
#define HUD_TEXT_TGL2( x2, color, text2 ) \
HUD_TEXT2( x2, color_text, "[" ); \
HUD_TEXT2( x2, color, text2 ); \
HUD_TEXT2( x2, color_text, "] " )
Ho cercato di seguire quello già fatto. Guardate il parametro numero due di "pD3DFont->PrintShadow", contiene la posizione rispetto a X. Se nella vecchia definizione il parmatero era (LunghezzaTotaleSchermo - AltezzaTesto - 3) ora dobbiamo partire da 0 (il punto più alto) e aggiungere l'offset -3.
Andiamo alla riga 3616 e mettiamo questo codice:
CODICE
float x = 0.0f, x2 = 0.0f;
Questo definisce la variabile x e la setta a 0.0f (per la float si mette sempre la f finale) che era già stata definita, e aggiunge la definzione della seconda variabile che vale uguale.
Per definire più variabili posso usare questo tipo di sintassi:
TIPOVARIABILE NOMEVARIABILE1, NOMEVARIABILE2, NOMEVARIABILE3, ..., NOMEVARIABILEN;
Volendo posso aggiungere un "=" seguito dal valore dopo il nome della variabile per impostare un valore iniziale.
Ora andiamo alla riga 3683 e aggiungiamo un pezzo di codice:
CODICE
if ( set.hud_draw_bar_up )
{
uint32_t bar_color = D3DCOLOR_ARGB( hud_bar->alpha, hud_bar->red, hud_bar->green, hud_bar->blue );
render->D3DBoxi( (int)x2 - 1, - 4, (int)(pPresentParam.BackBufferWidth + 14), 22, bar_color, NULL );
}
Questo codice serve per creare la seconda barra. L'isruzione IF seguita dalla condizione serve per indicare se la variabile hud_draw_bar_up contenuta nella struttura set (si vede dal punto) è attiva. Noi vorremmo che sia attiva di default, vorremmo inoltre che si possa attivare o disattivare dal menù.
Intanto andiamo alla riga 3764, e modifichiamo la funzione "HUD_TEXT_TGL" con "HUD_TEXT_TGL2" e "x" con "x2", ottenendo questo:
CODICE
HUD_TEXT_TGL2( x2, cheat_state->vehicle.crasher ? color_enabled : color_disabled, "Crasher" );
Compilando avremo due errori. Manca la variabile hud_draw_bar_up.
Quindi andiamo nella cartella Cheat del Solution Explorer e apriamo ini.h.
Sotto alla riga 233 incolliamo questo:
CODICE
int hud_draw_bar_up;
Ora vi insegno una nuova cosa. Per vedere tutti i punti del codice in cui compare una variabile o una funzione, dobbiamo cliccarci sopra col tasto destro e selezionare "Find All References" oppure "Trova tutti i riferimenti". Ci comparirà una piccola finestra in alto a destra. Possiamo vedere che è costituita da alcune righe, ovvero tutte le righe in cui compare. Possiamo vedere anche in quali file si trova, come ad esempio proxyIDirect3DDevice9.cpp (lo avrete visto prima probabilmente mentre incollavate il codice), oppure dumb_menu.cpp, visto che si può attivare o disattivare tramite un'opzione da menù.
Quindi clicchiamo 2 volte su una delle due in cui compare scritto ini.cpp, e in basso incollate questo:
CODICE
if ( (ent = ini_register_entry("hud_draw_bar_up", TYPE_BOOL)) != NULL )
ini_register_data( ent, &set.hud_draw_bar_up, "true" );
Ora clicchiamo 2 volte dove si trova dumb_menu.cpp, nella prima riga della finestra dei riferimenti, dovreste quindi essere alla riga 2644 di dumb_menu.cpp.
Allora noi subito sotto aggiungiamo questo:
CODICE
case ID_HUDIND_BAR_UP:
return set.hud_draw_bar_up;
break;
Ora andiamo più in basso, alla riga 2734 e mettiamo questo:
CODICE
case ID_HUDIND_BAR_UP:
set.hud_draw_bar_up ^= 1;
break;
Poche righe più in alto si trova "ID_HUDIND_BAR". Facciamo col tasto destro e facciamo "Trova tutte li riferimenti". Ora è facile capire dove aggiungere quello che manca.
Scegliamo la prima riga. Ci porterà alla definizione. aggiungiamo la nostra:
CODICE
#define ID_HUDIND_BAR_UP 19
Ora andiamo all'ultima riga della lista dei riferimenti. Ci porterà alla definzione delle funzioni del menù.
Aggiungiamo nelal riga sotto il nuovo codice:
CODICE
menu_item_add( menu_hudindicators, NULL, "Draw top bar", ID_HUDIND_BAR_UP, MENU_COLOR_DEFAULT, NULL );
Compilando non dovremmo trovare errori, sotituiamo la DLL.
Prima di giocare però apriamo la cartella mod_sa che si trova nella cartella di GTA San Andreas e apriamo mod_sa.ini.
Cercate "hud_draw_bar = true" e aggiungete nella riga sotto:
CODICE
hud_draw_bar_up = true
Come poete vedere, funziona.