遊戲修改:天翔記
自從國中被我兩個同學推入「三國志」的無底洞以後,「三國志」和「信長之野望」就一直是我主要玩的遊戲。每一代都有其特色和精華,當然也有一些我討厭的機制。但大體來說我都會花時間下去玩(而且還會全破不少次),除了 ... 天翔記。
我本人是個種田派和公仔收集派的玩家,很遺憾的,「天翔記」是一款窮兵黷武的遊戲,這實在讓我很難上手。遊戲試圖要表現出「成長」的概念,這很好!但是到遊戲裏面就會發現 ... 一個剛出生的名將和久經戰陣的凡將是根本無法比擬的,這讓「天才」這兩個字在遊戲中基本上是不可能出現的。我認同能力不會一開始就全滿而要成長,但你差距也不可以高到這種程度吧!這樣完全不可能有名將的成長空間(因為在年輕時就被幹掉了)。此外,電腦的成長速度根本是用作弊來形容!我自己的經驗,當我用島津家努力違反自己的天性,一天到晚作戰時,卻發現「立花道雪」這老怪物的能力老早就上升的比我快30點,而且我主力培養的還只有義弘一個人而已 ... 經過一番奮戰,總算擊退道雪,天曉得下一季又再一次看到他,能力還比之前更高,我島津義弘都沒成長這麼快啊 ... 於是我關檔了。
可惜沒有威力加強版... 沒有就算了,那就自己來寫一個存檔修改器吧,當中也查了不少格式的資料,最後玩成品記載在下面:
我本人是個種田派和公仔收集派的玩家,很遺憾的,「天翔記」是一款窮兵黷武的遊戲,這實在讓我很難上手。遊戲試圖要表現出「成長」的概念,這很好!但是到遊戲裏面就會發現 ... 一個剛出生的名將和久經戰陣的凡將是根本無法比擬的,這讓「天才」這兩個字在遊戲中基本上是不可能出現的。我認同能力不會一開始就全滿而要成長,但你差距也不可以高到這種程度吧!這樣完全不可能有名將的成長空間(因為在年輕時就被幹掉了)。此外,電腦的成長速度根本是用作弊來形容!我自己的經驗,當我用島津家努力違反自己的天性,一天到晚作戰時,卻發現「立花道雪」這老怪物的能力老早就上升的比我快30點,而且我主力培養的還只有義弘一個人而已 ... 經過一番奮戰,總算擊退道雪,天曉得下一季又再一次看到他,能力還比之前更高,我島津義弘都沒成長這麼快啊 ... 於是我關檔了。
可惜沒有威力加強版... 沒有就算了,那就自己來寫一個存檔修改器吧,當中也查了不少格式的資料,最後玩成品記載在下面:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> struct nb6man { unsigned short dummy; unsigned char p_max; unsigned char b_max; unsigned char w_max; unsigned short p_real; unsigned short b_real; unsigned short w_real; unsigned char charming; unsigned char ambition; unsigned char loyalty; unsigned short merit; unsigned char blood; unsigned short attach; unsigned short gundan; unsigned short castle; unsigned short rise; unsigned char soldier; unsigned char training; unsigned char solloyal; unsigned char form; unsigned char workyear; unsigned char spouse; unsigned char birth;//-1454 unsigned short parents; unsigned short dummy2; unsigned char aptitude; //00aa bbcc unsigned char tech; unsigned char job; unsigned short soldier_type; unsigned char option1; // aabbbccc, aa:independent, bbb: ferocious, ccc: max_year unsigned char option2; unsigned char dummy4[4]; }__attribute__ ((__packed__)); struct nb6castle { unsigned char dummy[17]; unsigned short id; unsigned char hp; unsigned short farm; unsigned char bussiness; unsigned short men; unsigned char loyalty; unsigned short soldier; unsigned char dummy2[5]; }__attribute__ ((__packed__)); struct nb6castlemax { unsigned short dummy; unsigned char farm; // *10 unsigned char bussiness; unsigned int dummy2; }__attribute__ ((__packed__)); #define SABER 0x0007 #define RIDER 0x0038 #define GUNNER 0x01C0 #define NAVI 0x0E00 #define RATIO 0.7 static void util_forAllMen( char *, short, int ); static void util_cheat( struct nb6man *, int ); static long util_getFdSize( int ); static void util_printMan( struct nb6man * ); static void util_printMan2( struct nb6man * ); static void util_forAllCastle( char *, short, int ); static void util_cheat_castle( struct nb6castle *, struct nb6castlemax * ); static void util_printCastle( struct nb6castle *, struct nb6castlemax * ); static void util_find_man_cheat( char *, int, int, int ); static void util_find_man( char *, int, int, int ); int main( int argc, char *argv[] ) { int i = 0; char input[20]; char saveData[8]; char running = 1; int a1 = 0, a2 = 0, a3 = 0; char *delim = " "; int fd = open( "SAVEDAT.NB6", O_RDWR ); long fileSize = 0; char *_pFile = NULL; if( fd < 0 ) { printf( "File open failed!\n" ); return; } fileSize = util_getFdSize( fd ); if( fileSize == -1 ) { return; } _pFile = mmap( 0, fileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); _pFile += 11; // Offset printf( "Save Data:\n" ); for( i = 0 ; i < 8; i++ ) { printf( "%d: ", i ); if( _pFile[i*2] == 1 ) { printf( "%d.\n", 1454 + *( (short *)( _pFile + 4 + 16 + 158 * i ) ) ); saveData[i] = 1; } else { printf( "None.\n" ); saveData[i] = 0; } } _pFile += 4; // NULL _pFile += 16; // Save Count _pFile += 158 * 8; // Save Meta Data printf( "Please Select the Save Data you want to cheat: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 7 || atoi( input ) < 0 ) { printf( "Wrong range.\n" ); running = 0; } else if( saveData[atoi( input )] == 1 ) { _pFile += ( 93758 * atoi( input ) ) ; printf( "%d %d.\n", atoi( input ), 1454 + *( (short *)( _pFile ) ) ); } else { printf( "No Save Data.\n" ); running = 0; } while( running ) { printf( "Options:\n" ); printf( " 1: Men.\n" ); printf( " 2: Men without soldiers\n" ); printf( " 3: Print men.\n" ); printf( " 4: Castle.\n" ); printf( " 5: Castle Max.\n" ); printf( " 6: Print castle.\n" ); printf( " 7: Cheat on the target man.\n" ); printf( " 8: Search.\n" ); printf( " 9: Exit.\n" ); printf( "Your choice: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) == 1 ) { printf( "Please enter your country code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "country code: %d\n", atoi( input ) ); util_forAllMen( _pFile, (short)atoi( input ), 1 ); } else if( atoi( input ) == 2 ) { printf( "Please enter your country code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "army group code: %d\n", atoi( input ) ); util_forAllMen( _pFile, (short)atoi( input ), 0 ); } else if( atoi( input ) == 3 ) { printf( "Please enter your country code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "army group code: %d\n", atoi( input ) ); util_forAllMen( _pFile, (short)atoi( input ), 2 ); } else if( atoi( input ) == 4 ) { printf( "Please enter your army group code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "army group code: %d\n", atoi( input ) ); util_forAllCastle( _pFile, (short)atoi( input ), 0 ); } else if( atoi( input ) == 5 ) { printf( "Please enter your army group code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "army group code: %d\n", atoi( input ) ); util_forAllCastle( _pFile, (short)atoi( input ), 1 ); } else if( atoi( input ) == 6 ) { printf( "Please enter your army group code: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); // printf( "army group code: %d\n", atoi( input ) ); util_forAllCastle( _pFile, (short)atoi( input ), 2 ); } else if( atoi( input ) == 7 ) { printf( "Please enter the three abilities of the target man: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); a1 = atoi( strtok( input, delim ) ); a2 = atoi( strtok( NULL, delim ) ); a3 = atoi( strtok( NULL, delim ) ); // printf( "%d %d %d\n", a1, a2, a3 ); util_find_man_cheat( _pFile, a1/2, a2/2, a3/2 ); } else if( atoi( input ) == 8 ) { printf( "Please enter the three abilities of the target man: " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); a1 = atoi( strtok( input, delim ) ); a2 = atoi( strtok( NULL, delim ) ); a3 = atoi( strtok( NULL, delim ) ); // printf( "%d %d %d\n", a1, a2, a3 ); util_find_man( _pFile, a1/2, a2/2, a3/2 ); } else if( atoi( input ) == 9 ) { running = 0; } else { printf( "Wrong input!!\n" ); } } /* if( argc == 2 ) { util_forAllMen( "SAVEDAT.NB6", (short)atoi( argv[1] ) ); return 0; } else if( argc == 3 ) { util_forAllMen( "SAVEDAT.NB6", (short)atoi( argv[1] ) ); util_forAllCastle( "SAVEDAT.NB6", (short)atoi( argv[2] ) ); return 0; } printf( "Usage: cheat*/ munmap( _pFile, fileSize ); close( fd ); return 0; } static void util_forAllMen( char *_pFile, short _id, int _soldier_flag ) { char *_pManStart = NULL; struct nb6man *_pMan = NULL; int i = 0, counter = 1; //_pManStart = _pFile + 0x0FF5; _pManStart = _pFile + 0x0AE6; for( i = 0 ; i < 500 ; i++ ) { _pMan = ( struct nb6man * )( _pManStart + ( i * 47 ) ); //if( _pMan -> p_max + _pMan -> b_max + _pMan -> w_max >= 280 ) if( _pMan -> attach == _id ) { printf( "%d. \n", counter ); util_printMan( _pMan ); util_printMan2( _pMan ); if( _soldier_flag != 2 ) { util_cheat( _pMan, _soldier_flag ); util_printMan( _pMan ); util_printMan2( _pMan ); } counter++; } } return; } static void util_cheat( struct nb6man *_pMan, int _soldier_flag ) { int saber = _pMan -> soldier_type & SABER; int rider = ( _pMan -> soldier_type & RIDER ) >> 3; int gunner = ( _pMan -> soldier_type & GUNNER ) >> 6; if( ( RATIO * 2000 ) > _pMan -> p_real ) { _pMan -> p_real = 2000 * RATIO; } else if ( _pMan -> p_real > 1950 ) { _pMan -> p_real = 2000; } if( ( 2000 * RATIO ) > _pMan -> b_real ) { _pMan -> b_real = 2000 * RATIO; } else if( _pMan -> b_real > 1950 ) { _pMan -> b_real = 2000; } if( ( 2000 * RATIO ) > _pMan -> w_real ) { _pMan -> w_real = 2000 * RATIO; } else if( _pMan -> w_real > 1950 ) { _pMan -> w_real = 2000; } if( _pMan -> merit >= 900 ) { _pMan -> soldier = 100; } else if( _pMan -> merit >= 600 ) { _pMan -> soldier = 75; } else if( _pMan -> merit >= 350 ) { _pMan -> soldier = 55; } else if( _pMan -> merit >= 150 ) { _pMan -> soldier = 40; } else { _pMan -> soldier = 30; } if( _soldier_flag == 1 ) { _pMan -> loyalty = 100; _pMan -> training = 200; _pMan -> solloyal = 100; if( _pMan -> soldier_type & 0x2000 ) { _pMan -> form = 3; } else if( gunner >= saber && gunner >= rider ) { _pMan -> form = 2; } else if( rider >= saber ) { _pMan -> form = 1; } else { if( saber <= 2 ) { _pMan -> form = 2; } else { _pMan -> form = 0; } } _pMan -> soldier_type = _pMan -> soldier_type | 0x5000; } return; } static void util_printMan( struct nb6man *_pMan ) { if( _pMan -> dummy != 0xFFFF ) { printf( "Error!!\n" ); return; } printf( "%d/%d ", _pMan -> p_real * _pMan -> p_max / 1000, _pMan -> p_max * 2 ); printf( "%d/%d ", _pMan -> b_real * _pMan -> b_max / 1000, _pMan -> b_max * 2 ); printf( "%d/%d ", _pMan -> w_real * _pMan -> w_max / 1000, _pMan -> w_max * 2 ); printf( "%d %d %d ", _pMan -> charming, _pMan -> ambition, _pMan -> loyalty ); printf( "%d %d %d ", _pMan -> soldier, _pMan -> training, _pMan -> solloyal ); if( _pMan -> aptitude % 4 == 0 ) { printf( "C" ); } else if ( _pMan -> aptitude % 4 == 1 ) { printf( "B" ); } else { printf( "A" ); } if( ( _pMan -> aptitude / 4 ) % 4 == 0 ) { printf( "C" ); } else if ( ( _pMan -> aptitude / 4 ) % 4 == 1 ) { printf( "B" ); } else { printf( "A" ); } if( ( _pMan -> aptitude / 16 ) % 4 == 0 ) { printf( "C" ); } else if ( ( _pMan -> aptitude / 16 ) % 4 == 1 ) { printf( "B" ); } else { printf( "A" ); } printf( " " ); printf( "%d%d%d%d ", _pMan -> soldier_type & SABER, ( _pMan -> soldier_type & RIDER ) >> 3, ( _pMan -> soldier_type & GUNNER ) >> 6, ( _pMan -> soldier_type & NAVI ) >> 9 ); printf( "\n" ); return; } static void util_printMan2( struct nb6man *_pMan ) { unsigned char *_pPtr = (char *)_pMan; int i = 0; for( i = 0 ; i < 47 ; i++ ) { printf( "%02X ", _pPtr[i] ); } printf( "\n" ); return; } static long util_getFdSize( int fd ) { struct stat statbuf; if( fstat( fd, &statbuf ) < 0 ) { close( fd ); return -1; } return statbuf.st_size; } static void util_forAllCastle( char *_pFile, short _id, int _max ) { char *_pCastleStart = NULL; struct nb6castle *_pCastle = NULL; struct nb6castlemax *_pCastleMax = NULL; int i = 0, counter = 1; //_pCastleStart = _pFile + 0x9705; _pCastleStart = _pFile + 0x91F6; for( i = 0 ; i < 214 ; i++ ) { _pCastle = ( struct nb6castle * )( _pCastleStart + ( i * 33 ) ); _pCastleMax = ( struct nb6castlemax * )( _pCastleStart + ( 33 * 214 ) + ( i * 8 ) ); if( _pCastle -> id == _id ) { printf( "%d.\n", counter ); if( _max == 2 ) { util_printCastle( _pCastle, _pCastleMax ); } if( _max == 1 ) { _pCastleMax -> farm = 0xFF; _pCastleMax -> bussiness = 0xFF; } util_cheat_castle( _pCastle, _pCastleMax ); counter++; } } return; } static void util_cheat_castle( struct nb6castle *_pCastle, struct nb6castlemax *_pCastleMax ) { _pCastle -> farm = _pCastleMax -> farm * 10; _pCastle -> bussiness = _pCastleMax -> bussiness; _pCastle -> hp = 250; _pCastle -> loyalty = 100; if( _pCastle -> soldier < 500 ) { _pCastle -> soldier = 500; } return; } static void util_printCastle( struct nb6castle *_pCastle, struct nb6castlemax *_pCastleMax ) { printf( "%d/%d ", _pCastle -> farm, ( _pCastleMax -> farm * 10 ) ); printf( "%d/%d ", _pCastle -> bussiness, _pCastleMax -> bussiness ); printf( "%d %d ", _pCastle -> hp, _pCastle -> loyalty ); printf( "%d(%d)", _pCastle -> men + _pCastle -> soldier, _pCastle -> soldier ); printf( "\n" ); return; } static void util_find_man( char *_pFile, int _a1, int _a2, int _a3 ) { char *_pManStart = NULL; struct nb6man *_pMan = NULL; int i = 0; _pManStart = _pFile + 0x0AE6; for( i = 0 ; i < 500 ; i++ ) { _pMan = ( struct nb6man * )( _pManStart + ( i * 47 ) ); if( _pMan -> p_max == _a1 && _pMan -> b_max == _a2 && _pMan -> w_max == _a3 ) { printf( "country code: %d\n", _pMan -> attach ); printf( "army group code: %d\n", _pMan -> gundan ); } } return; } static void util_find_man_cheat( char *_pFile, int _a1, int _a2, int _a3 ) { char *_pManStart = NULL; struct nb6man *_pMan = NULL; int i = 0; char input[20]; unsigned char value1 = 0; unsigned short value2 = 0, tmp = 0; _pManStart = _pFile + 0x0AE6; for( i = 0 ; i < 500 ; i++ ) { _pMan = ( struct nb6man * )( _pManStart + ( i * 47 ) ); if( _pMan -> p_max == _a1 && _pMan -> b_max == _a2 && _pMan -> w_max == _a3 ) { printf( "Please enter the politic ability (max:200): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) < 201 ) { value1 = atoi( input ) / 2; _pMan -> p_max = value1; } printf( "Please enter the politic exp (max:2000): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) <= 2000 ) { value2 = atoi( input ); _pMan -> p_real = value2; } printf( "Please enter the battle ability (max:200): "); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) < 201 ) { value1 = atoi( input ) / 2; _pMan -> b_max = value1; } printf( "Please enter the battle exp (max:2000): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) <= 2000 ) { value2 = atoi( input ); _pMan -> b_real = value2; } printf( "Please enter the wisdom ability (max:200): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) < 201 ) { value1 = atoi( input ) / 2; _pMan -> w_max = value1; } printf( "Please enter the wisdom exp (max:2000): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) <= 2000 ) { value2 = atoi( input ); _pMan -> w_real = value2; } printf( "Please enter charming (%d, max:200): ", _pMan -> charming ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) <= 200 ) { value1 = atoi( input ); _pMan -> charming = value1; } printf( "Please enter ambition (%d, max:200): ", _pMan -> ambition ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) > 0 && atoi( input ) <= 200 ) { value1 = atoi( input ); _pMan -> ambition = value1; } printf( "Please enter tech (0x%02X, max:255): ", _pMan -> tech ); memset( input, 0, 20 ); fgets( input, 20, stdin ); if( atoi( input ) >= 0 && atoi( input ) <= 255 ) { value1 = atoi( input ); _pMan -> tech = value1; } printf( "Please enter soldier type ([1|0]xxxx): " ); memset( input, 0, 20 ); fgets( input, 20, stdin ); _pMan -> soldier_type = 0; if( input[0] == '1' ) { _pMan -> soldier_type += 8192; } _pMan -> soldier_type += ( input[1] - 48 ) * 1; _pMan -> soldier_type += ( input[2] - 48 ) * 8; _pMan -> soldier_type += ( input[3] - 48 ) * 64; _pMan -> soldier_type += ( input[4] - 48 ) * 512; _pMan -> option1 = _pMan -> option1 | 0x3F; } } return; } \n" );
留言
張貼留言