Skip to content

地图脚本制作指南

Cook Green edited this page Dec 18, 2019 · 8 revisions

入口函数

一个地图脚本文件的入口函数是WorldLoaded, 你可以在这个函数里面加入一些初始化代码,比如获取玩家,添加任务目标等等 你可以使用如下代码定义这个入口函数:

WorldLoaded = function()
    .....
end

创建任务目标

任务目标就是玩家需要在这个任务完成的一些目标,有些任务目标失败不会影响游戏进程,但是有些任务目标失败将会导致游戏结束, 如果你想要创建一个任务目标的话,你可以使用下面的代码:


player = Player.GetPlayer("PLAYER NAME")
player.AddPrimaryObjective("Description String")   -[[添加一个主要任务目标]]
player.AddSecondaryObjective("Description String")   -[[添加一个次要任务目标]]

一个任务目标有三个触发器, OnObjectiveAdded, OnObjectiveCompleted和OnObjectiveFailed
AddPrimaryObjective或者AddSecondaryObjective被调用的时候OnObjectiveAdded会被触发
当调用MarkCompletedObjective的时候OnObjectiveCompleted会被触发
当调用MarkFailedObjective的时候OnObjectiveFailed会被触发
像这样:

ObjectiveObject = player.AddPrimaryObjective("blah")
player.MarkCompletedObjective(ObjectiveObject)
player.MarkFailedObjective(ObjectiveObject)


Trigger.OnObjectiveAdded = function(player, function(p, objectiveID))
    --[[ 你可以使用 p.GetObjectiveDescription(objectiveID) 方法去获取任务目标的描述 ]]
end

Trigger.OnObjectiveCompleted = function(player, function(p, objectiveID))
    --[[ 你可以使用 p.GetObjectiveDescription(objectiveID) 方法去获取任务目标的描述 ]]
end

Trigger.OnObjectiveFailed = function(player, function(p, objectiveID))
    --[[ 你可以使用 p.GetObjectiveDescription(objectiveID) 方法去获取任务目标的描述 ]]
end

当任意主要任务目标失败, OnPlayerLost触发器将会被触发, 相反地,当所有主要任务目标完成的时候, OnPlayerWon将会被触发
你可以自己挂钩这两个触发器

Trigger.OnPlayerLost = (player, LostFunction)  

Trigger.OnPlayerWon = (player, WonFunction)  

引用一个Actor

所有在map.yaml定义的Actor都可以在地图脚本文件中被引用, 比方说, 我们有一个像这样的map.yaml文件:

MapFormat: 11
RequiresMod: example
Title: Placeholder
Author: BlahBlahBlah
Tileset: TILESET
MapSize: 100,200
Bounds: 2,5,96,188
Visibility: Lobby
Categories: Conquest
Players:
	PlayerReference@Neutral:
		Name: Neutral
		OwnsWorld: True
		NonCombatant: True
		Faction: Random
	PlayerReference@Creeps:
		Name: Creeps
		NonCombatant: True
		Faction: Random

Actors:
	Actor0: ACTOR_TYPE
		Location: 95,3
		Owner: Neutral
	Actor1: ACTOR_TYPE
		Location: 114,26
		Owner: Neutral

如果我们想要在脚本文件中引用Actor0以检测其是否死亡,我们可以这样做:

if Actor0.IsDead then
    .....
end

我们可以直接使用在map.yaml定义的Actor的ID在地图脚本文件中使用, 并且可以访问这个Actor的所有属性.
因此,你最好把在map.yaml定义的Actor的ID修改得可读性强一些.

Tick方法

在脚本文件中Tick方法将会被引擎调用当引擎要更新游戏的时候,因此这意味着我们可以将一些我们需要持续调用的方法放在Tick方法里面,比如检测Actor状态,或者循环发送部队。 一个tick方法像如下这样:

Tick = function()
    ......
end

Map.yaml

map.yaml文件在OpenRA地图系统中很重要, 你不仅可以在这个文件中定义基本信息,比如作者,名称等等. 你还可以定义这个地图中存在的玩家已经Actor
尤其是, 你可以在这个文件重写规则文件和武器文件(就像在红警地图编辑器里面一样).

地图基本信息

地图基本信息包含地图文件所有信息:
MapFormat - 地图YAML文件格式, 通常是11
RequiresMod - 这个地图适用的模组
Title - 在地图浏览器里面显示的名称
Author - 在地图浏览器里面显示的作者
Tileset - 地图使用的地形
MapSize - 地图大小
Bounds - 地图边界
Visibility - 决定地图显示的位置,可用的取值: Lobby, ShellmapMissionSelector

  • Lobby - 地图将会在地图浏览器里面显示
  • Shellmap - 地图将作为一个启动的地图
  • MissionSelector - 地图将会显示在任务列表里面

Categories - 分组, 可以填写任意值

玩家定义信息

玩家在地图中的作用很重要,在地图中发生的所有游戏事件都是发生在这些玩家之间,一个玩家可以是由人操作的,也可以由AI控制的。一个玩家不意味着一个阵营,实际上,两个玩家,都可以是同一个阵营。

PlayerReference@Greece:
	Name: Greece
	Playable: True
	AllowBots: False
	Required: True
	LockFaction: True
	Faction: allies
	LockColor: True
	Color: ABB7E4
	LockSpawn: True
	LockTeam: True
	Allies: England
	Enemies: USSR

PlayerReference@Greece - 这告诉引擎,我们将要开始一个玩家定义块,其ID是Greece
Name: Greece - 玩家的名称是Greece
Playable: TrueAllowBots: False - 告诉引擎这是由人操作的玩家
Required: True - 这意味着这个游戏位置必须被赋予,否则的话将无法开始游戏
LockFaction: True - 其阵营将会被锁定
Faction: allies - 这个玩家所使用的阵营是allies
LockColor: True - 这个玩家使用的颜色不能被改变
Color: ABB7E4 - 如果LockColorTrue, 那你必须指定一个颜色
LockSpawn: True - 系统将锁定其刷出点
LockTeam: True - 其队伍不会变更
Allies - 这个玩家不会被Allies所定义的玩家所攻击,比方说,现在,这个Allies定义了England,那么这个玩家就不会被名为England的玩家所攻击
Enemies - 这个玩家将会被Enemies所定义的玩家攻击, 比方说, 现在,这个Enemies定义了USSR, 那么这个玩家将会被名为USSR的玩家所攻击

一旦你在map.yaml定义好了玩家, 之后你就可以在脚本中使用以下代码引用这个玩家:

player = Player.GetPlayer("PLAYERNAME")

对于我们之前分析那个玩家,我们可以通过如下的代码引用:

greece = Player.GetPlayer("Greece")

Actor定义信息

所有的Actor定义信息要在Actors:节点下定义

ACTORID: ACTOR_TYPE
    Location: 0, 0
    Facing: 100
    Owner: PLAYERNAME

ACTORID - Actor的ID,你可以在脚本文件直接使用这个id ACTOR_TYPE - 你在规则文件中所定义的actor的类型 Location - Actor在地图中的位置
Facing - Actor在地图中的朝向
Owner - Actor的拥有者,需要玩家的名称

规则重写

如果你需要在这个地图中做一些限制,比如单位限制,科技限制,甚至建筑限制,亦或者你想在本地图中让我方或者敌方生产一些特定的单位,你可以使用规则重写定义块,这个块可以覆盖规则文件中的定义
所有规则重写必须位于Rules:节点之下,定义方式与规则文件里面定义的方法一致

ACTORTYPE:
    Trait List....

或者你可以使用一个外部的地图规则文件,比如下面的代码:

Rules: map-rules.yaml

它会在与map.yaml相同目录下找到这个文件

武器重写

有些时候我们需要对武器进行一些修改, 但是又不想影响到其他地图正常使用,我们可以在map.yaml中使用武器重写定义块
武器重写定义块里面的内容和通常的武器定义没有任何区别
同样地,武器重写定义块也可以使用外部文件定义的方式,比如下面的代码

Weapons: map-weapons.yaml

它会在与map.yaml相同目录下找到这个文件

Lua语法

赋值语句:

variable = 1

条件语句

if 条件表达式 then
    ....
end

循环语句

while 条件表达式 do
    .....
end

或者

for x in arr do
    ....
end

或者使用OpenRA版本

Utils.Do(arr, function(element)
    ....
end)

注释

单行注释

--[[这是一个单行注释]]

多行注释

--[[
这些是多行注释
--]]

数组

arr = {"element1", "element2", "element3"}

tb = {}
tb["key"]="value"

访问数组元素

element  = arr[index]

定义函数

函数名称 = function(函数参数)
   ....
end

调用函数

函数名称(函数参数)

返回语句

return

参见

OpenRA Lua API: https://github.com/OpenRA/OpenRA/wiki/Lua-API