分享到新浪微博 分享到QQ空间 打印

[美工] 修改火红标题画面!

修改火红标题画面!

PTB roywillow 原创,转载注明

这个帖子就别带图了……大家自己理解,只有领悟了才能真正会做

首先,用unLZGBA打开火红中文的Rom,提示框直接点确定,几秒后,即可操作。
到达144,这个就是火红的图片。你能认出来咱可怜的盆或龙么?
import皮卡丘图片。这里咱给提供一个(你想问我怎么弄来的?我在修改英文版的时候得到的……):

点 write to rom,写入rom。然后打开游戏,看看标题画面……这个……是皮卡丘么?没关系,我没还没有修改tilemap呢!(tilemap知识看文末)。这个时候只要发现皮卡丘的“尸体”是一种很XX的粉色就可以。如果不是……可能是图片超出了范围,在write to rom的时候,第二列第一个什么auto abort别打上钩看看。
确定标题图片是我所说的样子之后,备份rom。一定要备份!下一步有点困难,我失败了不下五次。
原来的喷火龙下一个图就是tilemap,点raw dump,导出tilemap。
打开cyclone,导入tileset,也就是皮卡丘图,然后load tilemap,选择图片左上角的一小块,把整个右边零乱的画面给抹掉。然后,从左边一个个选择小方块,到右边拼出来。你想让皮卡丘出现在屏幕那个位置就在右面的相应位置拼出皮卡丘。右面好像就是一个GBA屏幕……这一步要注意皮卡丘脚等等部位的图块就一个像素,别漏掉。还有就是肚子部位颜色相同,别自作主张搞混了。
save tilemap为raw格式。在unLZGBA里面的这个tilemap导入刚刚的raw文件(在文件菜单里面有导入)。write to rom,刚提到的某个小钩咱到现在也不确定要不要打上。你可以两个都试一遍。
打开rom看看效果。如果你发现除了皮卡丘颜色全身都是很XX的粉红色,没有别的不同,恭喜你,你过了最重要的一关。如果你发现背景的颜色,或者皮卡丘成了灰色等等(我n次遇到),说明你……失败了……下一步的修改调色板什么的进行下去都没有了意义……
打开APE,到达皮卡丘的调色板:00C405D0,这个其实是精灵图片的皮卡丘的调色板地址,由于颜色差不多,就挪用了。注意此步需要把compresses什么打上钩。然后copy到下面的调色板里面。到达喷火龙的调色板:00385228,这一步不用打上那个钩。点replace。到rom里面查看效果。是不是皮卡丘变成了绿色?(也许出现,反正我这里出现了)还有皮卡丘轮廓成了XX粉色?(这个应该一定)仔细看看调色板,发现了吗?有两种皮卡丘黄成了绿色。打开color picker,从皮卡丘身上吸取相应的颜色。(那几种黄色依次变深),然后就是第二个很XX的粉色,那个就是轮廓,修改为0000,黑色即可。
再一次打开rom,是不是OK?

我的效果(用的是英文版的tilemap,所以皮卡丘的位置……):

皮卡丘烧尾巴了哈……

对了,你可能会发现皮卡丘嘴和脸颊有点颜色不对,那个也是调色板的问题。用picker吸取错误的颜色,知道了错误颜色的代码后,把调色板相应的颜色给修改了就可以了。(做英文版也出现了,不过录像没出现……)

顺便附上我用的tilemap。大家先做做自己的tilemap看看,如果总是不行,就用这个吧……如果OK,一定要传上来分享!


tilemap:根据个人的理解,没有查资料哈。tilemap,字面上就使碎片地图,同tileset对应。游戏中的图片大部分都是类似碎片的东西,大概是为了存储的时候节省空间。游戏启动的时候,为了得知每一个碎片的位置,就用到了tilemap,就像地图一样告诉每一个碎片的位置。(这下明白了皮卡丘肚子的“相同”的图块不能乱放的原因了吧)就这点解释,自己领悟。


PTB roywillow 原创,转载注明

[ 本帖最后由 海洋之囧 于 2009-1-18 11:59 编辑 ]
附件: 您所在的用户组无法下载或查看附件

TOP

哇,酷……那图是可以随便替换的喽

TOP

我感觉跟修改我p4固件一个道理。。
谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP

114是一个蓝色的点而已啊

TOP

根据解出的版本不同,图片位置可能不同
这个变动下倒无所谓
谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP

引用:
原帖由 冰の都 于 2008-7-16 01:04 发表
114是一个蓝色的点而已啊
咳咳……是144……不过也可能有偏差


对了,提供的皮卡丘图片最好不要随便裁减。得保证长宽是8的倍数

[ 本帖最后由 roywillow 于 2008-7-16 12:13 编辑 ]

TOP

如果能找到指针的话,那么无论哪个ROM都能顺利的找到完整的题目画面了,而制作工具也就成为了可能……
每次来网吧就用“王道”给PTB浇浇水……好习惯吧?

TOP

目前国外也没有完整的修改工具……估计只有手动最保险……


PS:花子问问zel怎么修改冲浪坐骑……PC上的人说“Thats strange”……因为在OE里面找不到……(我记得打开英文的时候也找不到……)

TOP

有点复杂的说~ 但是,MS还是很好的嘛!

TOP

TOP

建议你把那火删了.把后面的火改为雷电

TOP

正想呢……有点麻烦……因为得用黑白模式……冰帮我做个OK?

TOP

嗯...因为是连着的.每个图也连接口也要一样.我也在想怎么做雷电

TOP



失败了...........

TOP

做几个噼啪的黄色火花就行,就当是雷球

TOP

我还是不会操作指针
如果会的话写什么改版工具也都简单了
谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP

操作指南?什么意思

TOP

编程方面你可以休息了
谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP

什么意思...告诉我

[ 本帖最后由 冰の都 于 2008-7-21 15:36 编辑 ]

TOP

文件指针自己找去
引用:
2.在信息工程中指针是一个用来指示一个内存地址的计算机语言的变量或中央处理器(CPU)中寄存器(Register)。指针一般出现在比较近机器语言的语言,如汇编语言或C语言。面向对象的语言如Java一般避免用指针。指针一般指向一个函数或一个变量。在使用一个指针时,一个程序既可以直接使用这个指针所储存的内存地址,又可以使用这个地址里储存的变量或函数的值。
大家都认为,c语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是c语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有c语言的指针才能算指针。basic不支持指针,在此不论。其实,pascal语言本身也是支持指针的。从最初的pascal发展至今的object pascal,可以说在指针运用上,丝毫不会逊色于c语言的指针。

指针
1、内存分配表
    计算机中的内存都是编址的,就像你家的地址一样。在程序编译或者运行的时候,系统(可以不关心具体是什么,可能是编译器,也可能是操作系统)开辟了一张表。每遇到一次声明语句(包括函数的传入参数的声明)都会开辟一个内存空间,并在表中增加一行纪录。记载着一些对应关系。
----------------------------------------------------
Declaration       | ID Name       Address Length
----------------------------------------------------
Int nP;           | 1  nP         2000     2B
char myChar;      | 2  myChar     2002     1B
int *myPointer;   | 3  myPointer  2003     2B
char *myPointer2; | 4  myPointer2 2005     2B
----------------------------------------------------

2、指针就是一个整数。
    指针,是一个无符号整数(unsigned int,下简写为int),它是一个以当前系统寻址范围为取值范围的整数。32 位系统下寻址能力(地址空间)是4G-bit(0~232-1)二进制表示长度为32bit,也就是4B。
    int 类型也正好如此取值。
    例证就是程序1 得到的答案和程序2 的答案一致。(不同机器可能需要调整一下pT 取值。)
----------------------------------------------------
程序1
#include <stdio.h>
main()
{
    char *pT;
    char t='h';
    pT=&t;
    putchar(*pT);
}
----------------------------------------------------
程序2
#include <stdio.h>
main()
{
    char *pT;
    char t='h';
    pT=(char *)1245048;
    putchar(*pT);
}
----------------------------------------------------
    加上(char *)是因为毕竟int 和char *不是一回事,需要强制转换,否则会有个警告。因为char *声明过的类型,一次访问1 个sizeof(char)长度,double *声明过的类型,一次访问1个sizeof(double)长度。
    在汇编里int 类型和指针就是一回事了。因为不论是整数还是指针,执行自增的时候,都是其值加一。如果上文声明char *pT;,汇编语言中pT 自增之后值为1245049,可是C语言中pT++之后pT 值为1245049。如果32 位系统中, s 上文声明int *pT;,汇编语言中pT 自增之后值为1245049,可是C 语言中pT++之后pT 值为1245052。
    为什么DOS下面的Turbo C,和Windows 下VC 的int 类型不一样长。因为DOS是16位的,Windows 是32 位的,可以预见,在64 位Windows 中编译,上文声明int *pT;,pT++之后pT 值为1245056。
    那么,复杂的结构怎么分配空间呢?C 语言的结构体(汇编语言对应为Record 类型)按顺
序分配空间。
----------------------------------------------------
int a[20];
----------------------------------------------------
typedef struct st
{
    double val;
    char c;
    struct st *next;
} pst;
----------------------------------------------------
pst pT[10];
----------------------------------------------------
    在32 位系统下,内存里面做如下分配(单位:H,16 进制);
----------------------------------------------------
变量 2000 2001 2002 2003 2004 2005 2006 … 204C 204D 204E 204F
地址 a[0]                a[1]           … a[19]
----------------------------------------------------
变量 2050    2051 … 2057 2058     2059 205A 205B 205C 205D 205E 205F
地址 pst.val pst.c        pst.next                     无效 无效 无效
----------------------------------------------------
    这就说明了为什么sizeof(pst)=16 而不是8。编译器把结构体的Size 规定为结构体成员中Size 最大的那个类型的整数倍。
    至于pT 的存储,可以依例推得。总长为160,此不赘述。
    有个问题,如果执行pT++,答案是什么?是自增16,还是160?别忘了,pT 是常量,不能加减。
    所以,我们就可以声明:
----------------------------------------------------
typedef struct BinTree
{
    int value;
    struct BinTree *LeftChild;
    struct BinTree *RightChild;
} BTree;
----------------------------------------------------
    用一个整数,代表一棵树的结点。把它赋给某个结点的LeftChild/RightChild 值,就形成了上下级关系。只要无法找到一个路径,使得A->LC/RC->LC/RC...->LC/RC==A,这就构成了一棵二叉树。反之就成了图。

3、C 的按值传递
    C 中函数调用是按值传递的,传入参数在子函数中只是一个初值相等的副本,无法对传入参数作任何改动。但实际编程中,经常要改动传入参数的值。这一点我们可以用传入参数的地址而不是原参数本身,当对传入参数(地址)取(*)运算时,就可以直接在内存中修改,从而改动原想作为传入参数的参数值。
----------------------------------------------------
#include <stdio.h>
void inc(int *val)
{
    (*val)++;
}
main()
{
    int a=3;
    inc(&a);
    printf("%d" , a);
}
----------------------------------------------------
    在执行inc(&a);时,系统在内存分配表里增加了一行“inc 中的val”,其地址为新地址,值为&a。操作*val,即是在操作a 了。

4、*和&运算
    为了(*p)操作是这样一种运算,返回p 的值作为地址的那个空间的取值。(&p)则是这样一种运算,返回当时声明p 时开辟的地址。显然可以用赋值语句对内存地址赋值。我们假设有这么两段内存地址空间,他们取值如下:(单位:H,16 进制)
----------------------------------------------------
地址 0000 ... 2000 2001 2002 2003 2004 ... 3000 3001 3002 3003 ...
取值 ???? ... 01   30   00   00   30       00 03 20 9A
----------------------------------------------------
    假设有这么一段代码:(假设开辟空间时p 被分配给了3001H、3002H 两个位置)
----------------------------------------------------
int *p;
p=2003;
*p=3001H
----------------------------------------------------
    **p 的值为多少?
    **p=*(*(p))=*(*(2003H))=*(3000H)=0300H。
    那么&&p、*(&p)和&(*p)又等于多少?
    &&p=&(&(p))=&(3001H),此时出错了,3001H 是个常数怎么可能有地址呢?
    *&p=*(&(p))=*(3001H)=2003H,也就是*&p=p。
    &*p=&(*(p))=&(3001H),读者可能以为&*p=p 此时出错了,3001H 是个常数怎么可能有地址呢?

4'、另类的*和&
    两个地方要注意:
    在程序声明变量的时候的*,只是表明“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(type)长度”。这点不要和(*)操作符混淆;
    在C++程序声明变量的时候的&,只是表明“它是一个引用,这个引用声明时不开辟新空间,它在内存分配表加入新的一行,该行内存地址等于和调用时传入的对应参数内存地址”。
    这点不要和(*)声明符,(&)操作符混淆。
    清华大学软件学院免试研究生面试就有问过这个问题。

5、双重指针(指向指针的指针)
    双重指针又是怎么一回事儿呢?综合2 的BTree 定义,和3 的说法。对于一棵树,我们通常用它的根节点地址来表示这棵树。这就使“擒贼先擒王”。找到了树的根,其每个节点都可以找到。
    但是有时候我们需要对树进行删除节点,增加节点操作,往往考虑到删除根节点,增加的节点取代原来的根节点作为新根节点的情况。为了修改根节点这个“整数”,我们需要退一步,使用这个“整数”的内存地址,也就是指向这个“整数”的指针。在声明时,我们用2 个*号,声明指向指针的指针。它的意思是“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(int)长度,其值是一个整数,那个整数值指向某个内存地址,一次访问sizeof(BTree)长度。”。详见“数据结构.rar”有关“树”(06 文件夹)的程序代码。

6、指针数组、数组指针和指向函数的指针
    指针数组:就是一个整数数组,那个数组的各个元素都是整数,指向某个内存地址。
    数组指针:数组名本身就是一个指针,指向数组的首地址。注意这是一个常数。
    指向函数的指针:从二进制角度考虑,数组名是该数组数据段首地址,函数名就是该代码段的首地址,可以用“int *fun()”。在二进制层面,代码段和数据段什么区别?没什么区别。
----------------------------------------------------
#include <stdio.h>
void inc(int *val)
{
    (*val)++;
}
main()
{
    void (*fun)(int *);
    int a=3;
    fun=inc;
    (*fun)(&a);
    printf("%d" , a);
}
---------------------------------------------------- 

谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP