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函數已經幫你完成了這些設置。