文明6mod制作(8):lua写脚步
前言

Gameplay相关部分
先用Lua做一个简单的mod,在文档\My Games\Sid Meier’s Civilzation VI\Mods下新建一个文件夹,然后在里面创建一个lua脚本文件(demo.lua)
要编写游戏脚本,首先必须要知道游戏接口(API),官方没有资料,以下是网友总结的:
原文件:http://1t.click/bnfV (可能无法访问)
在表格底下点击Events切换,文明6的脚步是事件驱动(当某一事件发生时,游戏自动调用我们准备好的函数),我们需要做的就是为事件创建一个函数(function)
例如:事件ResearchCompleted是完成科技,参数包含玩家ID和科技序号
假设要让我们每完成一项科技,都能获得100金币:
1
2
3
4
5
6
7function OnResearchCompleted(iPlayerID, iTech)
local pPlayer = Players[iPlayerID]
pPlayer:GetTreasury():ChangeGoldBalance(100)
end
Events.ResearchCompleted.Add(OnResearchCompleted)具体可以看表格的Lua Objects部分(难免有错误的地方),所以最好去看官方文件,下面这是一款用来查询游戏自带文件的软件:
https://www.mythicsoft.com/agentransack/
具体操作如下,打开软件,在File name这里输入*.lua,表示所有后缀名为lua的文件,在Containing text一栏输入要搜索的字符串,选择搜索目录为文明6的游戏根目录,点击start开始搜索,即可找到游戏源文件中 所有包含该字符串的文件
脚本写好之后,需要创建modinfo文件来加载
前面的写法与其他mod类似
接下来是Components部分,添加游戏脚步的操作
最后是包含的全部文件,就做完了
利用官方工具调试
1.初步调试
利用官方提供的工具对代码进行调试,首先在游戏选项里面启用调谐器

然后打开官方的开发工具(Development Tools),在启动界面那里选择Fire Tuner(调谐器)
进入游戏后,左上角选择打开面板(Open Pannel)

进入Debug文件夹(在游戏根目录\Debug),其中
City.ltp是城市
Map.ltp是地图
Player.ltp是玩家
Unit.ltp是单位
Forge.ltp是界面

2.调节玩家数据
选一个和城市有关的举例,在空白的地方选择新的动作(New Action Control)

名字随便填,下面Action方框内就是测试代码的地方,输进来后点击测试点OK,如下图的输出结果就表明没有问题

最经常操作的lua对象就是以下四种,上面改金币的例子就是第一种

很多事件在触发的时候 会把玩家的ID给传递过来,于是就可以根据ID获得指定玩家,有的是获取单位的ID
可以参考lua手册检索常用功能:
3.调节单位数据
接下来对单位进行测试,获取单位根据玩家ID和单位ID,打开Unit文件,单人游戏本地玩家ID都是0,于是在代码框中如下输入即可


4.调节城市数据
接下来对城市进行测试,获取城市可以根据ID或者坐标,打开City文件,如下操作输出即可


有一种显示浮动文本的方式如下:第一项填0,第二项是要显示的字符串,最后两个是坐标
5.调节单元格数据
接下来对单元格进行测试,通过坐标获取,根据格位可以查询上面的地貌资源等
还有常见判断,比如判断是不是平原、海洋等

6.其他和实例
除此之外还有3个全局表,它们不是类的实例,所以调用方法用的是点号,而不是冒号,具体写法参考文档

gameinfo是访问数据库用到的,接下来通过例子来介绍
由下图可见,当城市建造完成会传递五个参数:
第一个就是玩家的ID,根据ID获取所属的玩家,这一步经常要用到(即第二行):
1
2
3
4
5
6
7function OnCityProdComp(playerID, cityID, iConstructionType, itemID, bCancelled)
local pPlayer = Players[playerID]
end
Events.CityProductionCompleted.Add(OnCityProdComp)为了增强代码的健壮性,建议在这里判断结果是否为空,如果要判断是否是人类玩家的话就用IsHuman() 这个方法(第四行):
1
2
3
4
5
6
7
8
9
10function OnCityProdComp(playerID, cityID, iConstructionType, itemID, bCancelled)
local pPlayer = Players[playerID]
if pPlayer:IsHuman()
end
end
Events.CityProductionCompleted.Add(OnCityProdComp)第三个参数iConstructionType是建造的种类,0表示单位,1表示建筑或奇观,2表示区域,3表示项目
我们来获取刚造好的这个单位,用到的是第四个参数(第四行):
1
2
3
4
5
6
7
8
9
10function OnCityProdComp(playerID, cityID, iConstructionType, itemID, bCancelled)
local pPlayer = Players[playerID]
if pPlayer:IsHuman() and iConstructionType==0 then
end
end
Events.CityProductionCompleted.Add(OnCityProdComp)用SQ Lite Studio打开数据库(操作在(4)中有),找到Units这个表,切换到数据选项卡,第四个参数其实就是表中的序号,比如0是开拓者,1是建造者,上面获取的结果相当于表中的第一行,然后通过点号来获取其中的具体内容(如下)
同时此处也建议先判断结果是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function OnCityProdComp(playerID, cityID, iConstructionType, itemID, bCancelled)
local pPlayer = Players[playerID]
if pPlayer:IsHuman() and iConstructionType==0 then
local unit = Gameinfo.Units[itemID]
if unit ~= nil then
end
end
end
Events.CityProductionCompleted.Add(OnCityProdComp)现在要确定添加的位置,,正好第二个参数就是城市的ID,接下来获取城市并找出它的坐标值(8-10),建议用第11行的这种方法来添加单位,它能把新的单位放到指定坐标上,放不下也会放在相邻位置,第一个参数是玩家ID,第二个是单位类型,第三个和第四个是横纵坐标,第五个是单位数量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function OnCityProdComp(playerID, cityID, iConstructionType, itemID, bCancelled)
local pPlayer = Players[playerID]
if pPlayer:IsHuman() and iConstructionType==0 then
local unit = Gameinfo.Units[itemID]
if unit ~= nil then
local pCity = CityManager.GetCity(playerID, cityID)
local iX = pCity:GetX()
local iY = pCity:GetY()
UnitManager.InitUnitValidAdjacentHex(playerID, unit.UnitType, iX, iY, 1)
end
end
end
Events.CityProductionCompleted.Add(OnCityProdComp) --只要任意城市完成一项建造就会触发