侠盗猎车:圣安地列斯CLEO入门教程

来自萌娘文库
宇文天启讨论 | 贡献2019年4月17日 (三) 20:04的版本 (3)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转至: 导航搜索

作品名:侠盗猎车:圣安地列斯CLEO入门教程

作者:璐绥居士

说明:我学习CLEO也有一段时间了。可供参考的资料少之又少,唯一的一点还都是在外国网站上找的英文资料,开着词霸我就一点一点地看啊看。最后也就能制作一些简单的作品,太复杂的还希望看到此文的高手给予指点。本教程是入门级别,主要是我学习的一些心得,希望能给对CLEO制作感兴趣的朋友们一点帮助。

 

引言:CLEO的环境和基本说明

《侠盗猎车:圣安地列斯》,英文名GTA:SA,是一款集第三人称射击、赛车竞速、角色扮演、恋爱养成等元素为一体的经典游戏,更可喜的是游戏给各位喜爱DIY的玩家多方面的接口,大家可以从不同角度去修改游戏使其个性化,CLEO即是基于GTA:SA的一种功能MOD,通过它可以实现很多根本不敢想的功能,比如让游戏主角在天上飞,海里的鲨鱼会吃人,像蜘蛛侠一样爬到墙上,发射六脉神剑等等,可以说是其乐无穷的一种MOD。

想在游戏中使用CLEO功能,首先需要安装CLEO环境,去CLEO的主页下载最新的cleo3,地址:http://cleo.sannybuilder.com/ 左上角有两个链接,第一个是自动安装程序。下载后安装到你的游戏目录下,这时打开游戏目录,你会发现多了一个CLEO文件夹。以后你在网上下载的CLEO就可以放在这个文件夹下了。注意只有扩展名为.cs或.cm的文件才能放在CLEO目录,.fxt文件要放在CLEO_TEXT目录下。游戏运行时加载所有cs文件,玩家可以使用全部功能。

CLEO功能主文件的扩展名是cs(CLEO Script),一些任务类CLEO还有扩展名为cm(CLEO Mission)的任务文件,放在CLEO文件夹根目录下;此外还可能有扩展名为fxt的文件,是CLEO中所需要的文本描述,可以用记事本编辑,放在CLEO\CLEO_TEXT文件夹下;如果还有扩展名为txd的,放在游戏目录下的models\txd文件夹下。若还有其余文件请参考该MOD的说明。

在游戏中使用CLEO功能,需要详细阅读帮助文件,知道其功能,使用功能的方法(快捷键或作弊码),使用功能所需要的条件(步行或乘车),以及一些可能导致游戏错误的BUG的说明,尽量避免在这些情况下使用CLEO,这是很重要的,免得你在没存档之前错误退出而捶胸顿足。

CLEO的修改和制作需要一款软件:SannyBuilder(简称SB),在其官网上可以免费下载(http://www.sannybuilder.com/ ),安装完成以后就可以使用了。如果出错需要在Tools-Options里设置SA的安装路径。

SB可以打开main.scm文件,.cs文件,.cm文件以及所有的文本文件。在打开文本文件的时候就是一个纯粹的文本编辑器;在打开CLEO文件和MAIN文件时先自动反编译出源代码存为txt放在当前目录,再打开该txt,我们做好修改以后,需要按下F7键,程序完成三个步骤:保存当前文档(txt),编译成CLEO的cs文件或main.scm文件,复制该文件到游戏目录(如果不在原始目录的话),cs和cm放到CLEO下,main.scm放到Script下,总之各归各位。大概就是这么一个流程。

这就是CLEO环境和开发环境的简单介绍,对于CLEO制作和编辑感兴趣的请继续看下文,只对使用感兴趣的就到这里为止了。

第一课:引例◆一个简单CLEO的横向剖析

CLEO的学习是从修改开始的,如果一开始就讲一大堆代码,变量,语句之类估计会吓跑一堆人,呵呵,好了不多说了,我们开始吧。

这是一个代码很简单的CLEO,曾经作为火星物品被封锁,主文件名是repair.cs,主要功能是在车上的时候,按Y键可以把车修好,就不用去喷漆处了。

以下是该CLEO源码和我作的说明,每条语句的//后:

 

// This file was decompiled using SASCM.INI published by Seemann (http://sannybuilder.com/files/SASCM.rar) on 13.10.2007

 

{$VERSION 3.1.0027}

{$CLEO .cs}

 

//-------------MAIN---------------

//注意以上代码不可缺少,它标志着这是一个CLEO文件,而不是main.scm文件

thread 'ENGINE' //引号里的是CLEO的名称,必须保证不会和已有的CLEO重名

 

ENGINE_11 //这是标签,为语句跳转所设

wait 10 //等待10毫秒

if //如果,条件判断

   Player.Defined($PLAYER_CHAR) //玩家是否定义?真正含义不解,没有这个判断也行

jf @ENGINE_11 //如果条件不满足的话跳转到ENGINE_11,满足的话继续执行

if and //多条件必须同时满足,表示与的关系

0449: actor $PLAYER_ACTOR in_a_car //主角是否在车里

00E1: player 0 pressed_key 11 //是否按下了功能键11(游戏默认是Y键)

jf @ENGINE_11

03C0: $CAR_REP = actor $PLAYER_ACTOR car //定义主角所乘车辆的句柄变量

0A30: repair_car $CAR_REP //修车

jump @ENGINE_11 //无条件跳转

0A93: end_custom_thread //结束标记

 

大家可以在SB里新建一文档,将上面的代码拷进去,就能编译了,//是注释标记,不受影响。

看懂了之后我来做几点说明。SB的程序设计语言似乎没有循环这么一说,全是goto语句,这对适应了结构化程序设计的人来说是相当不习惯的。总是被代码拖着,一会儿跳到这里,一会儿跳到那里。但是对于游戏来说,的确很需要这种跳转,这样使得代码更容易被游戏所理解。

进入游戏后,首先判断玩家是否加载正常,不是的话重新执行,直到加载正常,然后判断玩家是否在车里并按了Y键,如不是重新执行,直到满足条件为止,设置车的句柄变量,然后用该变量就能控制玩家所乘坐的车了。本代码的目的是修车,就只有一句代码,所以说0A30: repair_car $CAR_REP才是这段代码中最重要的一句。

我们可以在这个CLEO的基础上,增加自己想有的功能,比如说觉得无偿修车太没意思了,可以在修车的同时减少玩家的金钱数:

Player.Money($PLAYER_CHAR) += -10000 //本句加在修车句之后

呵呵,这就可以了,加太多语句就跑题了。好了,本次课就到这里了,如果觉得还行的话欢迎下次再来哦,下一次就开始讲解SB的语法了,毕竟搞编程不懂语法不行啊 ^_^

第二课:opcode规则和一般语法

在上一个例子中不知大家有没有注意到一些代码前面有类似0A93:的字样,这就是所谓的opcode,每一个opcode都有一个特定的含义,目前官方似乎不愿意公布所有opcode的详细用法,这就给我们制作CLEO的制造了麻烦,我们不得不通过分析一些CLEO来研究每一条opcode的用法。一般情况下,如果你知道了一种功能的opcode,你就可以在CLEO中实现这种功能,比如修车的0A30:,只有知道这条opcode的人才会用它来编出有修车功能的CLEO。

Opcode并不一定每条语句都得有,一些简单的语句可以省略opcode,如果你编译的时候出现了错误,可能是你把不该省略的opcode给省略了,所以建议大家除了那些有例子可以省略的语句外,一律加上其opcode。

在SB界面下,你把光标定位到某一条语句时,状态栏就会显示该语句的opcode用法,比如03C0: $CAR_REP = actor $PLAYER_ACTOR car,显示的是03C0: expecting 2 params,意思是这个opcode有两个变量,表现出来就是$CAR_REP和$PLAYER_ACTOR。

好了,下面就是SB的语法介绍了。

SB语句不区分大小写。

变量:SB的变量命名规则和别的语言大不相同,大致分为两类,功能是一样的,具体喜好就看程序员自己了。它们是以$开头的字符串和以@结束的数字。举例:$sanny,10@

变量支持隐式定义,即直接使用,但全局变量需要定义。

变量的类型包括常用的整型,浮点型以外,还有句柄型,即上例中标志玩家所乘车辆的变量。

语法:算术运算和比较运算同C语言的语法,赋值语句支持+=等方法。

基本语法是条件判断和跳转。其他语句还真不怎么熟悉,用的很少。

跳转:jump @MAIN_4,提前保证有:MAIN_4的标签,以便于跳转时找到目标

单一条件判断并跳转:

If

 语句,返回值必须为真或假,从英文字面上看是肯定语气的opcode

jump_if_false @MAIN_4 如果条件不成立,则跳转到指定语句

本句可简写为 jf @MAIN_4,意思一样

多条件判断并跳转:

If and

 语句1

 语句2

 …… 必须同时满足所有语句才行

jf @MAIN_4

If or

 语句1

 语句2

 …… 只需满足其中一条语句就行

jf @MAIN_4

可以说SB的基本语法也就这么多,没什么难的。主要的难点在于灵活运用每一条opcode,每一条opcode都有它的参数表、固定格式和功能用法,是不能乱用的,比如01B6: set_weather 1是设置天气的opcode,如果断章取义写成了01B6: repair_car $CAR,那就是严重的错误了,所以务必要弄清楚opcode的格式规范。在SB界面下按Ctrl+Alt+2可以打开一个opcode查询器,能查到所有opcode的基本用法,但也只能到这个程度,更复杂的使用和技巧就只有靠我们自己去摸索和发现了。

好了,这一课就到这里了,以后的教程我会结合各种各样不同类型的CLEO代码进行分析,让大家在不同的功能中丰富和探索CLEO的知识。

第三课:CLEO与玩家的接口

当编好了一个很经典的CLEO时,必须设置与玩家的接口,即触发条件。没有接口,CLEO就像是程序设计中未调用的函数,失去了它本身的意义。

CLEO与玩家的接口表现在三个方面:1、自动触发;2、玩家就像输入作弊码那样触发;3、玩家在键盘上按下某个键时触发。自动触发的CLEO很多,比如汽车耐久度计量槽,汽车加油,NPC跳楼等等。然而我们用的最多的,还是那些经典的,可以触发的功能CLEO。

大家从网上下载的CLEO,很多都存在快捷键冲突的问题,像上例修车那样,用功能键Y定义,实在是太不合理了。还有那个呼叫出租的,居然设成了1和2。所以我们这一课的主要目的,就是把这些不合理的快捷键改掉,让每个CLEO互相都不起冲突。

CLEO的快捷键分为两类,按键,功能键和作弊码,下面分别说明

①按键类,即按下1等单键,或Ctrl+W等组合键实现接口功能

核心代码:0AB0: key_pressed 0x73

0AB0是opcode,不可缺少,0x73是一个变量,类型为KeyCode码,比如我设置快捷键为U,代码应该写成:0AB0: key_pressed 85。字母和数字的KeyCode码同ASCII码,其他特殊字符的KeyCode列举如下:

小键盘上的键

控制键

功能键

按键

键码

按键

键码

按键

键码

按键

键码

0

96

BackSpace

8



39

F1

112

1

97

Tab

9



40

F2

113

2

98

Clear

12

Insert

45

F3

114

3

99

Enter

13

Delete

46

F4

115

4

100

Shift

16

NumLock

144

F5

116

5

101

Control

17



186

F6

117

6

102

Alt

18

=+

187

F7

118

7

103

CapsLock

20

,<

188

F8

119

8

104

Esc

27

-_

189

F9

120

9

105

Spacebar

32

.>

190

F10

121



106

PageUp

33

/?

191

F11

122

+

107

PageDown

34

`~

192

F12

123

Enter

108

End

35

[{

219

 

 

-

109

Home

36

\|

220

Win

91

.

110



37

]}

221

Pause

19

/

111



38

'"

222

 

 

如果想实现Ctrl+T,if语句的完整代码如下:

if and

0AB0: key_pressed 17 //Ctrl的KeyCode是17

0AB0: key_pressed 84

jf @MAIN_1

这样,就能轻易实现按键类快捷键的设置了。大家可以依葫芦画瓢,将那些不合理的或冲突的快捷键统统改掉,这下所有CLEO都能共用啦!

②功能键类

核心代码:00E1: player 0 pressed_key 19

之所以叫功能键,就是游戏中按下会起到一定效果的键,比如上下左右,开火或蹲下等,在游戏的设置中可以调,但无论调到那个键,CLEO中设置的功能键都会随之改变,没有按键的单一固定特性。设置此类功能键时应特别注意冲突问题,最好加上and和按键类一起使用。

修车CLEO的触发键是Y,这就是设置的功能键。如果你想设置成Ctrl+蹲下的快捷键,可以用if and来实现,代码为

if and

0AB0: key_pressed 17

00E1: player 0 pressed_key 20

jf @MAIN_1

以下列举常用的功能键及其代码:

2

left/right

3

steer back/up

4

special ctrl left/right

5

special ctrl up/down

6

secondary fire

7

look left

8

hand brake

9

look right

10

next radio station

11

previous radio station

12

no

13

yes

15

camera

16

brake/reverse

17

enter/exit

18

accelerate

19

fire

20

horn(in car)

21

submission

22

walk(on foot)

23

RMB vehicle mouse look

可能有一些不准,具体的大家可以自己进行测试。

功能键的设置适合制作一些武器类的CLEO,但大多数情况下并不推荐使用。

③作弊码类

作弊码的设置比较难,需要内存编辑的基础,初学者完全可以略过,以下也是我的一些心得,仅供参考。

1、eject.cs的作弊码(4字符作弊码)

核心代码:

0A8D: 0@ = read_memory 9867536 size 4 virtual_protect 0

if

04A4: 0@ == 1162495316 // @ == any

jf @EJECT_11

分析:从969110/16开始(开区间)读取4个单位长度(只能是4个),这是用户连续输入4个键的储存位置

1162495316/10=454A4554/16,拆开来就是45、4A、45、54,再转换成10进制并查出对应的ASCII字符即为密码“EJET”

操作:要修改这个CLEO的作弊码,可以按照我的步骤进行。假如修改成“ABCD”(只能是4个字符),先查出每个字符的ASCII码并分别转换成16进制,得到41、42、43、44,连起来,为41424344,转换为10进制,得到1094861636,这就是你在内存中想要读到的值。然后就可以写代码了,将上面代码的判断语句改成04A4: 0@ == 1094861636即可。

2、firework.cs的作弊码(4x字符作弊码)

核心代码:

0@ = -229907

if

  &0(0@,1i) == 1179210309

jf @FW_11

0@ = -229908

if

  &0(0@,1i) == 1464816203

jf @FW_11

&0(0@,1i) = 1464816128

分析:-229907应该也是内存地址,一个地址储存用户输入的4个连续键。读入用户第一次输入4个键,1179210309/10=46495245/16,拆开来就是46、49、52、45,即为“FIRE”

然后读入下一个内存地址的数据,1464816203/10=574F524B/16,拆开来就是57、4F、52、4B,即为“WORK”,连起来就是密码“FIREWORK”,最后的一句是内存的改写,避免程序重读错误。

操作:除了格式,基本原理和EJET一样,大家先把作弊码在内存的对应值算好,再带入“&0(0@,1i) ==*”比较语句即可,如果是12字符作弊码,在加一个判断语句即可,注意0@的变化规律。大家只需照套路走就是了,&0(0@,1i)的用法我还不是很懂。

3、amrifle.cs的作弊码(4字符以下作弊码)

核心代码:

0A8D: 0@ = read_memory 9867535 size 4 virtual_protect 0

if

  0@ == 1095586304

jf @AMR_11

0A8C: write_memory 9867536 size 4 value 1095586304 virtual_protect 0

分析:和4字符类似,1095586304/10=414D5200/16,即为“AMR”,但是注意读取的开始内存地址,4字符是9867536,3字符是9867535。最后一句也是内存改写以避免程序重读错误。

4、laevateinn.cs(任意字符作弊码)

核心代码:

30@ = -229906

008B: 30@ = &0(30@,1i) // (int)

0085: 31@ = 30@ // (int)

31@ /= 65536

31@ *= 65536

0062: 30@ -= 31@ // (int)

if

  30@ == 19521 //LE

jf @LVTN_11

30@ = -229907

if

  &0(30@,1i) == 1163280724

jf @LVTN_11

30@ = -229908

if

  &0(30@,1i) == 1162432078

jf @LVTN_11

&0(30@,1i) = 1162432000

分析:这段代码比较长,目的是在内存中获取“LAEVATEINN”,10个字符作弊码,可以切割来看,从右到左4位一组,LA,EVAT,EINN,算出来就是19521,1163280724,1162432078。后八位和2例类似,只是前两位的代码比较难懂。大家可以注意观察下内存的取得地址和前例的不同之处,以便触类旁通

5、hud.cs(4例的三字符补充)

核心代码:

2@ = -229908

008B: 0@ = &0(2@,1i) // (int)

0085: 1@ = 0@ // (int)

0@ /= 16777216

0@ *= 16777216

0062: 1@ -= 0@ // (int)

if

  1@ == 4740420 //485544

jf @HUD_28

&0(2@,1i) = 1213547520

分析:作为4例的补充,本代码的目的是“HUD”,三字符的算法和两字符略有不同,主要是在0@ /= 16777216上面,大家可以试试把这段字符转换成16进制,即为1000000,而65536则是10000,多了两个16进制字符位,正好就能区分4位和3位密码了。大家可以触类旁通,试试2位的该怎么写。

6、PEDSpawn.cs(傻瓜的作弊码设置,适合所有人)

核心代码:

if

0AB0: key_pressed 80

jf @PEDS_113

14@ = 1

33@ = 0

 

PEDS_113

if and

  14@ == 1

0AB0: key_pressed 69

jf @PEDS_149

14@ = 2

33@ = 0

 

PEDS_149

if and

  14@ == 2

0AB0: key_pressed 68

jf @PEDS_185

14@ = 0

jump @PEDS_218

分析:我想不用我多说了吧,值得注意的是单纯地照着这个思路下去会有一点问题,三个字符的触发判断必须要联系在一起,本例中33@和14@变量就是联系在一起的纽带。大家注意观察观察就不难发现,如果没有这条纽带的联系,就无法实现作弊码的效果了。

这个例子代码虽然含金量不高,但通俗易懂适合所有人使用,大家只需以此类推就能写出任意个字符的作弊码,但用太多判断语句,执行效率不高,多了的话会有让人无法忍受的延迟。

 

这一课说了这么多,总而言之就是如何设置快捷键来触发CLEO,想当初我就是为了这个目的来学习CLEO的,呵呵,当时没有人会的东西被我研究出来了,我相当有成就感。遗憾的是并不是每一条代码都理解的十分透彻,可恶的SB并不给出详尽的解释,我想研究CLEO的路应该还很长,很长……