找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 5530|回复: 6

译注:LUA代码进阶教程

[复制链接]
发表于 2018-9-18 13:33:22 | 显示全部楼层 |阅读模式
本帖最后由 Ngen 于 2024-4-24 19:58 编辑

CNCSAGE引擎和META MOD的LUA代码教程
作者:Mjjstral
译注:星火战队-Ngen
摘要:本文是CNCNZ论坛的Mjjstral aka. MetaIdea (Maximilian F.)制作的MetaMod2.00的自述文件中Lua教程的译注文。MetaMod是凯恩之怒的一个Mod,这个Mod最大的特点就是使用了大量先进而复杂的Lua代码,实现了游戏内实时编辑运行Lua代码、读写地图内具体单位标志信息、改编存档等神奇游戏效果,学习这个Mod的代码对于研究Lua在RA3Mod中的作用有重大意义。原文的前半部分主要介绍了KWMod的安装和MetaMod内置防御/塔防地图的玩法,后半部分则是Sage引擎中Lua代码的教程,后半部分对与研究Lua很有帮助,这里我对后半部分进行了翻译并注评,评注主要是指出在RA3的环境下相关代码与KW的区别。希望得到这个Mod及其源码请下载附件,这个Mod本身是开源的而且鼓励改编。实际上MetaMod本身也有开发工具的性质,因为它实现了在游戏内实时编辑运行Lua代码这个重要功能,即不需要反复打包Mod、开关游戏就能实现Mod中Lua代码的改动,这给modder带来了极大的便利,因而这个教程中有很多部分是在介绍如何使用MetaMod作为Mod的开发工具。只可惜这个Mod不能直接用在RA3中,只关心Lua在RA3ModSDK中实用功能的读者在读到此类时可以选择略读或者略过,跳过2、6、7、8,只看1、3、4、5、9,而其中5、9最为重要。当然如果你有能力可以尝试将游戏内实时编辑运行Lua代码的功能复刻至RA3中。为了保证代码本身保留字、函数名、xml模块等词的可搜索性,这些词选择不译,另外译者并非Lua程序员,如果相关专业术语翻译错误请多多包涵。
一、Lua一般信息
《命令与征服3:泰伯利亚战争》和《凯恩之怒》使用的所有Lua函数的语法和类型词都是4.0.1版,并且它们的参数使用官方的Lua4引用方法(参考refman-4.0.pdf)。要查找语法错误可使用luac4.exe,这在metamod的压缩包里有。比如一段错码会这样提示:
@Echo off
luac4.exe
"C:\LUA_INPUT.lua"pause
你可以选择933种不同的游戏内Lua代码指令来创造出非常复杂的游戏机制。Lua本身提供了95个内部Lua函数。另外在Meta Mod2.0里有大量新奇而且强大的函数。
下面这个重要的列表是在MetaMod压缩包里找到的:ALL_SAGE_LUA_COMMANDS.txt
这是CNC3的Sage引擎内部可行的所有Lua函数、指令、变量的列表,同时也包含了Lua本身的函数语法和一个LuaEvent代码表。这个列表包含了许多在scripts.ini里找不到的ExecuteAction和EvaluateCondition指令。这也许也能在同样出自EALA的《魔戒:中土之战》系列游戏中有用。至于如何给这些CNC Sage函数配用正确的参数请看下面的教程。更多关于如何使用Lua本身的函数的信息请看refman-4.0.pdf。
另一个文件METAMOD_LUA_REFERENCE_LIST.txt是关于Mjjstral的Meta Mod2.0中大部分函数、变量、表的列表。要使用的话请参考实际源码以详细了解参数的类型。在很多情况下函数的自变量是非必要的,你可以用nil值或直接不填来跳过某些自变量,根据上下文可知这些自变量是string还是table或者number类型。

二、快速写、测Lua代码的方法
用参数-win打开KW。打开LIVE_INPUT.lua文件和LIVE_OUTPUT.txt文件然后让文本编辑器放在游戏窗口旁边。然后使用meta control建造栏中的“Run Lua Script”按钮或者使用Force_Lua_Script_Button= yes来让协议技能栏出现“Run Lua Script”按钮。然后你可以直接在LIVE_INPUT.lua里输入代码,也可以重写已有函数。查看ErrorLog.txt来找错。我也推荐使用Dev_Mode = yes。要输出任何值到LIVE_OUTPUT.txt就使用out(yourtext)函数,而用print(yourtext)函数则是把值显示到游戏里。

三、下列行为在Lua代码中是可能的
1.  在执行代码中用string类型参数(在ObjectType变量中也行)
注1:所谓执行代码(action script)就是指真正产生实际游戏效果的933个游戏内部Lua函数。
2.  在执行代码中用real或float类型参数
3.  使用下拉列表的参数(通过用n-1值,n为该参数在下拉列表的序数)
注2:在地编脚本编辑器里具体脚本的参数选择时,有些参数是通过在下拉列表里选择来使用的,这里简单说一下Lua函数怎么引用地编下拉列表的值。有两种方法:1.直接用字符串,下拉列表里写着啥就照抄进Lua函数,然后用引号括起来。2.根据这个参数在下拉列表中的序数(第几个),把序数-1作为数值写进Lua里。
4.  在执行代码中用队伍名参数
5.  使用布尔值(0或1)
6.  文件的写入导出和各种操作(例如保存游戏,自动用config参数打开游戏,引用外部mod代码)
7.  播放自定义视频,用雷达况播视频,播Sound和Music
8.  单位的属性变化以及任意方式storage
9.  用EvaluateCondition系列函数得到单位的信息:如status、kindof、objecttype、数量等等
10. 自定义胜利条件
11. 计数器和计时器
12. 规划代码用的代码计时器


四、Lua代码的限制:
1.  有些执行代码不能用integer(整数)类型参数(只是少量)
2.  不能用player参数:不过大部分执行代码能用队伍名参数代替,所以我们可以靠它。在本文中提到的函数都能用。
3.  执行代码不能直接用地图绝对坐标系的值,只有SpawnAtPosition(...)这个函数能用。


1.png
 楼主| 发表于 2018-9-18 13:34:37 | 显示全部楼层
本帖最后由 Ngen 于 2018-9-18 13:42 编辑

五、在CNCSage引擎中Lua函数的参数使用规则:
关于CNC Sage引擎中非ExecuteAction和EvaluateCondition类函的Lua函数:这些函数只会引用table类型的Object参数(不像ExecuteAction类函数),所以一定要用GetObj.Table(Object)函数。注意在globals() table中有但没有在Lua注册过的Object不能被这些函数直接使用。
注3:所谓“在globals() table中有”就是说这个GameObject的本级(与kindof同级)属性值ForceLuaRegistration="True"或者这是在地编里放置的物体。而“在Lua注册”是指在AIUpdateModuleData 下的AILuaEventsList 有相关的EventList,不过这只是对KW而言,对于RA3并不能在AI段注册,而要在Behavior段用<LUAEventList>注册。

Object参数的类型:
•       Table类型参数:
这些Object存储在lua 的globals()这个table中(所有的lua函数和global变量也是)并且它们也都是table类型的值。这些Object的table类型值都有一个独特的以“OBJID”开头的标志值,所以我们可以容易地滤选它们。所有在GameObject的xml 中的AIUpdate模块中有AILuaEventsList描述的Object都会在globals()中有一个相应的table类型值。你可以在xml里用ForceLuaRegistration="True"来强行注册。
注4:同注3
•       String类型参数:
所有Object都有多种和它们有关的string类型名字。这类的引用值可以在所有使用某Object作为参数的ExecuteAction和EvaluateCondition指令中用到。

其他参数类别:
•       队伍名(Team names):
使用GetTeamName(Object),可以得到某单位的队伍名。
在MetaMod中队伍名取值范围是:ClientTeamName, NeutralTeam, CreepsTeam,
CivilianTeam,ObserverTeam。
在MetaMod中含队伍名的table是:GlobalTeamTable, HumanPlayerTable,AIPlayerTable, AllTeamsTable。
需要实际队伍名值请看MetaMod的源码(scripts.lua)。
•       路径点在这两个table中:WaypointTable, WaypointDistanceTable
•       区域名:在AreaTable 中(未过滤)
•       布尔值(TRUE/FALSE):用0或者“0”代表否,用1或者“1”代表是。
•       下拉列表参数(通过使用n-1值,n为该参数在下拉列表中的序数):如果在地编里选择参数时有一个下拉列表,那么你就需要在相应的Lua中使用n-1作为数值或者string类型值。大部分下拉列表在MetaMod中已经用table引用了,直接使用table里的值就行。
•       String类型值(字符串):在地编里能用文本框任意改的值在Lua中都可以使用string类型值作为参数。
•       Real或者Double 类型值(实数或双精度实数):在Lua中你可以使用数字甚至带数字的字符串来表示real或者double类型值。
•       Integer类型值(整数):除了与之相关的运算符之外似乎没有别的方法能使用整数。当读取进入电脑端时,Lua的电脑-代码接口会把所有在Lua代码中提及的数字都被完全地转化为double类型。
•       坐标系类型值:似乎Lua中不能用。
•       Player类型值:在已知方法中没有一种能直接使用Player类型参数。从内部看Player类型参数引用时似乎是struct类型(结构体)。实际上Player类型参数由代码文件夹名和Player名组成,即是"WBScriptFolder/Playername"形式,举个例子:"Player_1/<This Player>"。好消息是在大多数执行代码中你可以用相应的team类型值代替。另一个能间接使用Player类型值的地方是是用SendScriptHostCodeMessage的方法法,这会在2.7地图整合指南那部分说。

ExecuteAction和EvaluateCondition系列函数:
这些是可用函数中最最有价值的。所有牛逼玩意都能用这些函数实现。广泛地使用这些函数是MetaMod的主要特点。ExecuteAction系列函数能让你使用大部分地编脚本功能,而EvaluateCondition系列函数则让你能使用大部分地编脚本的IF条件。
破游共包含677个ExecuteAction函数以及218个EvaluateCondition函数,这些你都能尝试使用。你可以在MetaMod的下载包里找到这些函数和所有内部指令的完整列表。
至于如何给这些函数找合适的参数:
•       用MetaMod文件包里的ALL_SAGE_LUA_COMMANDS.txt列表,得到第一个参数。
•       也可以在scripts.ini中得到第一个参数,但有些参数在那是没有的。
•       使用地编的脚本编辑器菜单来查看所有参数的及其顺序。你可以输出一个脚本scb文件然后用编辑器打开来查看第一个参数,通常是一段用大写字母和下划线写的东西。你只需要加上引号就能在Lua里使用这个参数。
•       ExecuteAction:
语法:ExecuteAction(command,parameter1,parameter2,...)
引用某Object时: 既能用string类型值也能用table类型值
•       EvaluateCondition:
语法:EvaluateCondition(command,parameter1;parameter2,...)
引用某Object时:只能用string类型值,所以用GetObj.String函数以确保正确的值类型。
相关的运算符:使用“n-1”(n为运算符的序数)或者使用CompareTable["operator"]
(运算符顺序: >, >= ,< ,<=, ==,~=)

注5:这里原文说得比较模糊,且RA3与KW地编区别比较大,很多有用的函数在ALL_SAGE_LUA_COMMANDS.txt里并不能找到,而且似乎RA3也没有scripts.ini文件,我简单说一下怎么利用RA3的地编中的脚本编辑器查找Lua函数的相关参数。首先打开地编脚本编辑器,编辑一段你喜欢的脚本,然后输出脚本(Export scripts),生成一个scb文件。用记事本或者UE打开这个文件,会发现一大堆乱码,但仔细搜索还是能发现几句人话。
1.png
例如这是“当选择航母时,航母对最近的T3单位使用EMP”这个脚本,可以看到NAMED_USE_COMMANDBUTTON_ON_NEAREST_KIND就是对最近单位用某个cmd的意思,这可以作为ExecuteAction函数的第一个参数写入Lua里,然后<This Object>是第二个参数,不过通常我们会用self来作为这类指涉单位的参数,以指涉在主函数里引用的【这个单位】,而Command_ActivateEMPCruiseMissleSpecialPower则是第三个参数,T3_UNIT就是第四个参数,因此这句可以写为ExecuteAction(“NAMED_USE_COMMANDBUTTON_ON_NEAREST_KIND”,self,“Command_ActivateEMPCruiseMissleSpecialPower”,”T3_UNIT”)
而它的条件则是一个EvaluateCondition函数,这个函数的第一个参数是TYPE_SELECTED,第二个参数是AlliedAntiStructureShip,于是整个函数写为EvaluateCondition(“TYPE_SELECTED”,”AlliedAntiStructureShip”)
所以整段脚本在Lua中的表达就是:
If EvaluateCondition(“TYPE_SELECTED”,”AlliedAntiStructureShip”)==1
Then ExecuteAction(“NAMED_USE_COMMANDBUTTON_ON_NEAREST_KIND”,self,“Command_ActivateEMPCruiseMissleSpecialPower”,”T3_UNIT”)
End
可以发现,这里面的参数顺序不一,脚本条件和执行的动作混杂在一起,怎么在其中区分出正确的参数还是要很考验各人的灵视的。

回复

使用道具 举报

 楼主| 发表于 2018-9-18 13:36:09 | 显示全部楼层
本帖最后由 Ngen 于 2018-9-18 13:42 编辑

六.MetaMod中一些特别函数的信息
包含超过10000行的lua代码的Meta Mod 2.00提供了很多有用的函数并且使modder有可能拥有超越地编脚本编辑器的能力。在数以百计的函数、表、变量中,最为重要的应该是这些:
  
FUNCTION
  
COMMENT
SetScriptTimer(time,action,loops,condition)
in 1s steps, loops=-1 for infinite, action is a function or string
SetScriptTimerFast(time,action,loops)
in 0.01s steps
SetDelayed(func)
shortcut for ScriptTimerFast with 0.01 delay
spawn(ObjectType,team,number,ref,waypoint,ActionOnObject,OnObjectTy  pe)

SpawnAtPosition(ObjectType,team,x,y,z,ObjectRef,orientation,Waypoint,n  umbercount,fast,ActionOnObject)   
fast: 0=normal,1=fast,2=superfast
GetObjectPosition(Object)         
returns a table, accessing coordinates by table.x  and table.y
GetBaseRef(team)     
returns an object reference of the original base hq
push(Task)  
push tasks on the TaskStack that depend

on games simulation time,Task can be a function or a  string
pop(Task)  
every Task pushed should contain pop()
GetTeamName(teamobject)

GetTeamsDescriptiveName(input)
input can be team or object
GetFactionName(input)
input can be team or object
GetStringRefListOfAllObjects(CreepsTeamToo)

GetStringRefListOfAllObjectsForTeam(team)

print(output, display_time)

WriteToFile(output,file,mode,hide) or out(...)
If no file is specified,
  
LIVE_OUTPUT.txt will be used
RandomString(l)
l=length
SetCounter(counter, value, text, no_display)

SetTimerCounter(value, text, counter)

delete(thisobject)

FireWeaponOnObject(Object, Weapon)

FireWeaponPosition(Weapon,x,y,waypoint,OnObjectType)

flash(input)
team or object
GiveChoosePositionOption(team,action,action_with_position,waypoint)

GiveAcceptDenyOptions(team,acceptaction,denyaction,preaction)

GPOT
GlobalPlayerOptionTable:  Use GPOT[teamname][attributename] important attributenames:
  
"teamname","name",  "faction", "ai"
GlobalTeamTable, HumanPlayerTable, AIPlayerTable

ClientTeamName, NeutralTeam, CivilianTeam, CreepsTeam, ObserverTeam

Human_Players_Count, AI_Players_Count

注意:使用Meta Mod的源码以了解细节!需要完整列表请看METAMOD_LUA_REFERENCE_LIST.txt文件。在很多情况下函数的自变量是非强制的,考虑到具体情况,大部分自变量是string或者table或者number类型。你可以用nil值或简单地不填来跳过某些自变量。

产生单位以及位置信息:
SpawnAtPosition函数不能没有延时。延时时长取决于代码原理!所有用这种方法产生单位的执行代码都需要用代码计时器延时或者push(Task)或者把"ActionOnObject"作为最后一个变量。
如果你想产生一个新的带有IMMOBILE这个kindof的mod单位,你就需要新加一个spawnextender入口(1.在xml里看Object_MetaControlDummyOCLSpawnExtender.xml. 2.在lua的 OCLSpawnExtenderTable这个table里写代码。否则产生这个单位时游戏就会炸掉。
用spawn(...)就不会有有以上两个缺点,但你只能在0,0坐标点用objecttype的方式产生单位,然后使用路径点。


回复

使用道具 举报

 楼主| 发表于 2018-9-18 13:38:36 | 显示全部楼层
本帖最后由 Ngen 于 2018-9-18 13:43 编辑

七、地图整合指南
有三类地图整合方式:
1.MetaMod可以和加了特定地编脚本指令的地图联系。如果只想让外交联盟变化的选项正常运行,把METAMOD_MAP_SCRIPTS_CUSTOMMAPS.scb脚本文件导入你的地图就行。
2.要把mod自带的防御/塔防玩法搞得更好,你可以给出确切的路径点名、路径名以及单位名。这些在防御图中不是强制的但能帮助MetaMod的算法使用更好的单位产生点和行走路径。至于塔防地图,必须给出确切的塔名以让MetaMod能检测和工作。
通过这些手段,你可以做一个有MetaMod内置防守玩法之先进出兵机制的新防守或者塔防地图。这意味着你再也不需要考虑出兵代码了。如果你喜欢改变MetaMod的出兵行为,你可以用外部的mod代码重写那些代表性的函数或者直接把代码加到autostart.lua文件中。这意味着你可以给你的地图配上额外的防御/塔防地图的mod代码,通过改写MetaMod的一般函数抑或只是加上了仅会在特定地图使用的代码。
请使用下列名称约定以便MetaMod和地图整合:
对于防守或者塔防图:
1.创建路径点:
路径点名:METAMOD_NAOD_SPAWN_WAYPOINT (强制使用MetaMod的玩法)
另一类路径点名:METAMOD_NAOD_SPAWN_WAYPOINT_OPTIONAL (只有当用户启动时才使用MetaMod的玩法)
2.创建可选的路径:
路径名:METAMOD_NAOD_WAYPOINT_PATH
第一个路径点名:METAMOD_NAOD_WAYPOINT_PATH_START
对于塔防:
塔名:METAMOD_TOWERDEFENSE_OBJECT

有了以上的约定,MetaMod会自动地检测到路径点或者塔,然后开始它自带的防御/塔防玩法。你也可以用自己的产生单位脚本,只要"metamod_modstatus_counter"值不是0,就像玩家没开MetaMod一样。

3.LUA中"用户端-代码执行端"的联系桥
在MetaMod地图整合中有一种特殊情况出现在了所有KW官方图。这些地图因为全球征服模式而全都引用了一个通用代码。而你可以用这个引用来把你自己的代码一次性插入到所有地图中,只要编辑这个地图中的代码:libraries/lib_mg_tacticalplay_skirmish/lib_mg_tacticalplay_skirmish.map
注意到在这些通用代码中的计数器不会和在Lua环境下使用的计数器共享,所以我们需要借由MetaMod的SendScriptHostCodeMessage(code,counter)函数来把它们联系起来。这只不过是简单地把计数器值从用户端经过一个虚单位的经验转化到了在“代码执行“端的一个计数器上。

八、LUA输出和输入
MetaMod使用一个叫MetaModIO的工作文件夹,在这:
C:\Users\"USERNAME"\Documents\Command & Conquer 3 Kane'sWrath\MetaModIO
或者在这:
C:\Users\"USERNAME"\AppData\Roaming\Command & Conquer 3Kane's Wrath\MetaModIO
罕见情况在这:
...\"C&CKane'sWrath GameFolder"\RetailExe\1.2\...
你也可以通过游戏内的meta command menu栏-> mod info -> openMetaModIO folder来打开文件夹。游戏会最小化然后打开相应的文件夹。
•       1."AUTOSTART_CONFIG.lua":这是被游戏读取的主文件。你可以在其中插入任何Lua代码然后它就会在地图开始时执行。你也可以重写MetaMod的Lua函数、值和表,尽管大部分情况下推荐使用mod原本的代码。
•       2. "METAMOD_SAVEDATA":所有元数据,比如等级,xp点,代币和最高分都储存在这里。注意这个文件是加密的。
•       3."METAMOD_SAVEDATA_BACKUP":名字表示备用,是在每次载入一个新地图时第一个存档生成时产生的。
•       4. "LIVE_INPUT.lua":这玩意对modder来说太他妈的有用了,你可以在这里写Lua代码然后在游戏里执行,只要你用那个在meta tab菜单里的Lua代码按钮,或者在autostart config里用Force_Lua_Script_Button = yes 调出一个协议栏技能。如果没这玩意这个Mod根本不会做出来。
•       5. "LIVE_OUTPUT.txt":这是用WriteToFile(...)函数或者它的简写out("text")函数时输出时产生的。而且在metacommand菜单的“other”下大部分选项都会将它们的输出值转到这个文件。你可以输出整个单位列表或者其他有用的玩意来修理bug或者测试。
•       6. "templates.txt":这个文件存贮了你在metacommand菜单"templates"下你能创造的模板。每个模板都是一个函数,这个函数至少包含单位的type和它们的相对位置。
•       7. "ErrorLog.txt":在修理bug时非常有用,比如错别字或者语法错误,特别是在你用"LIVE_INPUT.lua"在游戏内允许代码的时候。
•       8. "PreLoad.lua":比任何Metamod函数都先执行的函数。没用过,搞这个只是为了修理bug。
•       9. mod script files:所有外部文件的运行框架,情看下一节
MetaMod外部mod代码运行器写Luamod代码:
所有Lua代码必须以"script."开头而以".lua"结尾存储于MetaModIO文件夹例如script.ExampleScript.lua,这样才能被MetaMod识别。有关事项请打游戏内meta command中的"external scripts"开子菜单。那里也会有创建"ExampleScript"的选项,这将会周期性地把“hello world“打在屏幕上。请以这个代码作为基础来创造你自己的代码。
要创造你自己的代码,首先请在"LIVE_INPUT.lua"的帮助下写入并且测试你的代码。要快速找出语法错误请用上面提到的luac4.exe法。
你也可以改写任何在MetaMod内存在的函数或者值。我建议你在这里发布你的代码:http://forums.cncnz.com/forum/59-tiberium-warskanes-wrath-maps-modding/或者在moddb也行。
我会把你的代码打包进未来的MetaMod中,如果你发给我的话。

回复

使用道具 举报

发表于 2018-9-18 16:02:09 | 显示全部楼层
顶贴,苯砷!!!
回复

使用道具 举报

 楼主| 发表于 2018-9-18 19:51:48 | 显示全部楼层
老是回不了贴,附件也发不上去,郁闷
不发了,来这里看吧http://www.ratotal.org/?thread-218.htm
回复

使用道具 举报

 楼主| 发表于 2018-9-18 19:53:14 | 显示全部楼层
回复不了,也发不了附件,郁闷
不发了,都来这里看吧http://www.ratotal.org/?thread-218.htm
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|Archiver|手机版|管理员邮箱|红警DIY论坛 |网站地图

GMT+8, 2026-8-26 17:35 , Processed in 0.077118 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表