当前位置:文档之家› 修改游戏存档

修改游戏存档

修改游戏存档
修改游戏存档

本文旨在说明修改游戏存档的思路、编程方法和一点技巧,并无其他不良企图。如果仅仅为了修改游戏,FPE、金山游侠等更为专业。

前言

大多数程序员都玩过游戏,也或曾想过修改游戏,笔者也不例外。我通常不希望自己受困于游戏中的经验值、金钱之类的,于是采用修改游戏存档文件的方法,自己动手修改比起使用金山游侠等更有乐趣。毕竟有时候只要享受一下游戏的情节就够了,把大量的时间花费在增加经验值、赚钱方面太不合算了,毕竟时间有限而游戏无限!方法嘛,使用老牌的UltraEdit(以下简称UE),当然还需要配合“计算器”进行十进制和十六进制的转换。时间长了,也觉得繁琐,何不自己动手写一个针对游戏存档文件的修改器而一劳永逸?笔者比较喜欢C++,如果你有一定的C++基础,跟我走吧!

笔者的电脑:AMD XP1700+,Windows2000(sp4),Borland C++ Builder 6(sp4)

手工修改游戏存档文件的方法

游戏存档文件大多使用二进制格式,这样对于读取和保存数据都比较方便。可使用Windows的“计算器”来看看10进制和16进制的区别:采用“科学性”模式,在10进制模式下输入数据,然后切换到16进制就行了。

不过就算这样转换,看起来还是不很直观,因为在游戏存档中并不是如此显示的。

那么用C++如何表达的呢?下面这个小程序演示了如何读写二进制整数。

#include <iostream>

#include <fstream>

using namespace std;//标准库所在的空间

int main()

{

fstream BinFile("test.txt",ios::in | ios::out | ios::binary);//读+写+二进制模式

int i=1234;

BinFile.write(reinterpret_cast<const char*>(&i),sizeof(int));

//reinterpret_cast是C++的强制转换,这里把整数的地址强制转换为const char*,

//与C 的(const char*)&i 作用相同,但是reinterpret_cast更加含义明确。

i=0;

BinFile.seekg(0,ios::beg);//重新指向文件开头准备读取

BinFile.read(reinterpret_cast<char*>(&i),sizeof(int));

cout<<"i="<<i<<’\n’;

}

用UE打开test.txt切换到二进制模式,是这样子的:

在计算器中看到的是04D2,在UE 中看到的是D204,这就是笔者所谓的不直观性。因此,如果你要在某个游戏存档文件中间(扩充开来就是二进制文件)寻找04D2这个数值,找到上图显示的地方就对了。笔者初期手工修改存档也是这样的,比较麻烦。

下面这个小程序表明了模拟UE在二进制文件中寻

找整数的原理:

#include <iostream>

#include <fstream>

using namespace std;

int main()

{

fstream BinFile("test.txt",ios::in | ios::out | ios::binary);//读+写+二进制模式

const int i=87654;

BinFile.write(reinterpret_cast<const char*>(&i),

sizeof(int));//强制转换,把i用二进制方式写入文件

BinFile.seekg(0,ios::beg);

//重新指向文件开头,准备读取

char ch;

while(BinFile.read(&ch,sizeof(char)))//读取所有字符

cout<<static_cast<int>(ch)<<"\t";//显示

//static_cast是C++的静态转换,与C的(int)ch作用相

//同,但是static_cast意思表达更清楚。

cout<<’\n’;

//下面把i的地址转换为字符串地址,并用char方式依次读取,主要是比较两者读取的结果是否相同.

const char* P=reinterpret_cast<const char*>(&i);

for(int i=0;i<sizeof(int);++i)

cout<<static_cast<int>(P[i])<<"\t";

}

用C++制作自己的游戏修改器(上b)vc++ 2007-11-29 16:27:05 阅读13 评论0 字号:大中小

手工在存档文件中使用UE中来查找某个数值的时候,可能找到好多地方,靠一个一个查找然后记录下地址可真费眼神。写个程序来自动寻找指定的数值,并且记录下地址吧!本文所述的地址都是从0开始的,而且都以十进制方式输入输出。

template<class T>

class CheckBinaryFile

{

public:

typedef fstream::off_type AddressType;

CheckBinaryFile();

void Run();

private:

static const int MaxByte=sizeof(T);

const int CharSize;

EInputStream CIN;//我自己写的一个加强输入流string FileName;

T OldData;

int ByteNumber;

mutable bool InputIsOk;

mutable ifstream BinaryFile;

mutable list<AddressType> AddressList;

void Input();

int Check() const;

void SaveAddressToFile(ostream&) const;

void AutoModifySave(const T&) const;

};

template<class T>

const int CheckBinaryFile<T>::MaxByte;//定义静态整型常量

这是自己定义的一个类,下面逐一解释:

template<class T>

T代表要寻找的数据的类型。当然,这个程序只是寻找整数(经验值、金钱都是整数!),但我不排除以后要查找其他类型的数据。为了可扩充性,使用了模板。

typedef fstream::off_type AddressType;

我要找到数据在文件中总有地址,这个地址是什么类型呢? int还是long,或者是其他类型?fstream有一个类型叫off_type,应该是偏移类型的含义,在这里我把这个类型叫做AddressType。

static const int MaxByte=sizeof(T);

这是一个静态整型常量,表示T的大小(最多有多少字节),比如在我的机器上,sizeof(int)=4。T的大小在编译的时候就确定,而且它不能被修改(const),对于所有查找类型相同的CheckBinaryFile,这个数值是唯一的,共享的(static)。

构造函数:

template<class T>

CheckBinaryFile<T>::CheckBinaryFile():CharSize(sizeof (char)),CIN(cin)

{ InputIsOk=true; Input(); }

CharSize 为sizeof(char),把cin 绑定到CIN。由于CharSize是常量,必须在构造函数的初始化列表中设定。

预设输入状态,调用输入函数:

template<class T>

void CheckBinaryFile<T>::Input()

{

cout<<"Binary file name:\t";

CIN>>FileName;

BinaryFile.open(FileName.c_str(),ios::in | ios::binary);

if(!BinaryFile){

InputIsOk=false;

cerr<<"Open file failed.\n";

return;

}

cout<<"The integer you want to search:\t";

CIN>>OldData;

cout<<"Byte number(1--"<<CheckBinaryFile<T>::MaxByte<<"):\t";

CIN>>ByteNumber;

if(ByteNumber<1 || ByteNumber>CheckBinaryFile<T>::MaxByte) {

//字节数错误,调整为最大值

ByteNumber=CheckBinaryFile<T>::MaxByte;

cout<<"Byte number was amended to " << CheckBinaryFile<T>::ByteNumber <<’\n’;

}

}

提示用户输入二进制存档文件,用只读+二进制模式开启。如果失败,设置输入状态为

false,直接退出。然后提示用户输入要查找的整数(OldData)以及多少个字节(ByteNumber)。如果字节数错误,调整为最大值。由于计算机系统的不同以及char,short,int,long之间存在

转换关系,对于某些整型的字节数是不可确定的。比如100,可以用char表示,那么只需要sizeof(char)个字节表示就够了,当然也可以用字节数更多的类型,比如int,来表示100。

template<class T>

int CheckBinaryFile<T>::Check() const{

const char* P=reinterpret_cast<const char*>(&OldData);

char Range[CheckBinaryFile<T>::MaxByte];

int Occurs=0;

AddressType Addr=0;

//填充0

memset(Range,0,CheckBinaryFile<T>::MaxByte*CharSize);

BinaryFile.read(Range,CharSize*ByteNumber);//填满Range

while(BinaryFile){

if(memcmp(P,Range,CharSize*ByteNumber)==0){//匹配成功

AddressList.push_back(Addr);

++Occurs;

}

//删除一个最旧的

memcpy(Range,&Range[1],CharSize*(ByteNumber-1));

//读入一个新的

BinaryFile.read(&Range[ByteNumber-1],CharSize);

++Addr;

}

return Occurs;

}

检查输入的二进制文件中有多少个OldData,并保存地址,用模拟二进制方式比较OldData。Range 是一个比较区域,这里不打算输出这个字符串,也不考虑用strcpy来拷贝内容,所以不必预留一个空间来保存结尾符号’\0’。填满Range 后,开始一个一个字符比较了:

当Range和OldData完全相同就表示匹配成功(memcmp返回0 表示成功),一旦成功,就把该地址保存下来(AddressList)。不管是否成功,把Range去掉一个最早读取的,然后读入一个新的,继续匹配。函数返回匹配的个数。

用C++制作自己的游戏修改器(上c)vc++ 2007-11-29 16:28:28 阅读7 评论0 字号:大中小list是标准C++的一个容器,类似双向链表,在添加/删除节点方面表现优秀。我不打算使用排序,因为从头到尾遍历文件时保存下来的地址肯定是有序的;我也不需要随机读取这些地址,所以排除了vector以及deque这两种容器。至于没有采用内建的数组,咳,我不

知道能找到多少地址,或许一个都没有,或许成千上万。

list有一个size()函数,望文生义就是大小的意思,的确如此。不过由于list是一种链表,不像数组那样只要把头尾指针相减就能得到大小,取得size的办法只有从头到尾走一遍,速度比较慢。既然这个函数很清楚取得了多少个地址,那就直接返回这个数目吧!

template<class T>

void CheckBinaryFile<T>::Run()

{

if(InputIsOk==false) return;

const int Occurs=Check();

cout<<Occurs<<" different addresses were found.\n";

if(Occurs==0) return;

cout<<"Save address info to files(y/n)?\t";

char YN;

CIN>>YN;

if(YN==’y’ || YN==’Y’){

cout<<"Address file name:\t";

string AddressFileName;

CIN>>AddressFileName;

ofstream Save(AddressFileName.c_str(),ios::out);

if(!Save)

{ cerr<<"Create "<<AddressFileName<<" failed.\n";}

else

{ SaveAddressToFile(Save);

Save.close();

}

}

cout<<"Modify binary file automatically(y/n)?\t";

CIN>>YN;

if(YN==’y’ || YN==’Y’){

cout<<"New value:\t";

T NewValue;

CIN>>NewValue;

system("dir > @tmp");

system("del @*/q");

AutoModifySave(NewValue);

}

}

如果输入错误,则直接退出。显示匹配的个数并询问是否保存这些地址至文件。再询问是否自动修改。比如找到了10个地址,自动修改将产生10个新文件,每个文件与原文件相比都只修改了一个地址的数值。输入新的数值,将产生若干个新文件。新文件的格式是@+地址的十进制表示。产生新文件前先把旧的以@开头的文件删除。如果不存在@开头的文件,system("del @*/q");会说找不到文件,不大舒服,那我先制造一个@tmp(system("dir >@tmp");),这里使用了DOS的输出重定向,把原本显示到屏幕的内容输入到@tmp中。

template<class T>

void CheckBinaryFile<T>::SaveAddressToFile(ostream& os)

const

{

copy(AddressList.begin(),AddressList.end(),

ostream_iterator<T>(os,"\t"));

}

把AddressList的内容保存下来。copy是C++的函数,把一个区间的内容拷贝到另一个地方。

template<class T>

void CheckBinaryFile<T>::AutoModifySave(const T& NewValue)

const

{

list<AddressType>::const_iterator Beg=AddressList.

begin(),End=AddressList.end();

const char* P=reinterpret_cast<const char*>(&NewValue);

for(;Beg!=End;++Beg){

BinaryFile.clear();//清除错误状态

BinaryFile.seekg(0,ios::beg);//指向文件开头,准备读 AddressType Addr=0;

char ch;

stringstream NewFile;

NewFile<<"@"<<*Beg;

string NewFileName(NewFile.str());

ofstream Write(NewFileName.c_str(),ios::out | ios:: binary);

if(!Write){

cerr<<NewFileName<<" ... unsuccessfully.\n";

continue;

}

while(Addr < *Beg && BinaryFile){

//小于指定地址的内容

BinaryFile.read(&ch,CharSize);

Write.write(&ch,CharSize);

++Addr;

}

for(int k=0;k<ByteNumber;++k){//忽略源文件

BinaryFile.read(&ch,CharSize);

}

Write.write(P,CharSize*ByteNumber); //写入新值

while(BinaryFile){//源文件剩余的内容拷贝到新文件

BinaryFile.read(&ch,CharSize);

Write.write(&ch,CharSize);

}

Write.close();

cout<<NewFileName<<" ... successfully.\n";

}//for

}

根据AddressList的大小遍历若干遍源文件。新的文件用@+地址格式。先把小于指定地址的内容拷贝到新文件,到了指定地址后把新值写入新文件,再把源文件剩余的内容拷贝到新文件。const_iterator是常量迭代器,表明不修改AddressList 的内容。begin 函数得到AddressList的开头,end函数得到AddressList的最后一个元素的下一个地址,++表示迭代器前进一格。把源文件剩余的内容拷贝到新文件后,会导致源文件BinaryFile 的状态为bad,在bad状态下要执行比如读写、重新指向文件某个位置等操作必须先调用clear清除这个状态。

mutable是C++新近的关键字,大体意思是表明该内容可以在const成员函数中修改。比

如在这个类中间,比如mutable bool InputIsOk;InputIsOk只是表明用户输入数据的正确性,并不影响自身的状态; mutable list<AddressType> AddressList;也没有改动源文件的各个属性,只是保存了信息。

好了,这个类基本写完了。他的功能是:

输入一个二进制文件名以及要查找的整数和字节数。

告诉你找到了多少个地址(可保存地址信息到文件),如果你愿意,可以分别把这些地址上的数据修改为新的数值后产生新文件。

你可以在仙剑2上做实验。仙剑2的存档地址不是固定的。记录下当前的经验值和金钱(都是4字节),存档后切换到Windows,对存档的文件开刀,如果报告找到的地址只有四五个,可以自动产生新文件。把新文件覆盖原存档,切换到游戏后读取刚刚修改的文件试试看。大不了直接退出游戏。仙剑2 可以直接切换到Windows,这对于修改存档比较方便。我以前老老实实玩到底才32级,现在可以一下子飙升到七八十级(最高好像是99),我以前不知道苏媚还有“狐舞动天”的绝技,嗬嗬!

用C++制作自己的游戏修改器(上d)vc++ 2007-11-29 16:30:12 阅读4 评论0 字号:大中小应该说有些游戏的存档还是很老实的——地址不变。

对于这种类型的存档,我们可以用对集合取交集的方法来缩小范围。比如经验值为4的时候存档为A,经验值为7 的时候存档为B。对A用上面的工具查找4,保存地址信息为4.txt;对B用上面的工具查找7,保存地址信息为7.txt。把4.txt和7.txt的内容看作两个集合,如果地

址不变,那么取得两者的交集就能大大缩小查找范围。

嗯,仙剑2 不行,仙剑1 和3倒是可以的。

对于集合的个数,至少两个,可以对多个集合取交集。C++提供了set_intersection函数,可以对两个有序区间进行交集运算,我们只需要不断重复这个过程,就能对多个集合执行交集运算了。

约定:输入若干个集合文件进行交集元算,当输入一个不存在的文件表示结束输入。当程序发现取得空集的时候就自动结束。

template<class T>

void GetIntersection()

{

EInputStream CIN(cin);

cout<<"Input some text filenames for reading,end

with a nonexistent one.\n";

string fn;

CIN>>fn;

ifstream Read(fn.c_str());

if(!Read){

cerr<<"Open "<<fn<<" failed.\n";

return;

}

vector<T> V1;

copy(istream_iterator<T>(Read),istream_iterator<T>(),back_inserter(V1));//保存file1的内容到V1

CIN>>fn;

Read.clear();

Read.close();

Read.open(fn.c_str());

if(!Read){

cerr<<"Open "<<fn<<" failed.\n";

return;

}

vector<T> V2,V3;

copy(istream_iterator<T>(Read),istream_iterator<T>(),back_inserter(V2));//保存file2的内容到V2

sort(V1.begin(),V1.end());//排序

//删除重复的数据

V1.erase(unique(V1.begin(),V1.end()),V1.end());

sort(V2.begin(),V2.end());

V2.erase(unique(V2.begin(),V2.end()),V2.end());

set_intersection(V1.begin(),V1.end(),V2.begin(),

V2.end(),back_inserter(V3));//V3=V1和V2的交集

while(V3.empty()==false){

//如果是空集就可以退出了

CIN>>fn;

Read.clear();

Read.close();

Read.open(fn.c_str());

if(!Read) break;

vector<T>().swap(V1);//清除V1

copy(istream_iterator<T>(Read),

istream_iterator<T>(),back_inserter(V1));

sort(V1.begin(),V1.end());

V1.erase(unique(V1.begin(),V1.end()),V1.end());

V2.swap(V3);//V2和V3交换

vector<T>().swap(V3);//清除V3

set_intersection(V1.begin(),V1.end(),

V2.begin(),V2.end(),back_inserter(V3));

}

if(V3.empty()){

cout<<"An empty aggregate was found after reading " <<fn<<".\n";

return;

}

cout<<V3.size()<<" value were enumerated.\n";

cout<<"Input save filename:\t";

CIN>>fn;

ofstream Dest(fn.c_str());

if(!Dest){

cerr<<"Create "<<fn<<" failed.\n";

}

else{

copy(V3.begin(),V3.end(),ostream_iterator<T>(Dest,"\t"));

Dest.close();

}

}

下面逐一解释:

template<class T>

和上一例含义一样,在此代表集合元素的类别。我可以对整数集合进行交集元算,对小数、字符串组成的集合也能进行交集元算。当然我现在只用到了整数集合。

CIN是我自己的一个加强类,你可以看作cin。

首先打开两个指定的文件(做交集运算至少要两个集合),如果有一个失败就退出。把这两个文件的内容分别放入V1 和V2。然后对V1 和V2 排序(sort),剔除重复内容(unique和erase)。对调整过的V1 和V2 执行交集,结果保存到V3。

当V3不为空集的时候开始循环:读取下一个等待输入的文件。清空V1,把新的文件内容放入V1,把V3的内容拷贝到V2,清空V3,把V1 和V2 的交集放入V3。

上述“把V3的内容拷贝到V2”只是表达一个意思,实际上只是把V3 和V2 做交换而已,因为V3我需要清空,并不需要真正的拷贝。把某个集合清空,只是和临时的空集做交换而已。

这里我使用vector容器,set也是可以的。使用set的好处是可以自动排序和剔除重复内容,当然自动排序和保持元素的唯一性是需要代价的。使用vector的好处是等到所有输入完毕后,执行某些函数(比如sort,unique,erase)来完成上述功能,一次性达到目的,而

不像set那样任何时刻都保持元素的有序性和唯一性。

当数据量比较大的时候,vector或许要高效一些。当然,主观臆断不是科学精神,实践是最好的检验手段。我在这里只是随便选取了vector。一旦选择了vector,那么“清除所有内容”最好使用“与空的临时vector交换”,采用这种方法后,vector的容量也会变得尽可能的小;而如果采用clear 的方法,容量保持不变。因为vector内部也采用数组,数组就意味着一块连续的内存,一旦需求超出了容量会导致重新分配,所以vector会采用预留一部分空间的策略,避免每次增加元素都要重新分配。而set不一样,底层采用二叉树(sgi采用更严格的

红黑树),不需要预留空间,要多少分配多少,对它进行清空操作只需要简单的执行clear 即可,当然,和空的临时集合作交换也很好。临时变量一旦离开自己的生存期就会释放自身的资源。

拿仙剑3举例,比如有24文钱的时候存档为pal01.arc。有60文钱时存档为pal02.arc。退出游戏(如果你有两台电脑组成网,可以不退出游戏在另外一台电脑上修改),把pal01.arc,pal02.arc和这个程序放在一起,对pal01.arc查找4 字节的24,保存地址为24.txt;对 pal02.arc 查找4 字节的60,保存地址为60.txt。然后对24.txt和60.txt做交集。仙剑3的金钱存档有两个,一个是表象,方便读取存档,另一个才是真正的存放金钱的地址。所以交集结果应该为2个。知道了真正的地址,对于自动产生的文件就可以有的放矢的选择了。

手机游戏存档地址

在上篇中,我介绍了存档修改的一些基础知识,本篇将进入实战阶段,主要介绍如何判断存档文件、存档文件的类型、最简单的定位数据方法。 一、判断存档文件 通过iTools打开一个游戏的Documents目录时,我们往往会看到一堆文件,如何确定哪些是我们需要改的文件呢,这些存档文件每个游戏都可能不同,所以,并没有绝对的方法来确定哪些是我们需要的存档文件,判断主要依靠两个要素:经验和耐心,经验可以帮助你更快定位文件,但如果没成功,就只能靠耐心一个个的尝试,下面将通过一些游戏进行实例分析: 这是Asphalt6赛车游戏的存档,通过文件名我们可以看到有四个扩展名为.sav的文件,因为“保存”的英文就是“Save”,所以,我的第一感觉就是我需要改的是这四个中的一个或几

个,通过文件名可以看出serverConfig.sav是一个配置信息,trophy.sav是战利品存储信息,profileInit.sav的文件名中带了一个init(即初始化的意思),所以,最终我把目标定在了profile1.sav这个文件上,实事证明,就是它了。另外,还有一个叫profile1.bak的文件,通过比较发现,它的内容和profile1.sav一模一样,所以,在改了profile1.sav以后,我也同步改了profile1.bak这个文件。 这个是枪火兄弟连的存档,它的这些文件都以数字命名,无法一眼看出哪个才是我们需要的存档,这种情况下,我们只能全部复制出来通过搜索数据的方式来判断(如何搜索数据后面会讲到),幸运的是,只试了第一个就成了,也就是XXXXX_1000的这个文件,当然,有些时候可能得多试几个才能定位。

魔兽RPG游戏--怪物大师--存档代码

用户名:bluecoffee 雪人 -load a%eRYC-3KUu0S-aXa&6K-6hen6K-ayeag!-c7i6e7-eB9lca-z6YDO4 猛犸1 -load a%eTYC-3oFuCD-aXa&6K-6hen6K-ayeag!-c7i6e7-eB9lca-zDZDVe 猛犸+野人行者6 -load ayeTYC-6oFhCD-aaaa6K-6hen6K-aae%g!-a@iaC7-eB9lca-wXUD8% 猛犸25级+野人行者+大地守卫 -load ayeTYC-7JN7CD-aJaK6n-6heK6K-aae%g!-a@iaC7-e9Zlca-zGnm@x 野兽行者融合18 大地守卫30级 -load ayeTYC-68WRCD-aJaK6n-6heK6K-aae%g!-a@iaC7-Pftlca-B3sRZd 野兽行者融合18 大地守卫融合17 -load ayeTYC-68FRCC-aJaK6n-6heK6K-aae%g!-a@iaC7-Pftlca-BBoRf! 野兽行者30级融合18 大地守卫30级融合17 -load ay6%YC-cJWRRC-aKaK6K-60eK6K-6Teag!-c7!Re7-4PYlca-BriCSa 野兽行者30级融合18 狗头人法师融合20 -load ay6%Yb-cJFRRw-aKaK6K-60eK6K-6Teag!-c7!Re7-4PYlca-Bs1CSJ 巨人融合25 狗头人法师融合20 -load 6@6%Yb-6KMARw-aK646K-60ei6K-6Teag!-c7!Re7-43Zlca-BXOCkd 猛犸融合30 天堂鸟融合11 -load aDeTen-wH&h5D-6PaK6i-6JeK6M-6@e%Pw-cJvACF-eF?2ca-w%jD!y 猛犸30级融合30 ,美杜莎30级融合9 天堂鸟29级融合17 -load a&eTen-c8&75C-6PaM6i-6JYP6X-6@e%Pw-cJvACF-Yne2ca-3?ToM? 猛犸6级融合36 ,美杜莎6级融合15 天堂鸟29级融合17 -load a&eTen-PR&orC-6PaM6i-6JYP6X-6@e%Pw-cJvACF-Yn92ca-337onR 猛犸21级融合36 ,美杜莎21级融合15 天堂鸟30级融合17 -load a&6%en-28WoRC-6PaM6a-atYP6X-6@YTPw-cFvAsF-gcm2ca-Ae70QY 猛犸27级融合36 ,美杜莎27级融合15 阿拉克阿21级融合23 -load a&e@Y3-BoToGA-6PaM6a-ateM6X-aaYTPw-aqvasF-gLs2ca-3Kb0oo

《手机游戏存档修改通用教程1 - 基础篇》

之前发过一些修改游戏存档的帖子,大家都这个都比较感兴趣,但一直以来,大家都是照着教程一步步去修改,很多时候并不明白为什么要这样改、发贴人是怎么知道改哪个地方的?正所谓“授人以鱼不如授人以渔”,如果你有兴趣又有耐心的话,请继续往下看,教程里会有你想要的答案,这些方法不仅仅对于手机游戏的存档,对电脑单机游戏的存档同样适用。 10几年前刚开始学电脑时,为了学好十六进制的转换和电脑存储数据的方式,用修改游戏做试验,从当年DOS下的仙剑一代、命令与征服改到现在的手机游戏,其实本质上并没有什么区别,嗯。。。。一不小心又扯远了,勿怪勿怪。。。开始吧! 本篇主要介绍一些基础知识和常用工具,只有基础牢了,改起游戏来才会更加得心应手,虽然我写得很细,但你只要基本了解就行了,在改游戏的过程中再慢慢体会。 一、十六进制基本概念 先了解一下什么是十六进制,在日常生活中我们用得最多的就是十进制,也就是从0-9这10个数字,9再加1就变成了10,这就叫进位,而十六进制则不同,它有16个符号,分别是:0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F,A-F分别对应十进制下的10-15,F再加1就变成了十六进制的10(这个不读”拾”,直接读“幺零”),十六进制的10表示十进制下的16。 通常情况下,在我们用工具打开存档文件时,看到的都是十六进制代码,不管是查找或者修改数据,一般都是采用十六进制的方式,比如像下面这个“枪火兄弟连”的存档,打开后看到的就是十六进制数据:

二、十六进制的转换 为什么要转换呢?举个例子,“枪火兄弟连”游戏中现在显示有1000金币,这个时候,我想在存档中找到存储金币的位置,就需要把1000转成十六进制表示形式,再去存档中进行搜索。幸运的是,十六进制的转换现在非常简单,打开电脑上的“计算器”,如下:

极品飞车17存档位置解析

极品飞车17存档位置解析 很多玩家都遇到安装了游戏却不知道极品飞车17存档位置在哪里的这种情况,存档一般会放在系统盘的用户文件夹里面,不过有些游戏也会放在游戏的安装目录下,所以仔细找找还是可以找到的。 极品飞车17存档位置详解 win7系统 C:\Users\用户名\Documents\Criterion Games\Need For Speed(TM) Most Wanted\Save 如果没有找到存档,在计算机的“搜索”里面搜索“save”也是个不错的办法。 以上就是小编关于极品飞车17存档位置解析的详细说明了,希望可以帮到玩家们,也祝玩家们游戏开心。 《极品飞车17》easydrive菜单跳动怎么解决有些玩家在用手柄玩极品飞车17的时候,打开easydrive菜单,会出现上下抖动的情况。手柄设置正常,重新开了几次游戏都是这样,到后来拔了手柄用键盘也这样,怎么回事?

【极品飞车17easydrive菜单跳动解决方案】 1、你需要先去我的文档里有个Citerion game的文件夹里面有个save文件夹把control。。。的个文件删掉 2、进入游戏设置键位,.这里只需要将easy drive的四个键设置键盘位置我用的是I J K L 3、设置手柄按键注意手柄里的easy drive的就不要设置了 4、需要easy drive菜单的话就用键盘按键好了 以上就是小编关于《极品飞车17》easydrive菜单跳动解决方法详解的详细说明了,希望可以帮到玩家们,也祝玩家们游戏开心。 极品飞车17:最高通缉热力追踪攻略不少玩家们都在问极品飞车17:最高通缉热力追踪攻略有哪些?今天小编就和玩家们说说极品飞车17:最高通缉热力追踪技巧详解,感兴趣的一起来看看。

修改游戏存档

本文旨在说明修改游戏存档的思路、编程方法和一点技巧,并无其他不良企图。如果仅仅为了修改游戏,FPE、金山游侠等更为专业。 前言 大多数程序员都玩过游戏,也或曾想过修改游戏,笔者也不例外。我通常不希望自己受困于游戏中的经验值、金钱之类的,于是采用修改游戏存档文件的方法,自己动手修改比起使用金山游侠等更有乐趣。毕竟有时候只要享受一下游戏的情节就够了,把大量的时间花费在增加经验值、赚钱方面太不合算了,毕竟时间有限而游戏无限!方法嘛,使用老牌的UltraEdit(以下简称UE),当然还需要配合“计算器”进行十进制和十六进制的转换。时间长了,也觉得繁琐,何不自己动手写一个针对游戏存档文件的修改器而一劳永逸?笔者比较喜欢C++,如果你有一定的C++基础,跟我走吧! 笔者的电脑:AMD XP1700+,Windows2000(sp4),Borland C++ Builder 6(sp4) 手工修改游戏存档文件的方法 游戏存档文件大多使用二进制格式,这样对于读取和保存数据都比较方便。可使用Windows的“计算器”来看看10进制和16进制的区别:采用“科学性”模式,在10进制模式下输入数据,然后切换到16进制就行了。 不过就算这样转换,看起来还是不很直观,因为在游戏存档中并不是如此显示的。 那么用C++如何表达的呢?下面这个小程序演示了如何读写二进制整数。 #include <iostream> #include <fstream> using namespace std;//标准库所在的空间 int main()

{ fstream BinFile("test.txt",ios::in | ios::out | ios::binary);//读+写+二进制模式 int i=1234; BinFile.write(reinterpret_cast<const char*>(&i),sizeof(int)); //reinterpret_cast是C++的强制转换,这里把整数的地址强制转换为const char*, //与C 的(const char*)&i 作用相同,但是reinterpret_cast更加含义明确。 i=0; BinFile.seekg(0,ios::beg);//重新指向文件开头准备读取 BinFile.read(reinterpret_cast<char*>(&i),sizeof(int)); cout<<"i="<<i<<’\n’; } 用UE打开test.txt切换到二进制模式,是这样子的: 在计算器中看到的是04D2,在UE 中看到的是D204,这就是笔者所谓的不直观性。因此,如果你要在某个游戏存档文件中间(扩充开来就是二进制文件)寻找04D2这个数值,找到上图显示的地方就对了。笔者初期手工修改存档也是这样的,比较麻烦。 下面这个小程序表明了模拟UE在二进制文件中寻 找整数的原理: #include <iostream> #include <fstream> using namespace std; int main() {

《NBA2K17》怎么保存游戏进度 《NBA2K17》存档位置详解

《NBA2K17》怎么保存游戏进度《NBA2K17》存档位置 详解 《NBA2K17》将于9月20日正式上线,玩家们之前体验过的试玩版感觉如何呢?据小编所知,玩家试玩版的存档数据是可以直接保存到正式版本中的哦!这对玩家来说是不是个不小的惊喜呢~许多玩家不清楚《NBA2K17》存档位置在哪里,不用担心,老祖游戏小编马上为大家分享《NBA2K17》怎么保存游戏进度及《NBA2K17》存档位置详解,有需要的玩家来看看吧! 德拉蒙德·格林的庆祝动作 NBA2K17存档位置路径: 我们从《NBA 2K17》两个版本来介绍不同的存档路径,分别是codex破解版和国内破解版两种。 先来说一下codex破解组的存档位置: 一般来说该组的存档位置文件是在C:\Users\用户名\AppData\Roaming\Steam\CODEX\370240\文件夹下,其中“用户名”为玩家个人计算机的帐号。

当然,有时候也会在C:\Users\用户名\Documents\My Games\NBA2K17文件夹下。 而国内破解组的游戏存档文件则一般是在游戏根目录下面,比如存档位置路径X:\NBAK17\3DMGAME\storage文件夹下。 知道了存档位置路径,将需要的存档文件替换这里面的文件就可以替换存档了。 而NBA2K17游戏保存进度的方式也很简单。快速比赛是无法保存的。在生涯模式中,一般会在剧情结束开始前后,比赛开始结束前后自动保存,如果玩家在生涯比赛过程中想离开游戏,会有一个离开并保存进度的选项,玩家根据自己的需要选择是否保存即可。 做个鬼脸乐一乐 对于购买了正式版《NBA 2K17》的玩家来说,在两个地方上网体验游戏,这两台电脑能不能共享存档呢?这时玩家要注意,如果是Steam正式版本的《NBA 2K17》,是可以通过Steam 云存档来实现游戏存档异地同步的,两台电脑的游戏进度存档数据是相同,当然前提是玩家在畅玩游戏时是通过服务器连接的并保存了游戏进度。 好了,关于NBA2K17存档位置路径和保存进度方法的相关内容就先介绍到这里了,现在小伙伴们知道NBA2K17存档位置在哪了吧,没有大的变动的话应该就是这样。玩家们在游戏中有遇到其他问题也可以留言让大家帮助解决,祝大家游戏愉快!

PSP游戏存档知识讲解

以下是PSP罪恶都市故事的秘籍: Weapon Set 1 - brass knucles, knife, molatov, 9mm, rifle, SMG, AK(第一类武器) 左, 右, X, 上, 下, □, 左, 右 Weapon Set 2 - katana, remote grenades, python, shotgun, silenced uzi, m4, rockets, sniper rifle (第二类武器) 左, 右, □, 上, 下, △, 左, 右 Weapon Set 3 - chainsaw, grenades, laser scope python, shotgun, mp5, m4, minigun, sniper rifle (第三类武器) 左, 右, △, 上, 下, ○, 左, 右 Get $250000(得到250000金钱) 上, 下, 左, 右, X, X, L1, R1 Armor(防弹衣) 上, 下, 左, 右, □, □, L1, R1 Health(生命值) 上, 下, 左, 右, ○, ○, L1, R1 Raise Wanted Level(提高一级警报) 上, 右, □, □, 下, 左, ○, ○ Never Wanted(永元不会被通辑) 上, 右, △, △, 下, 左, X, X Sunny Weather(大太阳天) 左, 下, R1, L1, 右, 上, 左, ○ Clear Weather(晴朗的天气) 左, 下, R1, L1, 右, 上, 左, X Overcast Weather(阴天) 左, 下, L1, R1, 右, 上, 左, □ Rainy Weather(雨天) 左, 下, L1, R1, 右, 上, 左, △ Foggy Weather(雾天) 左, 下, △, X, 右, 上, 左, L1 获得坦克 上, L1, 下, R1, 左, L1, 右, R1

极品飞车9最高通缉游戏存档使用方法及注意事项

================================================================= ========================== **********************【切勿随意删除或修改本文档否则一切后果自负】 ********************** ================================================================= ========================== MMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM 【①】在[我的文档]内能够找到[NFS Most Wanted]文件夹 或是能够自行找到极品飞车9最高通缉的游戏存档保存路径 (以下用[我的文档\NFS Most Wanted]注明) 【②】每一个所下载的存档文件只能单独储存于一个名字相符的文件夹内 【③】如果所下载的只是一个文件,那么还需要在[我的文档\NFS Most Wanted]内建立一个文件夹 名称必须和所下载的文件名字吻合(如果你下载存档的时候有特殊说明就按说明做。然后就可以把文件放入[我的文档\NFS Most Wanted]中名字相符的文件夹内) 【④】为了保证游戏的质量与运行速度 建议在[我的文档\NFS Most Wanted]文件夹内只单独放置一个存档文件夹MMMMMMMMMMMMMMMMMMMMMM步 MMMMMMMMMMMMMMMMMMMMMM 【①】打开[我的文档\NFS Most Wanted]文件夹

【②】将所下载的文件放到名字相同的文件夹内即可 【③】进入游戏,按任意键继续之后,系统会弹出提示选择一个存档,选择你所要使用的存档名字即可 ================================================================= ========================== TYTXVXTYTXVX【 2009年12月21日08:00。DavidBelle整理编辑】 TYTXVXTYTXVX ================================================================= ==========================必须条件及注意事项 骤

PS3存档使用方法和技巧

通过FTP使用本来不能读取的别人的PS3存档 以战国BASARA3为例,先进游戏存个档,退出游戏运行PS3 FTP,电脑上转到dev_hdd0\home\0000000x\savedata下,找到你要替换的存档目录,战国BASARA3的存档编号是BLJM602180,也可以根据保存时间和里面的存档图标来判断 找到后进入这个目录,直接用别人存档里的同名文件替换即可,但要注意PARAM.SFO这个文件不要替换,这个文件就是对应别人的账号,替换了会提示你别人的存档不能读取 回到游戏运行,别人的存档就可以读取了,奖杯也可以正常取得,不过有部分游戏在重新保存时会提示存档损坏,不用管,退出存档界面再进去,再保存一次就正常了 PS3的存档目录结构 PS3的存档目录结构如下图所示 最上层是名称为PS3的文件夹,在PS3文件夹下面有一个名称为SA VEDA TA的文件夹,在SA VEDA TA文件夹下面就是游戏的数据文件夹了,比如像图上的BLJS…………这样的文件夹名称,在这个文件夹里面的数据和图像等就是一个游戏的具体数据了,如上图那样的这个游戏含有系统档和数据档两个文件夹,我们在使用的时候就要把这两个文件夹同时放在SA VEDA TA目录下面,这里的目录名称的英文字母都为半角英文字母。 在本站下载的存档一般都为RAR格式,解压后有的是PS3文件夹,有的可能直接就是存档的数据文件夹,如果是存档的数据文件夹,那么请自行手动按照上图的目录结构建立PS3和SA VEDATA文件夹。 从数据卡或者USB设备上复制存档到PS3主机 在PC上将含有存档数据的PS3文件夹复制到数据卡或USB设备里,再复制到PS3主机上 PS3 60G标准版应该配备记忆棒或者SD卡的卡槽,这样就可以将数据放在记忆棒或者SD 卡上使用 PS3 20G和40G版本应该有USB闪存接口,可以通过USB读卡器+数据卡或者直接用USB 存储设备接入使用 下面是具体的操作流程 启动PS3到主界面(XMB),依次选择【游戏】(ゲーム/GAME)→【存档管理】(セーブデータ管理/SA VEDA TA MANAGER),如果接入的数据卡或者USB设备可以识别的话,那么选取想要复制的存档按手柄的△键即可开始复制存档,同时也可以将PS3主机内的存档

相关主题
文本预览
相关文档 最新文档