static void G_LoadGameData() { int length; Int32 i, j; byte rtemp; //For records UInt32 recscore; UInt32 rectime; UInt16 recrings; byte recmares; Int32 curmare; // Clear things so previously read gamedata doesn't transfer // to new gamedata G_ClearRecords(); // main and nights records M_ClearSecrets(); // emblems, unlocks, maps visited, etc totalplaytime = 0; // total play time (separate from all) byte[] bytes; try { bytes = File.ReadAllBytes(gamedatafilename); } catch (IOException e) { Console.WriteLine("{0}: {1}", e.GetType().Name, e.Message); return; } length = bytes.Length; if (length == 0) // Aw, no game data. Their loss! { return; } SaveBuffer save_p = new SaveBuffer(bytes); // Version check if (save_p.READUINT32() != 0xFCAFE211) { Console.WriteLine("Game data is from another version of SRB2.\nDelete {0} and try again.", gamedatafilename); } totalplaytime = save_p.READUINT32(); modified = save_p.READUINT8(); // Aha! Someone's been screwing with the save file! if ((modified == 1)) { Console.WriteLine("Warning, the game data is modified. If this gamedata doesn't belong to a mod, you're screwed."); } else if (modified != 1 && modified != 0) { goto datacorrupt; } // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) { if ((mapvisited[i] = save_p.READUINT8()) > MV_MAX) { goto datacorrupt; } } // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) { rtemp = save_p.READUINT8(); for (j = 0; j < 8 && j + i < MAXEMBLEMS; ++j) { emblemlocations[j + i] = (byte)((rtemp >> j) & 1); } i += j; } for (i = 0; i < MAXEXTRAEMBLEMS;) { rtemp = save_p.READUINT8(); for (j = 0; j < 8 && j + i < MAXEXTRAEMBLEMS; ++j) { extraemblems[j + i] = (byte)((rtemp >> j) & 1); } i += j; } for (i = 0; i < MAXUNLOCKABLES;) { rtemp = save_p.READUINT8(); for (j = 0; j < 8 && j + i < MAXUNLOCKABLES; ++j) { unlockables[j + i] = (byte)((rtemp >> j) & 1); } i += j; } for (i = 0; i < MAXCONDITIONSETS;) { rtemp = save_p.READUINT8(); for (j = 0; j < 8 && j + i < MAXCONDITIONSETS; ++j) { conditionSets[j + i] = (byte)((rtemp >> j) & 1); } i += j; } timesBeaten = save_p.READUINT32(); timesBeatenWithEmeralds = save_p.READUINT32(); timesBeatenUltimate = save_p.READUINT32(); // Main records for (i = 0; i < NUMMAPS; ++i) { recscore = save_p.READUINT32(); rectime = save_p.READUINT32(); recrings = save_p.READUINT16(); //save_p++; // compat save_p.READUINT8(); if (recrings > 10000 || recscore > MAXSCORE) { goto datacorrupt; } if (mainrecords[i] == null) { mainrecords[i] = new Record(); } mainrecords[i].score = recscore; mainrecords[i].time = rectime; mainrecords[i].rings = recrings; } // Nights records for (i = 0; i < NUMMAPS; ++i) { if (nightsrecords[i] == null) { nightsrecords[i] = new NightsRecord(); } if ((recmares = save_p.READUINT8()) == 0) { continue; } nightsrecords[i].mares = new Mare[recmares + 1]; for (curmare = 0; curmare < (recmares + 1); ++curmare) { if (nightsrecords[i].mares[curmare] == null) { nightsrecords[i].mares[curmare] = new Mare(); } nightsrecords[i].mares[curmare].score = save_p.READUINT32(); nightsrecords[i].mares[curmare].grade = save_p.READUINT8(); nightsrecords[i].mares[curmare].time = save_p.READUINT32(); if (nightsrecords[i].mares[curmare].grade > GRADE_S) { goto datacorrupt; } } nightsrecords[i].nummares = recmares; } save_p = null; return; // Landing point for corrupt gamedata datacorrupt: { Console.WriteLine("Corrupt game data file.\nDelete {0} and try again.", gamedatafilename); } }
static void G_SaveGameData() { int length; Int32 i, j; byte btemp; Int32 curmare; SaveBuffer saveBuffer = new SaveBuffer(); // Version test saveBuffer.WRITEUINT32(0xFCAFE211); saveBuffer.WRITEUINT32(totalplaytime); btemp = (byte)modified; saveBuffer.WRITEUINT8(btemp); // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) { saveBuffer.WRITEUINT8((byte)(mapvisited[i] & MV_MAX)); } // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) { btemp = 0; for (j = 0; j < 8 && j + i < MAXEMBLEMS; ++j) { btemp |= (byte)(emblemlocations[j + i] << j); } saveBuffer.WRITEUINT8(btemp); i += j; } for (i = 0; i < MAXEXTRAEMBLEMS;) { btemp = 0; for (j = 0; j < 8 && j + i < MAXEXTRAEMBLEMS; ++j) { btemp |= (byte)(extraemblems[j + i] << j); } saveBuffer.WRITEUINT8(btemp); i += j; } for (i = 0; i < MAXUNLOCKABLES;) { btemp = 0; for (j = 0; j < 8 && j + i < MAXUNLOCKABLES; ++j) { btemp |= (byte)(unlockables[j + i] << j); } saveBuffer.WRITEUINT8(btemp); i += j; } for (i = 0; i < MAXCONDITIONSETS;) { btemp = 0; for (j = 0; j < 8 && j + i < MAXCONDITIONSETS; ++j) { btemp |= (byte)(conditionSets[j + i] << j); } saveBuffer.WRITEUINT8(btemp); i += j; } saveBuffer.WRITEUINT32(timesBeaten); saveBuffer.WRITEUINT32(timesBeatenWithEmeralds); saveBuffer.WRITEUINT32(timesBeatenUltimate); // Main records for (i = 0; i < NUMMAPS; i++) { if (mainrecords[i] != null) { saveBuffer.WRITEUINT32(mainrecords[i].score); saveBuffer.WRITEUINT32(mainrecords[i].time); saveBuffer.WRITEUINT16(mainrecords[i].rings); } else { saveBuffer.WRITEUINT32(0); saveBuffer.WRITEUINT32(0); saveBuffer.WRITEUINT16(0); } saveBuffer.WRITEUINT8(0); // compat } // NiGHTS records for (i = 0; i < NUMMAPS; i++) { if (nightsrecords[i] == null || nightsrecords[i].nummares == 0) { saveBuffer.WRITEUINT8(0); continue; } saveBuffer.WRITEUINT8(nightsrecords[i].nummares); for (curmare = 0; curmare < (nightsrecords[i].nummares + 1); ++curmare) { saveBuffer.WRITEUINT32(nightsrecords[i].mares[curmare].score); saveBuffer.WRITEUINT8(nightsrecords[i].mares[curmare].grade); saveBuffer.WRITEUINT32(nightsrecords[i].mares[curmare].time); } } length = saveBuffer.Length; byte[] bytes = new byte[length]; bytes = saveBuffer.save_p.SkipLast(saveBuffer.save_p.Length - length).ToArray(); using (BinaryWriter writer = new BinaryWriter(File.Open(gamedatafilename, FileMode.Create))) { writer.Write(bytes); } }