#include #include #include #include #include #include #include ".\i18n.h" #include ".\DataOfRanger1_jp.h" #include ".\DataOfRanger2.h" #include ".\DataOfRanger3_jp.h" #include ".\DataOfRanger3_oversea.h" void insertData(const char *filename, const unsigned char *data, size_t dataSize, long position, int ToolLanguage); int crc16_table[]; unsigned int CRC16(char *data, int size); void ChunkCrypt(unsigned int *data, int size); void CryptRanger1(const char *filename,int ToolLanguage); unsigned char GetR1Flag(const char *filename, unsigned int FlagType,int ToolLanguage); unsigned int DistributeRanger1jpMission(const char *filename,int ToolLanguage); unsigned int DistributeRanger23Mission(const char *filename,char initGameMark[],unsigned int BaseOffset,unsigned int BlockSize,const unsigned char *const Mission[],unsigned char BlockSet[],int ToolLanguage); void CreateInitialSave(int ToolLanguage,int InitialSaveType); unsigned int RNG(); unsigned int GenerateR1Seed(); unsigned int GenerateR1Time(const char *filename,int ToolLanguage); unsigned short GenerateR1Date(const char *filename,int ToolLanguage); unsigned int ManaphyMissionReset(const char *filename,int ToolLanguage); #define GAME_VERSION_RANGER1 1 #define GAME_VERSION_RANGER2 2 #define GAME_VERSION_RANGER3 3 #define GAME_LANGUAGE_JP 1 #define GAME_LANGUAGE_OVERSEA 2 #define GAME_LANGUAGE_US_EN 3 #define GAME_LANGUAGE_EU_EN 4 #define GAME_LANGUAGE_EU_FR 5 #define GAME_LANGUAGE_EU_IT 6 #define GAME_LANGUAGE_EU_DE 7 #define GAME_LANGUAGE_EU_SP 8 int main(int argc, char *argv[]) { //system("chcp 65001"); printf("*-------------------------------------------------------------*\n"); printf("| 宝可梦巡护员网络任务配信器 v1.0 ——卧看微尘制作 |\n"); printf("| PokemonRangerNetMissionDistributionTool v1.0 made by wokann |\n"); printf("| 2023.12.18 |\n"); printf("*-------------------------------------------------------------*\n\n"); int ToolLanguage = -1; while(1) { for(int i = 0; i < TOOL_LANGUAGE_COUNTS;i++) { //显示提示输入本工具的显示语言 printf(TextOfPRNMDTool[i][0]); } printf(":"); scanf("%d", &ToolLanguage); getchar(); if(ToolLanguage > 0 && ToolLanguage <= TOOL_LANGUAGE_COUNTS) { ToolLanguage--; printf("*------------------------------------------------*\n\n"); break; } else { for(int i = 0; i < TOOL_LANGUAGE_COUNTS;i++) { //显示参数错误 printf(TextOfPRNMDTool[i][1]); } printf("\n"); } } int IfMakeInitialSave = 0; int InitialSaveType = -1; if(argc < 2) { while(1) { printf("*------------------------------------------------*\n"); //显示使用方法 printf(TextOfPRNMDTool[ToolLanguage][2]); //显示是否创建初始存档 printf(TextOfPRNMDTool[ToolLanguage][60]); scanf("%d", &IfMakeInitialSave); getchar(); if(IfMakeInitialSave == 1) { //显示初始存档类型 printf(TextOfPRNMDTool[ToolLanguage][61]); scanf("%d", &InitialSaveType); getchar(); while(1) { if(InitialSaveType>=1 && InitialSaveType <=4) { InitialSaveType--; CreateInitialSave(ToolLanguage,InitialSaveType); //显示是否继续创建初始存档 printf(TextOfPRNMDTool[ToolLanguage][68]); scanf("%d", &IfMakeInitialSave); getchar(); printf("\n"); if(IfMakeInitialSave == 1) break; else if(IfMakeInitialSave == 2) { //显示按回车退出 printf(TextOfPRNMDTool[ToolLanguage][3]); getchar(); // 等待用户按下回车键 return 1; } else { //显示参数错误 printf(TextOfPRNMDTool[ToolLanguage][1]); printf("\n"); break; } } else { //显示参数错误 printf(TextOfPRNMDTool[ToolLanguage][1]); printf("\n"); break; } } } else if(IfMakeInitialSave == 2) { //显示按回车退出 printf(TextOfPRNMDTool[ToolLanguage][3]); getchar(); // 等待用户按下回车键 return 1; } else { //显示参数错误 printf(TextOfPRNMDTool[ToolLanguage][1]); printf("\n"); } } } //显示本次处理文本数量 printf(TextOfPRNMDTool[ToolLanguage][4],argc - 1); unsigned int IsR1OverseaExisted = false; for(int i = 1; i < argc; i++) { //显示当前文本序号 printf(TextOfPRNMDTool[ToolLanguage][5],i); //获取存档文件名,并创建 "Distributed_"+原名 的另存文件 const char *originfilename = argv[i]; //显示原文件名 printf(TextOfPRNMDTool[ToolLanguage][6],originfilename); char newfilename[65535]; memset(newfilename, 0, sizeof(newfilename)); const char *lastSlash = strrchr(originfilename, '\\');// 找到路径中最后一个反斜杠的位置 if (lastSlash != NULL) { int position = lastSlash - originfilename;// 获取路径末尾的索引位置 strncpy(newfilename, originfilename, position + 1); // 复制路径内容到新文件名(包括最后的反斜杠) strcat(newfilename, TextOfPRNMDTool[ToolLanguage][7]); // 在路径后面追加前缀 strcat(newfilename, lastSlash + 1);// 追加原始文件名(不包括反斜杠) } else // 如果未找到反斜杠,则直接在文件名前插入前缀 { strcpy(newfilename, TextOfPRNMDTool[ToolLanguage][7]); strcat(newfilename, originfilename); } //拷贝原文件至另存文件 FILE *originalFile, *newFile; originalFile = fopen(originfilename, "rb"); if (originalFile == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][8],originfilename); //显示本文件处理结束 printf(TextOfPRNMDTool[ToolLanguage][9],i); continue; } newFile = fopen(newfilename, "wb"); if (newFile == NULL) { //显示无法另存文件 printf(TextOfPRNMDTool[ToolLanguage][10],originfilename); //显示本文件处理结束 printf(TextOfPRNMDTool[ToolLanguage][9],i); continue; } char buffer[1024]; size_t bytesRead; while ((bytesRead = fread(buffer, 1, sizeof(buffer), originalFile)) > 0) { fwrite(buffer, 1, bytesRead, newFile); } fclose(originalFile); fclose(newFile); //读取文件头,判断版本及语言 unsigned char gGameVersion = 0; unsigned char gGameLanguage = 0; char *gGameMark = (char *)malloc(8); char *gGameMarkR1_2 = (char *)malloc(4); unsigned int *OffsetOfSave = (unsigned int *)malloc(4); char initGameMarkR1_1[0x8] = {0x50,0x4B,0x52,0x2D,0x30,0x35,0x39,0x00}; //PKR-059/0 char initGameMarkR1_2[0x4] = {0x61,0x30,0x30,0x00}; //a00/0 char initGameMarkR2[0x8] = {0x44,0x53,0x50,0x52,0x53,0x00,0x00,0x00}; //DSPRS/0/0/0 char initGameMarkR3[0x8] = {0x44,0x53,0x52,0x41,0x53,0x41,0x00,0x00}; //DSRASA/0/0 newFile = fopen(newfilename, "rb"); fseek(newFile, 0, SEEK_SET); fread(gGameMark, 1, 8, newFile); fseek(newFile, 8, SEEK_SET); fread(gGameMarkR1_2, 1, 4, newFile); fseek(newFile, 8, SEEK_SET); fread(OffsetOfSave, 1, 4, newFile); fclose(newFile); if(!strcmp(gGameMark,initGameMarkR1_1) && !strcmp(gGameMarkR1_2,initGameMarkR1_2)) { gGameVersion = GAME_VERSION_RANGER1; CryptRanger1(newfilename,ToolLanguage); unsigned char LanguageFlag = GetR1Flag(newfilename,0x1B,ToolLanguage); if(LanguageFlag == 1) gGameLanguage = GAME_LANGUAGE_JP; else if(LanguageFlag >=2 && LanguageFlag <=6) gGameLanguage = GAME_LANGUAGE_OVERSEA; else { remove(newfilename); //显示r1存档错误 printf(TextOfPRNMDTool[ToolLanguage][11]); //显示本文件处理结束 printf(TextOfPRNMDTool[ToolLanguage][9],i); continue; } } else if(!strcmp(gGameMark,initGameMarkR2) && OffsetOfSave[0] == 0x1C) { gGameVersion = GAME_VERSION_RANGER2; gGameLanguage = GAME_LANGUAGE_JP; //2代任务地址日版海外版相同,选哪种语言均可 //gGameLanguage = GAME_LANGUAGE_OVERSEA; //2代任务地址日版海外版相同,选哪种语言均可 } else if(!strcmp(gGameMark,initGameMarkR3) && (OffsetOfSave[0] == 0x1C || OffsetOfSave[0] == 0x100)) { gGameVersion = GAME_VERSION_RANGER3; if(OffsetOfSave[0] == 0x1C) gGameLanguage = GAME_LANGUAGE_JP; else if(OffsetOfSave[0] == 0x100) gGameLanguage = GAME_LANGUAGE_OVERSEA; } else { remove(newfilename); //显示r123存档错误 printf(TextOfPRNMDTool[ToolLanguage][12]); //显示本文件处理结束 printf(TextOfPRNMDTool[ToolLanguage][9],i); continue;; } if(gGameVersion != 2) { //显示存档游戏版本及语言 printf(TextOfPRNMDTool[ToolLanguage][13 + gGameLanguage],gGameVersion); } else { //显示存档游戏版本及语言 printf(TextOfPRNMDTool[ToolLanguage][13],gGameVersion); } //根据版本及语言进行配信 unsigned int HadDistributedCounts = 0; unsigned int HasResetManaphy = false; if(gGameVersion == GAME_VERSION_RANGER1) { if(gGameLanguage == GAME_LANGUAGE_JP) { HadDistributedCounts = DistributeRanger1jpMission(newfilename,ToolLanguage); HasResetManaphy = ManaphyMissionReset(newfilename,ToolLanguage); CryptRanger1(newfilename,ToolLanguage); } else if(gGameLanguage == GAME_LANGUAGE_OVERSEA) { IsR1OverseaExisted = true; //显示巡护员1海外版任务说明 printf(TextOfPRNMDTool[ToolLanguage][35]); HasResetManaphy = ManaphyMissionReset(newfilename,ToolLanguage); CryptRanger1(newfilename,ToolLanguage); } } else if(gGameVersion == GAME_VERSION_RANGER2) { unsigned char BlockSet[6] = {0,1,2,3,4,5}; if(gGameLanguage == GAME_LANGUAGE_JP||gGameLanguage == GAME_LANGUAGE_OVERSEA) HadDistributedCounts = DistributeRanger23Mission(newfilename,initGameMarkR2,0x1BDBE,0x3020,Ranger2Mission,BlockSet,ToolLanguage); } else if(gGameVersion == GAME_VERSION_RANGER3) { unsigned char BlockSet[6] = {0,1,2,3,4,6}; if(gGameLanguage == GAME_LANGUAGE_JP) HadDistributedCounts = DistributeRanger23Mission(newfilename,initGameMarkR3,0x1A4BC,0x401C,Ranger3jpMission,BlockSet,ToolLanguage); else if(gGameLanguage == GAME_LANGUAGE_OVERSEA) HadDistributedCounts = DistributeRanger23Mission(newfilename,initGameMarkR3,0x1A900,0x4100,Ranger3overseaMission,BlockSet,ToolLanguage); } //确认是否需要进行配信另存新文件 if((gGameVersion == GAME_VERSION_RANGER1 && gGameLanguage == GAME_LANGUAGE_JP && HadDistributedCounts == 4 && HasResetManaphy == false)|| (gGameVersion == GAME_VERSION_RANGER1 && gGameLanguage == GAME_LANGUAGE_OVERSEA && HasResetManaphy == false)|| (gGameVersion == GAME_VERSION_RANGER2 && HadDistributedCounts == 6)|| (gGameVersion == GAME_VERSION_RANGER3 && HadDistributedCounts == 6)) { remove(newfilename); //显示文件无需配信 printf(TextOfPRNMDTool[ToolLanguage][22]); } else //显示另存文件名 printf(TextOfPRNMDTool[ToolLanguage][23],newfilename); //显示本文件处理结束 printf(TextOfPRNMDTool[ToolLanguage][9],i); } //显示所有文件处理完成 printf(TextOfPRNMDTool[ToolLanguage][24], argc - 1); if(IsR1OverseaExisted == true) { //显示存在1代海外版,见上文说明 printf(TextOfPRNMDTool[ToolLanguage][25]); } //显示退出程序 printf(TextOfPRNMDTool[ToolLanguage][3]); getchar(); // 等待用户按下回车键 return 0; } // 插入数据到文件的函数 void insertData(const char *filename, const unsigned char *data, size_t dataSize, long position, int ToolLanguage) { FILE *file = fopen(filename, "rb+"); if (file == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return; } // 移动文件指针到特定位置 fseek(file, position, SEEK_SET); // 写入要插入的数据(覆盖) fwrite(data, 1, dataSize, file); // 关闭文件 fclose(file); } unsigned char GetR1Flag(const char *filename, unsigned int FlagType,int ToolLanguage) { FILE *sav = fopen(filename, "rb"); if (sav == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return 0; } unsigned int *dataSize = (unsigned int *)malloc(4); unsigned int *siskintsdChunkOffset = (unsigned int *)malloc(4); unsigned char *Flag = (unsigned char *)malloc(1); unsigned char *tmp = (unsigned char *)malloc(1); for(int i = 0; i < 10; i++) { fseek(sav,0x44 + i * 0x30,SEEK_SET); fread(dataSize, 1, 4, sav); if(dataSize[0] == 0x260C) { fseek(sav,0x40 + i * 0x30,SEEK_SET); fread(siskintsdChunkOffset, 1, 4, sav); break; } } fseek(sav,siskintsdChunkOffset[0] + 0x10,SEEK_SET); fread(Flag, 1, 1, sav); fseek(sav,siskintsdChunkOffset[0] + 0x2710,SEEK_SET); fread(tmp, 1, 1, sav); if(tmp[0]>Flag[0] && tmp[0]!=0xFF && Flag[0] !=0xFF) { fseek(sav,siskintsdChunkOffset[0] + FlagType + 0x2700,SEEK_SET); fread(Flag, 1, 1, sav); } else if(tmp[0]<=Flag[0] && tmp[0]!=0xFF && Flag[0] !=0xFF) { fseek(sav,siskintsdChunkOffset[0] + FlagType,SEEK_SET); fread(Flag, 1, 1, sav); } else if(tmp[0] == 0xFF) { fseek(sav,siskintsdChunkOffset[0] + FlagType,SEEK_SET); fread(Flag, 1, 1, sav); } else if(Flag[0] == 0xFF) { fseek(sav,siskintsdChunkOffset[0] + FlagType + 0x2700,SEEK_SET); fread(Flag, 1, 1, sav); } fclose(sav); return Flag[0]; } int crc16_table[] = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 }; unsigned int CRC16(char *data, int size) { unsigned int chk = 0; int i; for (i = 0; i < size; i++) { chk = (crc16_table[(data[i] ^ chk) & 0xFF] ^ chk >> 8); } return chk; } void ChunkCrypt(unsigned int *data, int size) { int i; // r5 unsigned int rand; // ST04_4 unsigned int h_rand; // r0 unsigned int s_rand = data[0]; // the initial seed is located before the encrypted data for(i = 1; i < (size/4); i++) { rand = 0x5D588B65 * s_rand; h_rand = rand; s_rand = 0x5D588B65 * rand; data[i] ^= (h_rand & 0xFFFF0000) | (s_rand >> 16); } } void CryptRanger1(const char *filename,int ToolLanguage) { FILE *sav = fopen(filename, "rb+"); if (sav == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return; } //获取存档当前加解密状态 char IsEncrypted = true;//默认假定为加密状态 unsigned int *maxChunkCounts = (unsigned int *)malloc(0x4); fseek(sav,0x1C,SEEK_SET); fread(maxChunkCounts, 1, 4, sav); if(maxChunkCounts[0] == 10) IsEncrypted = false;//解密状态 free(maxChunkCounts); //获取解密的存档头数据(不含存档标识符),用于后续块调用数据 unsigned int *DecryptedHeader = (unsigned int *)malloc((R1JP_SAVE_HEADER_SIZE-0xC)); fseek(sav, 0xC, SEEK_SET); fread(DecryptedHeader, 1, (R1JP_SAVE_HEADER_SIZE-0xC), sav); if(IsEncrypted) ChunkCrypt(DecryptedHeader, (R1JP_SAVE_HEADER_SIZE-0xC)); //加解密文件头的两个块 //开头的两个文件头,理论上应该是完全一致的镜像备份 for(int i = 0; i < 2;i++) { unsigned int *R1JPSaveheader = (unsigned int *)malloc((R1JP_SAVE_HEADER_SIZE-0xC)); fseek(sav, 0xC + (R1JP_SAVE_HEADER_SIZE*i), SEEK_SET); fread(R1JPSaveheader, 1, (R1JP_SAVE_HEADER_SIZE-0xC), sav); if(!IsEncrypted)//解密状态下重算crc16 R1JPSaveheader[1] = CRC16((char*)R1JPSaveheader+0x8, (R1JP_SAVE_HEADER_SIZE-0xC-0x8)); ChunkCrypt(R1JPSaveheader, (R1JP_SAVE_HEADER_SIZE-0xC)); fseek(sav, 0xC + (R1JP_SAVE_HEADER_SIZE*i), SEEK_SET); fwrite(R1JPSaveheader, 1, (R1JP_SAVE_HEADER_SIZE-0xC), sav); free(R1JPSaveheader); } //加解密剩余的块 //理论上有3(单机)+7(配信位)=10块,实际最多3+4(配信)=7块 //siskin.tsd, wren.tsd, hazel.tsd, //set_delivery001.dat, set_delivery003.dat, set_delivery002.dat, set_delivery004.dat //正常情况siskin.tsd位于第1位,剩余块按游戏内生成和接收配信的先后关系确定实际顺序 //不确定当年没有建档就去配信,是否会将siskin.tsd延后 int existedChunk = 0; for(int i = 0; i < 10; i++) { unsigned int datasize = DecryptedHeader[0xE + (i*0xC)]; if(datasize) existedChunk++; } for(int i = 0; i < existedChunk; i++) { unsigned int subChunkCounts = DecryptedHeader[0xC + (i*0xC)] >> 16 & 0xFF; unsigned int chunkOffset = DecryptedHeader[0xD + (i*0xC)]; unsigned int dataSize = DecryptedHeader[0xE + (i*0xC)]; unsigned int subChunkSize = DecryptedHeader[0xF + (i*0xC)] / subChunkCounts; if(chunkOffset != 0) { unsigned int j; for(j = 0; (j < subChunkCounts) && (j < 3); j++) { unsigned int *subchunk = (unsigned int *)malloc(subChunkSize); fseek(sav, chunkOffset + (subChunkSize*j), SEEK_SET); fread(subchunk, 1, subChunkSize, sav); if(!IsEncrypted && ((subchunk[1] & 0xFFFF) != 0))//解密状态下重算crc16,且原crc不为0(中断存档使用结束后crc16为0) subchunk[1] = CRC16((char*)subchunk+0x18, dataSize); ChunkCrypt(subchunk, (dataSize+0x18)); fseek(sav, chunkOffset + (subChunkSize*j), SEEK_SET); fwrite(subchunk, 1, (dataSize+0x18), sav); free(subchunk); } } //unsigned int nowOffset = ftell(sav); //printf("当前地址为:%08x 字节\n", nowOffset); } free(DecryptedHeader); fclose(sav); return; } unsigned int DistributeRanger1jpMission(const char *filename,int ToolLanguage) { FILE *sav = fopen(filename, "rb+"); if (sav == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return 0; } //获取解密的存档头数据(不含存档标识符),用于后续块调用数据 unsigned int *DecryptedHeader = (unsigned int *)malloc((R1JP_SAVE_HEADER_SIZE-0xC)); fseek(sav, 0xC, SEEK_SET); fread(DecryptedHeader, 1, (R1JP_SAVE_HEADER_SIZE-0xC), sav); fclose(sav); //计算现有块数,以及是否存在已配信块 int existedChunk = 0; unsigned int HadDistributedCounts = 0; char chunkOrder[7]= { [SISKIN] = 10,//siskin.tsd datasize:0x260C chunksize:0x4E00 [WREN] = 10,//wren.tsd datasize:0x30D4 chunksize:0x6200 [HAZEL] = 10,//hazel.tsd datasize:0x30D4 chunksize:0x6200 [D001] = 10,//set_delivery001.dat datasize:0xE7E8 chunksize:0xE800 [D002] = 10,//set_delivery003.dat datasize:0x67E8 chunksize:0x6800 [D003] = 10,//set_delivery002.dat datasize:0x57E8 chunksize:0x5800 [D004] = 10,//set_delivery004.dat datasize:0x4FE8 chunksize:0x5000 }; for(int i = 0; i < 10; i++) { unsigned int dataSize = DecryptedHeader[0xE + (i*0xC)]; unsigned char firstnNameChar = DecryptedHeader[0x5 + (i*0xC)]; if(dataSize) existedChunk++; if(dataSize == 0x260C) chunkOrder[SISKIN]=i; else if(dataSize == 0x30D4 && firstnNameChar == 'w') chunkOrder[WREN]=i; else if(dataSize == 0x30D4 && firstnNameChar == 'h') chunkOrder[HAZEL]=i; else if(dataSize == 0xE7E8) chunkOrder[D001]=i; else if(dataSize == 0x67E8) chunkOrder[D002]=i; else if(dataSize == 0x57E8) chunkOrder[D003]=i; else if(dataSize == 0x4FE8) chunkOrder[D004]=i; } //根据现有块,在后方插入配信数据 for(int i = 0;i < 4;i++) { unsigned int siskintsdChunkOffset = DecryptedHeader[0xD + (chunkOrder[SISKIN]*0xC)]; unsigned char MissionNewFlag; if(chunkOrder[i+3] == 10) { unsigned int previousChunkOffset = DecryptedHeader[0xD + ((existedChunk-1)*0xC)]; unsigned int previousChunkSize = DecryptedHeader[0xF + ((existedChunk-1)*0xC)]; unsigned int NowChunkOffset = previousChunkOffset + previousChunkSize; //写入saveheader insertData(filename, SaveHeaderOfD00[i], 0x30, 0x20 + (existedChunk*0x30),ToolLanguage); insertData(filename, SaveHeaderOfD00[i], 0x30, 0x20 + (existedChunk*0x30) + 0x200,ToolLanguage); //写入siskin.tsd的新brief insertData(filename, BriefOfD00[i], 0x56C, siskintsdChunkOffset + 0x30 + i*0x56C,ToolLanguage); insertData(filename, BriefOfD00[i], 0x56C, siskintsdChunkOffset + 0x30 + i*0x56C + 0x2700,ToolLanguage); //写入新chunk insertData(filename, DataOfD00[i], ChunkSizeOfD00[i], NowChunkOffset,ToolLanguage); //更新saveheader的chunk偏移地址 FILE *sav = fopen(filename, "rb+"); fseek(sav, (0x40 + (existedChunk*0x30)), SEEK_SET); fwrite(&NowChunkOffset, 1, 4, sav); fseek(sav, (0x240 + (existedChunk*0x30)), SEEK_SET); fwrite(&NowChunkOffset, 1, 4, sav); //更新siskin.tsd的new mission flag fseek(sav,siskintsdChunkOffset + 0x22,SEEK_SET); MissionNewFlag = fgetc(sav); MissionNewFlag = MissionNewFlag | (1<tm_hour; int minute = localTime->tm_min; int second = localTime->tm_sec; unsigned int time = 0xFFFFFFFF; // 默认值。后续更新从saveheader和chunkheader获取 time &= 0xFFE0FFFF; time |= ((hour & 0x1F) << HOUR_OFFSET); time &= 0xFFFFFFC0; time |= (minute & 0x3F); time &= 0xFFFFF03F; time |= ((second & 0x3F) << SECOND_OFFSET); return time; } unsigned short GenerateR1Date(const char *filename,int ToolLanguage) { #define YEAR_OFFSET 7 #define MONTH_OFFSET 4 #define DAY_OFFSET 0 FILE *file = fopen(filename, "rb"); if (file == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return 0; } // 获取当前系统时间 time_t currentTime; struct tm *localTime; time(¤tTime); localTime = localtime(¤tTime); // 提取年月日时分秒信息 int year = localTime->tm_year + 1900; // 年份需加上 1900 int month = localTime->tm_mon + 1; // 月份从 0 开始 int day = localTime->tm_mday; unsigned short date = 0xFFFF; // 默认值。后续更新从saveheader和chunkheader获取 date &= 0xFF80; date |= (year & 0x7F); date &= 0xF87F; date |= ((month & 0xF) << MONTH_OFFSET); date &= 0x7FF; date |= ((day & 0x1F) << DAY_OFFSET); return date; } unsigned int ManaphyMissionReset(const char *filename,int ToolLanguage) { #define MANAPHY_STATUS_MISSION_NOT_GET 0 #define MANAPHY_STATUS_EGG_NOT_RECEIVED 1 #define MANAPHY_STATUS_EGG_RECEIVED 2 #define MANAPHY_STATUS_EGG_SENT 3 #define RESET_NOTHING 0 #define RESET_TO_EGG_NOT_RECEIVED 1 #define RESET_TO_EGG_RECEIVED 2 FILE *file = fopen(filename, "rb+"); if (file == NULL) { //显示无法打开文件 printf(TextOfPRNMDTool[ToolLanguage][26]); return 0; } fclose(file); unsigned int HasResetManaphy = false; unsigned int ManaphyStatus = MANAPHY_STATUS_MISSION_NOT_GET; unsigned int ResetStatus = RESET_NOTHING; //获取相关flag unsigned char LanguageFlag = GetR1Flag(filename,0x1B,ToolLanguage); unsigned char ManaphyFlag = GetR1Flag(filename,0x20,ToolLanguage); unsigned int dateOfObtainManaphyEgg = 0; for(int i = 0;i < 4;i++) { unsigned char tmp = GetR1Flag(filename,0x24 + i,ToolLanguage); dateOfObtainManaphyEgg = dateOfObtainManaphyEgg | (tmp << (8*i)); } //根据flag确定当前status if(LanguageFlag == 1)//日版,日版此时至少已经完成配信,处于status 1-3 { if(ManaphyFlag == 0 && dateOfObtainManaphyEgg == 0) ManaphyStatus = MANAPHY_STATUS_EGG_NOT_RECEIVED; else if(ManaphyFlag == 1 && dateOfObtainManaphyEgg != 0) ManaphyStatus = MANAPHY_STATUS_EGG_RECEIVED; else if(ManaphyFlag == 2 && dateOfObtainManaphyEgg != 0) ManaphyStatus = MANAPHY_STATUS_EGG_SENT; } else if(LanguageFlag >= 2 && LanguageFlag <= 6)//海外版,海外版status 0-4均有可能 { if(ManaphyFlag == 0 && dateOfObtainManaphyEgg == 0) ManaphyStatus = MANAPHY_STATUS_MISSION_NOT_GET; else if(ManaphyFlag == 3 && dateOfObtainManaphyEgg == 0) ManaphyStatus = MANAPHY_STATUS_EGG_NOT_RECEIVED; else if(ManaphyFlag == 1 && dateOfObtainManaphyEgg != 0) ManaphyStatus = MANAPHY_STATUS_EGG_RECEIVED; else if(ManaphyFlag == 2 && dateOfObtainManaphyEgg != 0) ManaphyStatus = MANAPHY_STATUS_EGG_SENT; } //处理status2、3的情况,获取选择哪种重置 if(ManaphyStatus == MANAPHY_STATUS_EGG_RECEIVED) { while(1) { //显示已接收蛋的重置选项 printf(TextOfPRNMDTool[ToolLanguage][69]); scanf("%d", &ResetStatus); getchar(); if(ResetStatus == 1) { ResetStatus = RESET_TO_EGG_NOT_RECEIVED; break; } else if(ResetStatus == 2) { ResetStatus = RESET_NOTHING; break; } else { //显示参数错误 printf(TextOfPRNMDTool[ToolLanguage][1]); printf("\n"); } } } else if( ManaphyStatus == MANAPHY_STATUS_EGG_SENT) { while(1) { //显示已传送蛋的重置选项 printf(TextOfPRNMDTool[ToolLanguage][70]); scanf("%d", &ResetStatus); getchar(); if(ResetStatus == 1) { ResetStatus = RESET_TO_EGG_NOT_RECEIVED; break; } else if(ResetStatus == 2) { ResetStatus = RESET_TO_EGG_RECEIVED; break; } else if(ResetStatus == 3) { ResetStatus = RESET_NOTHING; break; } else { //显示参数错误 printf(TextOfPRNMDTool[ToolLanguage][1]); printf("\n"); } } } //根据重置选项进行重置 file = fopen(filename, "rb+"); unsigned int *dataSize = (unsigned int *)malloc(4); unsigned int *siskintsdChunkOffset = (unsigned int *)malloc(4); for(int i = 0; i < 10; i++) { fseek(file,0x44 + i * 0x30,SEEK_SET); fread(dataSize, 1, 4, file); if(dataSize[0] == 0x260C) { fseek(file,0x40 + i * 0x30,SEEK_SET); fread(siskintsdChunkOffset, 1, 4, file); break; } } if(ResetStatus == RESET_TO_EGG_NOT_RECEIVED) { if(LanguageFlag == 1) ManaphyFlag = 0; else ManaphyFlag = 3; dateOfObtainManaphyEgg = 0; unsigned char MissionNewFlag; //重置newflag fseek(file,siskintsdChunkOffset[0] + 0x22,SEEK_SET); MissionNewFlag = fgetc(file); MissionNewFlag = MissionNewFlag | 1; fseek(file,siskintsdChunkOffset[0] + 0x22,SEEK_SET); fwrite(&MissionNewFlag, 1, 1, file); fseek(file,siskintsdChunkOffset[0] + 0x2722,SEEK_SET); MissionNewFlag = fgetc(file); MissionNewFlag = MissionNewFlag | 1; fseek(file,siskintsdChunkOffset[0] + 0x2722,SEEK_SET); fwrite(&MissionNewFlag, 1, 1, file); //重置玛娜霏flag fseek(file,siskintsdChunkOffset[0] + 0x20,SEEK_SET); fwrite(&ManaphyFlag,1,1,file); fseek(file,siskintsdChunkOffset[0] + 0x2720,SEEK_SET); fwrite(&ManaphyFlag,1,1,file); //重置获得蛋日期 fseek(file,siskintsdChunkOffset[0] + 0x24,SEEK_SET); fwrite(&dateOfObtainManaphyEgg,1,4,file); fseek(file,siskintsdChunkOffset[0] + 0x2724,SEEK_SET); fwrite(&dateOfObtainManaphyEgg,1,4,file); //显示已重置为未接收蛋 printf(TextOfPRNMDTool[ToolLanguage][71]); //显示任务需通关提示 printf(TextOfPRNMDTool[ToolLanguage][73]); HasResetManaphy = true; } else if(ResetStatus == RESET_TO_EGG_RECEIVED) { ManaphyFlag = 1; //重置玛娜霏flag fseek(file,siskintsdChunkOffset[0] + 0x20,SEEK_SET); fwrite(&ManaphyFlag,1,1,file); fseek(file,siskintsdChunkOffset[0] + 0x2720,SEEK_SET); fwrite(&ManaphyFlag,1,1,file); //显示已重置为未传送蛋 printf(TextOfPRNMDTool[ToolLanguage][72]); //显示任务需通关提示 printf(TextOfPRNMDTool[ToolLanguage][73]); HasResetManaphy = true; } fclose(file); return HasResetManaphy; }