Mod:Lua脚本

来自Noita Wiki
跳到导航 跳到搜索
模组制作导航
基础
入门基础Lua脚本Data.wak实用工具
制作指南
音频敌人生物群系天赋法术精灵表材料图像放射器特殊行为CMake使用
组件/实体
组件文档枚举特殊标签所有标签列表
Lua编程
Lua API实用脚本
其他信息
法术和天赋的ID声音事件魔数(Magic Numbers)


为Noita mods编写Lua脚本的基本信息和例子。请注意,脚本只是修改的一个组成部分,请务必阅读ECS-实体组件系统(Entity Component System)有关内容。

Lua脚本基础内容

init.lua

  • 初见最好的文件
  • 不需要覆盖或者修改任何内容,这些内容都只作用于你的mod。
  • 参见 模组修改基础知识

data/scripts/gun/gun.lua

  • 每一次使用法杖时都会被调用, 与引擎代码高度交织在一起。
  • 注意兼容性,如下所述

data/scripts/biomes/<biome_name>.lua

  • 在进入生物群落时被调用一次
  • 注意兼容性,如下所述

<LuaComponent>

  • 可以挂载你的任意代码的最佳与最常用的地方。
  • 大多数其他的东西,你可以在data/scripts/找到,实际上是通过这个组件在某个实体中定义的。
  • 见官方的 lua_api_documentation.txt 以了解如何通过该组件挂载不同行为。

以兼容的方式使用钩子函数

当处理游戏本身和其他MOD大量使用的普通脚本文件时,通过ModLuaFileAppend函数对其进行附加可能是一个好主意,而不是简单地通过data/路径覆盖它。

如果每个模组制作者都这样做,他们的代码会根据玩家的mod加载顺序被挨个强行覆盖,只留下最后加载的那版文件。

-- 任何文件都可以被任何文件所附加,gun.lua只是一个例子。
-- *但*这只能在init.lua内进行。
ModLuaFileAppend("data/scripts/gun/gun.lua", "mods/mymod/files/gun.lua")

Lua说明与提示

受限的库

一些默认的Lua库被限制,不能在mod文件中运行。一个不完整的受限库和函数的列表:

  • IO
  • OS
  • require

这些库的一些功能已经在Lua API中重新实现。

-- 你没法这样做
local file = require "/mods/MODNAME/files/somefile.lua"
-- 但是你可以这样
local file = dofile_once("/mods/MODNAME/files/somefile.lua")

-- 你没法这样做
local time = os.time()
-- 但是你可以这样
local year,month,day,hour,minute,second = GameGetDateAndTimeLocal()
local time = year .. month .. day .. hour .. minute .. second

因为没有IO库,在多局游戏间保存持久性数据要困难得多。存储持久数据的仅有两种方法是使用Flag或mod_settings文件。

脚本示例

获取当前实体

local entity = GetUpdatedEntityID()

“当前实体”是指通过<LuaComponent>(或其他类似触发器)运行脚本的实体。不过并非所有脚本都是由实体运行的,例如init.lua

在上面的代码片段中,获得的实体可以是玩家、魔杖、投射物或者其他任何东西,这取决于脚本的运行位置。这是获取当前运行的实体的最简单方法,因此值得一提。

注意:data/scripts/gun/gun.lua中这个函数会给你玩家实体。

获取玩家实体

内置的utility脚本会返回一个玩家实体列表,所以我们必须经过一个小步骤才能得到单个玩家实体。

简洁起见,下面的示例中省略了获取玩家实体的操作。许多钩子都已经能够获取玩家实体了,但这段代码可以留作备用,如果它们失效了没有返回玩家实体的话。

dofile_once("data/scripts/lib/utilities.lua")

function get_player()
  local players = get_players()
  if players then
    return players[1]
  end

  -- 当找不到玩家(例如玩家死亡)时
  return nil
end

local player = get_player()

获取当前手持魔杖

dofile_once("data/scripts/gun/procedural/gun_action_utils.lua")

-- 可能适用于任何带有Inventory2Component的实体,例如一些敌人
local wand = find_the_wand_held(player)

获取当前手持物品(包括魔杖)

function get_held_item(animal)
  local inv_comp = EntityGetFirstComponentIncludingDisabled(
    animal, "Inventory2Component"
  )

  -- 尽管这个组件应该永远存在,但是指不定会有人点炒饭
  -- (比如另一个模组瞎搞把它搞没了之类的)
  if not inv_comp then
    return nil
  end

  return ComponentGetValue2(inv_comp, "mActiveItem")
end

-- 应该返回一个数字ID
local wand = get_held_item(player)

简单地向物品栏中加入物品

-- 注意,玩家不是唯一具有物品栏的实体
function add_items_to_inventory(player, items)
  for _, path in ipairs(items) do
    local item = EntityLoad(path)
    if item then
      GamePickUpInventoryItem(player, item)
    else
      GamePrint("Error: Couldn't load the item ["..path.."]!")
    end
  end
end

function OnPlayerSpawned(player)
  local items = {
    "data/entities/items/pickup/thunderstone.xml",
  }
  add_items_to_inventory(player, items)
end

生成并启用天赋

-- 天赋系统有点复杂,所以使用现成的函数
dofile_once("data/scripts/perks/perk.lua")

local perk = perk_spawn(x, y, "PROTECTION_RADIOACTIVITY")

-- 如果你只是想在世界中生成天赋,就把这部分去掉
if perk then
  perk_pickup(perk, player, EntityGetName(perk), false, false)
end

生成其他大多数事物

-- 敌人
EntityLoad("data/entities/animals/duck.xml", x, y)

-- 黄金
EntityLoad("data/entities/items/pickup/goldnugget_200.xml", x, y)

只加载一次init.lua

即只在开始新游戏时才加载,加载保存的已有游戏时不会加载

local LOAD_KEY = "MYMOD_FIRST_LOAD_DONE"

function OnPlayerSpawned(player)
  if GlobalsGetValue(LOAD_KEY, "0") == "1" then
    return
  end
  GlobalsSetValue(LOAD_KEY, "1")

  -- 你其他的代码可以继续放在这里
end

通过Lua发射一个投射物

dofile_once("data/scripts/lib/utilities.lua")

-- 根据你想要的发射规则,在此定义投射物发射的位置
-- 以及投射物的速度

shoot_projectile(player, "mods/mymod/files/projectiles/supernuke.xml", from_x, from_y, vel_x, vel_y)

要注意的是,用GameShootProject()也可以完成此功能,但它需要几行设置,而这段代码中包含的utility函数已经帮你完成了这些设置。