@@ -61,42 +61,189 @@ void afficherVictoire(Vaisseau *joueur) {
6161
6262void attendreJoueur () {
6363 printf (COLOR_CYAN "\n[ Appuyez sur ENTREE pour continuer ]" COLOR_RESET );
64+ int c ;
65+ while ((c = getchar ()) != '\n' && c != EOF ); // Nettoie le buffer
6466 getchar ();
6567}
6668
6769// Sauvegarde et chargement
6870
71+ // Version du format de sauvegarde — à incrémenter à chaque ajout de champ
72+ #define SAVE_VERSION 4
73+
6974void sauvegarderPartie (Vaisseau * v ) {
70- FILE * fichier = fopen ("savegame.dat " , "wb " ); // 'wb' pour Write Binary
71- if (fichier == NULL ) {
75+ FILE * f = fopen ("savegame.sav " , "w " );
76+ if (f == NULL ) {
7277 printf ("\n" COLOR_RED "[ERREUR] Impossible de créer le fichier de sauvegarde." COLOR_RESET "\n" );
7378 return ;
7479 }
7580
76- // On écrit toute la structure d'un coup
77- fwrite (v , sizeof (Vaisseau ), 1 , fichier );
78-
79- fclose (fichier );
81+ // --- EN-TÊTE ---
82+ fprintf (f , "VERSION %d\n" , SAVE_VERSION );
83+
84+ // --- STATS DE BASE ---
85+ fprintf (f , "nom %s\n" , v -> nom );
86+ fprintf (f , "coque %d\n" , v -> coque );
87+ fprintf (f , "coqueMax %d\n" , v -> coqueMax );
88+ fprintf (f , "ferraille %d\n" , v -> ferraille );
89+ fprintf (f , "carburant %d\n" , v -> carburant );
90+ fprintf (f , "missiles %d\n" , v -> missiles );
91+ fprintf (f , "moteurs %d\n" , v -> moteurs );
92+ fprintf (f , "precision %d\n" , v -> precision );
93+ fprintf (f , "bouclierActuel %d\n" , v -> bouclierActuel );
94+ fprintf (f , "debuffArme %d\n" , v -> debuffArme );
95+ fprintf (f , "debuffMoteur %d\n" , v -> debuffMoteur );
96+
97+ // --- NAVIGATION ---
98+ fprintf (f , "distanceParcourue %d\n" , v -> distanceParcourue );
99+ fprintf (f , "distanceObjectif %d\n" , v -> distanceObjectif );
100+ fprintf (f , "secteurActuel %s\n" , v -> secteurActuel );
101+ fprintf (f , "seedSecteur %u\n" , v -> seedSecteur );
102+ fprintf (f , "explorationActuelle %d\n" ,v -> explorationActuelle );
103+ fprintf (f , "explorationMax %d\n" , v -> explorationMax );
104+
105+ // --- ÉTAT COMBAT ---
106+ fprintf (f , "ennemiPresent %d\n" , v -> ennemiPresent );
107+ fprintf (f , "ennemiCoqueActuelle %d\n" , v -> ennemiCoqueActuelle );
108+ fprintf (f , "chargeFTL %d\n" , v -> chargeFTL );
109+ fprintf (f , "maxchargeFTL %d\n" , v -> maxchargeFTL );
110+
111+ // --- COMPOSANTS (nom rang efficacite) ---
112+ fprintf (f , "ARME %s|%d|%d\n" ,
113+ v -> systemeArme .nom , v -> systemeArme .rang , v -> systemeArme .efficacite );
114+ fprintf (f , "BOUCLIER %s|%d|%d\n" ,
115+ v -> systemeBouclier .nom , v -> systemeBouclier .rang , v -> systemeBouclier .efficacite );
116+
117+ // --- ÉQUIPAGE (nom|role|pv|pvMax|estVivant|xp|niveau) ---
118+ fprintf (f , "nbMembres %d\n" , v -> nbMembres );
119+ for (int i = 0 ; i < 3 ; i ++ ) {
120+ Membre * m = & v -> equipage [i ];
121+ fprintf (f , "MEMBRE_%d %s|%d|%d|%d|%d|%d|%d\n" ,
122+ i , m -> nom , (int )m -> role , m -> pv , m -> pvMax ,
123+ m -> estVivant , m -> xp , m -> niveau );
124+ }
125+
126+ fclose (f );
80127 printf ("\n" COLOR_GREEN "💾 Progression synchronisée avec les serveurs de la Fédération." COLOR_RESET "\n" );
81128}
82129
83130int chargerPartie (Vaisseau * v ) {
84- FILE * fichier = fopen ("savegame.dat" , "rb" ); // 'rb' pour Read Binary
85- if (fichier == NULL ) {
86- return 0 ; // Pas de sauvegarde trouvée
131+ FILE * f = fopen ("savegame.sav" , "r" );
132+ if (f == NULL ) return 0 ; // Pas de sauvegarde
133+
134+ // --- Vérification de version ---
135+ int version = 0 ;
136+ if (fscanf (f , "VERSION %d\n" , & version ) != 1 ) {
137+ fclose (f );
138+ printf (COLOR_RED "[SAVE] Fichier de sauvegarde illisible. Nouvelle partie.\n" COLOR_RESET );
139+ return 0 ;
140+ }
141+
142+ if (version < SAVE_VERSION ) {
143+ fclose (f );
144+ printf (COLOR_YELLOW "[SAVE] Sauvegarde ancienne version (v%d → v%d). "
145+ "Impossible de charger.\n" COLOR_RESET , version , SAVE_VERSION );
146+ printf ("Appuyez sur ENTREE pour démarrer une nouvelle partie...\n" );
147+ getchar ();
148+ return 0 ;
149+ }
150+
151+ // --- Lecture ligne par ligne ---
152+ char clef [64 ];
153+ char valeur [256 ];
154+
155+ while (fscanf (f , "%63s" , clef ) == 1 ) {
156+
157+ // Stats de base
158+ if (strcmp (clef , "nom" ) == 0 )
159+ { fscanf (f , " %49[^\n]" , v -> nom ); }
160+ else if (strcmp (clef , "coque" ) == 0 )
161+ { fscanf (f , "%d" , & v -> coque ); }
162+ else if (strcmp (clef , "coqueMax" ) == 0 )
163+ { fscanf (f , "%d" , & v -> coqueMax ); }
164+ else if (strcmp (clef , "ferraille" ) == 0 )
165+ { fscanf (f , "%d" , & v -> ferraille ); }
166+ else if (strcmp (clef , "carburant" ) == 0 )
167+ { fscanf (f , "%d" , & v -> carburant ); }
168+ else if (strcmp (clef , "missiles" ) == 0 )
169+ { fscanf (f , "%d" , & v -> missiles ); }
170+ else if (strcmp (clef , "moteurs" ) == 0 )
171+ { fscanf (f , "%d" , & v -> moteurs ); }
172+ else if (strcmp (clef , "precision" ) == 0 )
173+ { fscanf (f , "%d" , & v -> precision ); }
174+ else if (strcmp (clef , "bouclierActuel" ) == 0 )
175+ { fscanf (f , "%d" , & v -> bouclierActuel ); }
176+ else if (strcmp (clef , "debuffArme" ) == 0 )
177+ { fscanf (f , "%d" , & v -> debuffArme ); }
178+ else if (strcmp (clef , "debuffMoteur" ) == 0 )
179+ { fscanf (f , "%d" , & v -> debuffMoteur ); }
180+
181+ // Navigation
182+ else if (strcmp (clef , "distanceParcourue" ) == 0 )
183+ { fscanf (f , "%d" , & v -> distanceParcourue ); }
184+ else if (strcmp (clef , "distanceObjectif" ) == 0 )
185+ { fscanf (f , "%d" , & v -> distanceObjectif ); }
186+ else if (strcmp (clef , "secteurActuel" ) == 0 )
187+ { fscanf (f , " %49[^\n]" , v -> secteurActuel ); }
188+ else if (strcmp (clef , "seedSecteur" ) == 0 )
189+ { fscanf (f , "%u" , & v -> seedSecteur ); }
190+ else if (strcmp (clef , "explorationActuelle" ) == 0 )
191+ { fscanf (f , "%d" , & v -> explorationActuelle ); }
192+ else if (strcmp (clef , "explorationMax" ) == 0 )
193+ { fscanf (f , "%d" , & v -> explorationMax ); }
194+
195+ // État combat
196+ else if (strcmp (clef , "ennemiPresent" ) == 0 )
197+ { fscanf (f , "%d" , & v -> ennemiPresent ); }
198+ else if (strcmp (clef , "ennemiCoqueActuelle" ) == 0 )
199+ { fscanf (f , "%d" , & v -> ennemiCoqueActuelle ); }
200+ else if (strcmp (clef , "chargeFTL" ) == 0 )
201+ { fscanf (f , "%d" , & v -> chargeFTL ); }
202+ else if (strcmp (clef , "maxchargeFTL" ) == 0 )
203+ { fscanf (f , "%d" , & v -> maxchargeFTL ); }
204+
205+ // Composants (format: NOM|rang|efficacite)
206+ else if (strcmp (clef , "ARME" ) == 0 ) {
207+ fscanf (f , " %255[^\n]" , valeur );
208+ sscanf (valeur , "%29[^|]|%d|%d" ,
209+ v -> systemeArme .nom , & v -> systemeArme .rang , & v -> systemeArme .efficacite );
210+ }
211+ else if (strcmp (clef , "BOUCLIER" ) == 0 ) {
212+ fscanf (f , " %255[^\n]" , valeur );
213+ sscanf (valeur , "%29[^|]|%d|%d" ,
214+ v -> systemeBouclier .nom , & v -> systemeBouclier .rang , & v -> systemeBouclier .efficacite );
215+ }
216+
217+ // Équipage
218+ else if (strcmp (clef , "nbMembres" ) == 0 )
219+ { fscanf (f , "%d" , & v -> nbMembres ); }
220+ else if (strncmp (clef , "MEMBRE_" , 7 ) == 0 ) {
221+ int idx = atoi (clef + 7 );
222+ if (idx >= 0 && idx < 3 ) {
223+ fscanf (f , " %255[^\n]" , valeur );
224+ int role ;
225+ sscanf (valeur , "%29[^|]|%d|%d|%d|%d|%d|%d" ,
226+ v -> equipage [idx ].nom , & role ,
227+ & v -> equipage [idx ].pv , & v -> equipage [idx ].pvMax ,
228+ & v -> equipage [idx ].estVivant ,
229+ & v -> equipage [idx ].xp , & v -> equipage [idx ].niveau );
230+ v -> equipage [idx ].role = (TypeRole )role ;
231+ }
232+ }
233+
234+ // Clef inconnue (nouveau champ d'une version future) → on ignore
235+ else {
236+ fgets (valeur , sizeof (valeur ), f );
237+ }
87238 }
88239
89- fread (v , sizeof (Vaisseau ), 1 , fichier );
90- fclose (fichier );
91- return 1 ; // Chargement réussi
240+ fclose (f );
241+ return 1 ;
92242}
93243
94244void supprimerSauvegarde () {
95- // On vérifie si le fichier existe avant de tenter de le supprimer
96- if (remove ("savegame.dat" ) == 0 ) {
245+ if (remove ("savegame.sav" ) == 0 ) {
97246 printf (COLOR_RED "\n[SYSTEME] Données de vol effacées. Fin de transmission.\n" COLOR_RESET );
98- } else {
99- // Le fichier n'existait probablement pas, rien à faire
100247 }
101248}
102249
@@ -110,17 +257,22 @@ void finaliserEvenement(Vaisseau *joueur) {
110257// Fonction utilitaire pour lire un entier de manière robuste
111258int lireEntierSecurise (int min , int max ) {
112259 int valeur ;
113- char buffer [100 ];
260+ char buffer [100 ]; // On lit une ligne de texte pour éviter les bugs de scanf
114261
115262 while (1 ) {
263+ // On lit toute la ligne (jusqu'à Entrée)
116264 if (fgets (buffer , sizeof (buffer ), stdin ) != NULL ) {
265+ // On essaie de convertir le texte en nombre
266+ // %d capture le nombre, le reste est ignoré
117267 if (sscanf (buffer , "%d" , & valeur ) == 1 ) {
268+ // Si c'est un nombre valide, on vérifie les bornes
118269 if (valeur >= min && valeur <= max ) {
119- return valeur ;
270+ return valeur ; // C'est gagné, on renvoie la valeur
120271 }
121272 }
122273 }
123274
275+ // Si on arrive ici, c'est que l'entrée était mauvaise
124276 printf (COLOR_RED "⚠ Entrée invalide. Veuillez taper un nombre entre %d et %d : " COLOR_RESET , min , max );
125277 printf (COLOR_YELLOW "> " COLOR_RESET );
126278 }
@@ -135,7 +287,6 @@ int lireChoix(int defaut) {
135287 int c ; while ((c = getchar ()) != '\n' && c != EOF );
136288 return defaut ;
137289 }
138- int c ; while ((c = getchar ()) != '\n' && c != EOF ); // vide le \n après succès
139290 return choix ;
140291}
141292
0 commit comments