前言
植物大战僵尸作为一个集趣味性和益智性为一身的经典塔防类游戏,在推出之初便收获了广泛的关注及好评。推出十年间,不断有围绕该游戏不同的攻略,不同的二创、三创作品。使得人们对该游戏的热度不减。然而,作为经典单机游戏,它的有趣性不仅体现在于其本身画面设计精美、游戏数据设计合理,还在与其有强大的可再修改性。通过修改当中完全开源的内容,玩家可以自行升高或降低难度,自行调节关卡进度,自行查看场地数据,达到了十足的可玩性。本文从最基本的关卡和金币修改出发,探究植物大战僵尸游戏中蕴藏的数据原理。
一、获取数据
使用二进制编辑器打开植物大战僵尸用户文件(一般为C:\ProgramData\PopCap Games\PlantsVsZombies\userdata\user1.dat)(如图)。
不难发现,当关卡变化时,(04,00000000)的数值发生了改变,而经过作者不断实验发现,当只改变关卡数,仅有该数值发生变化:当游戏关卡为1-1时,其数值为01,当游戏关卡为1-10时,其数值为0A,以此类推皆成立。发现,该位置数字为16进制,且符合关卡变动规律,故推定该位置为关卡数据存放位置。
同时,在其他条件均相同情况下,用其他修改器修改游戏内的金币数,观察游戏存档变化。发现,当金币变化时,(08,00000000)(09,00000000)(0A,00000000)(0B,00000000)四个位置的数据随金币数量的十分之一而改变。
不妨令其四个值为a,b,c,d.设金币数为g,实验观察得知,金币数g满足方程
得知当金币数储存在上述各位置。
二、程序设计
以下以C++语言为例,简要说明修改的具体实现。
1.打开文件
首先,需要打开所需要的数据文件,并将其输入到内存中,此方法使用fread函数来读取二进制内容。由于该数据在显示上以两位16进制字符为一个单位,故使用char方式进行读取,以保证读取的数据格式与显示一致。
FILE *infile;//创建两个文件指针
FILE *outfile;
char filename[] = "C:\\ProgramData\\PopCap Games\\PlantsVsZombies\\userdata\\user1.dat";//数据所在位置
infile = fopen(filename, "rb");//以二进制方式读取
while (fread(&num1, sizeof(char), 1, infile))//以一个字节为一个单位
a[x] = num1, x++;
fclose(infile);
2.修改
其次,进入修改环节,核心在于对输入的数据进行处理后修改。
若要跳关,则执行以下代码:
printf("请输入您需要跳到的关卡(x-y):\n");
scanf("%d-%d", &q, &w);//输入x-y关
while (q < 1 || q > 6 || w > 10 || w < 1)//边界条件
{
printf("输入不正确,请再次输入(1<=x<=6,1<=y<=10)\n");
scanf("%d-%d", &q, &w);
}
char jump = (q - 1) * 10 + w;//赋值
a[4] = jump;
printf("跳到%d-%d关......\n\n", q, w);
若要修改金币,则执行以下代码:
printf("请输入您需要的金币数(x10):\n");
scanf("%d", &gold);//输入金币数
while (gold < 0 || gold > 999999999)
{
printf("输入不正确,请再次输入\n");
scanf("%d", &gold);
}
/*
以编码方式储存数据,并将int隐式转换为char
*/
int g = gold;
a[8] = gold % 256;
gold /= 256;
a[9] = gold % 256;
gold /= 256;
a[10] = gold % 256;
gold /= 256;
a[11] = gold % 256;
gold /= 256;
printf("修改到%d0金币......\n", g);
3.写入
将修改完的数组以二进制方式写入文件:
outfile = fopen(filename, "wb");
fwrite(a, sizeof(a), 1, outfile);
fclose(outfile);
完整代码
以下代码加入了一些操作提示,便于进行操作
#include <bits/stdc++.h>
int main()
{
int q, w, gold;
FILE *infile;
FILE *outfile;
char filename[] = "C:\\ProgramData\\PopCap Games\\PlantsVsZombies\\userdata\\user1.dat";
infile = fopen(filename, "rb");
unsigned char a[820];
unsigned char num1;
int x = 0;
while (fread(&num1, sizeof(char), 1, infile))
a[x] = num1, x++;
fclose(infile);
printf("欢迎使用植物大战僵尸修改器\n\n");
printf("需要跳关吗?\n输入1跳关\n");
int num;
scanf("%d", &num);
if (num == 1)
{
printf("请输入您需要跳到的关卡(x-y):\n");
scanf("%d-%d", &q, &w);
while (q < 1 || q > 6 || w > 10 || w < 1)
{
printf("输入不正确,请再次输入(1<=x<=6,1<=y<=10)\n");
scanf("%d-%d", &q, &w);
}
char jump = (q - 1) * 10 + w;
a[4] = jump;
printf("跳到%d-%d关......\n\n", q, w);
}
printf("需要修改金币吗?\n输入1修改\n");
scanf("%d", &num);
if (num == 1)
{
printf("请输入您需要的金币数(x10):\n");
scanf("%d", &gold);
while (gold < 0 || gold > 999999999)
{
printf("输入不正确,请再次输入\n");
scanf("%d", &gold);
}
int g = gold;
a[8] = gold % 256;
gold /= 256;
a[9] = gold % 256;
gold /= 256;
a[10] = gold % 256;
gold /= 256;
a[11] = gold % 256;
gold /= 256;
printf("修改到%d0金币......\n", g);
}
printf("\n");
printf("修改成功!\n");
outfile = fopen(filename, "wb");
fwrite(a, sizeof(a), 1, outfile);
fclose(outfile);
system("pause");
return 0;
}
相关样题解答
110101010001转十六进制是多少?
D51
101011.101011的十进制数是多少?
43.671875
常见的视频编码格式有哪些?
AVI,DV-AVI,MPEG,DivX,MOV,ASF,WMV,RM,RMVB等
65对应ASCII码是哪个字符?
‘A’
总结
本文对植物大战僵尸中的数值修改进行了阐述,望能对读者有所帮助。本人才疏学浅,本文必有纰漏之处,望诸君不吝指出,谢谢。