一、添加模组科技树
1.1 调用
添加新科技树的原理是向“techtree”表中插入新的科技树,所以需要调用“techtree”
local TechTree = require("techtree")
1.2 修改科技树的生成方式
table.insert(TechTree.AVAILABLE_TECH, "SAKURA_TECH") --添加新科技树名称
local Create_old = TechTree.Create
TechTree.Create = function(t, ...)
local newt = Create_old(t, ...)
newt["SAKURA_TECH"] = newt["SAKURA_TECH"] or 0
return newt
end
1.3 三类等级
1.4及之后的步骤需要我们先了解并区分这三类等级:
1.3.1 制作等级
制作等级是配方制作时的需求水平,通常一个配方的制作等级只会需求一个科技等级。
1.3.2 解锁等级
解锁等级是科技站所能解锁的全部科技的水平,一个科技站可以解锁多个科技等级。(如枝江往事——奇特的构造体)
1.3.3 科技等级
科技等级是一种度量单位,他是制作等级与解锁等级之间的桥梁。
1.4 创建新制作等级
TECH.NONE.SAKURA_TECH = 0
TECH.SAKURA_TECH_ONE = { SAKURA_TECH = 1 }
-- TECH.ELECOURMALINE_TWO = { SAKURA_TECH = 2 }
-- 解锁等级中间隔一个等级,能使当前无法解锁的科技不会显示出来
TECH.SAKURA_TECH_THREE = { SAKURA_TECH = 3 }
此处,
TECH.SAKURA_TECH_ONE即为“AddRecipe2”中所使用的制作等级;
{ SAKURA_TECH = 1 }即为制作等级的等级标志,与后面的解锁等级的等级标志为同一数据,用于将制作等级与解锁等级对应起来。
注意:如果modmain函数中没有下面的神奇咒语,则这里的TECH不能直接使用,而需要调用GLOBLE:
-- 神奇咒语
GLOBAL.setmetatable(env, {__index = function(t, k) return GLOBAL.rawget(GLOBAL, k ) end})
-- 如果没有神奇咒语,则需要下面的语句才能使用TECH
local _G = GLOBLE
_G.TECH.NONE.SAKURA_TECH = 0
--或者直接
GLOBLE.TECH.NONE.SAKURA_TECH = 0
1.4 创建新解锁等级
-- TUNING.PROTOTYPER_TREES中存储的是科技站所能解锁的科技等级,这里先将所有科技站所能解锁的新科技等级都初始化为0
for _, v in pairs(TUNING.PROTOTYPER_TREES) do
v.SAKURA_TECH = 0
end
TUNING.PROTOTYPER_TREES.SAKURA_TECH_ONE = TechTree.Create({ SAKURA_TECH = 1 })
TUNING.PROTOTYPER_TREES.SAKURA_TECH_THREE = TechTree.Create({ SAKURA_TECH = 3 })
如果科技站的解锁等级为TUNING.PROTOTYPER_TREES.SAKURA_TECH_ONE,则这个科技站能解锁的科技等级为{ SAKURA_TECH = 1 }。
这个表可以包含多个科技等级,从而实现一个科技站可以解锁多个科技等级,如:
TUNING.PROTOTYPER_TREES.SAKURA_TECH_THREE = TechTree.Create({
SAKURA_TECH = 1,
SAKURA_TECH = 3
})
当我们对科技站的需求不是那么复杂时,完全可以仅用一个科技等级。
1.5 修改不需要新科技就能解锁的配方的科技需求
--如果v.level.SAKURA_TECH == nil,则说明该配方无需新科技就能解锁,将科技等级值设置为0
for _, v in pairs(AllRecipes) do
if v.level.SAKURA_TECH == nil then
v.level.SAKURA_TECH = 0
end
end
注意:这段代码务必在新增需要新科技的配方之前调用,避免原本需要新科技的配方的科技等级需求归0。
1.6 将未解锁的配方显示在制作栏
if not TheNet:IsDedicated() then
local craftingmenu_widget = require "widgets/redux/craftingmenu_widget"
local ApplyFilters_old = craftingmenu_widget.ApplyFilters
craftingmenu_widget.ApplyFilters = function(self, ...)
if
(self.current_filter_name == "SAKURA_BOOK") and
CRAFTING_FILTERS[self.current_filter_name] ~= nil
then
self.filtered_recipes = {}
local filter_recipes = FunctionOrValue(CRAFTING_FILTERS[self.current_filter_name].default_sort_values) or nil
if filter_recipes == nil then
return ApplyFilters_old(self, ...)
end
for i, recipe_name in metaipairs(self.sort_class) do
local data = self.crafting_hud.valid_recipes[recipe_name]
if data and filter_recipes[recipe_name] ~= nil then
table.insert(self.filtered_recipes, data)
end
end
if self.crafting_hud:IsCraftingOpen() then
self:UpdateRecipeGrid(self.focus and not TheFrontEnd.tracking_mouse)
else
self.recipe_grid.dirty = true
end
else
return ApplyFilters_old(self, ...)
end
end
end
将上面的“SAKURA_BOOK”改为需要显示的过滤器,也就是制作栏名称即可。
二、添加原型站/制作站
2.1 prefabs文件
在原型站/制作站实体的代码中加入原型组件,使其具有解锁等级:
inst:AddComponent("prototyper")
inst.components.prototyper.onturnon = onturnon --打开时的函数
inst.components.prototyper.onturnoff = onturnoff --关闭时的函数
inst.components.prototyper.onactivate = onactivate --使用时的函数
inst.components.prototyper.trees = TUNING.PROTOTYPER_TREES.SAKURA_TECH_ONE --设置解锁等级
2.2 modmain文件
2.1仅设置了原型站/制作站的解锁等级,但还不能使用。想要使用,就要为实体添加靠近后解锁科技功能:
AddPrototyperDef("sakura_book", --第一个参数是指玩家靠近时会解锁科技的prefab名
{
icon_atlas = "images/sakura_book.xml", --科技栏图标资源
icon_image = "sakura_book.tex",
is_crafting_station = true, --是否为制作站
action_str = "SAKURA_BOOK", --建造时显示的文字
filter_text = "小樱的魔法书", --鼠标悬浮在制作栏(过滤器)时的文字
})
设置is_crafting_station = true时,该机器为制作站,左上角会出现相应的制作栏;
设置is_crafting_station = false时,该机器为原型站,左上角不会出现相应的制作栏。
此时打开的制作栏会自动显示:
1.需要该制作站科技才能解锁
2.只能在制作站附近制作
的配方,当且仅当配方同时满足上面两个条件时,才会出现在这个制作栏。
三、添加制作栏(过滤器)
如果想要平常就能找到这一配方,就需要添加一个过滤器,也就是我们常说的“制作栏”:
AddRecipeFilter({--添加自定义的过滤器(即新的制作栏)
name = "SAKURA_BOOK", --独一无二的过滤器名
atlas = "images/sakura_book.xml", --原始贴图54x54像素,64x64的也会默认缩放成54x54
image = "sakura_book.tex",
custom_pos = true
})
STRINGS.UI.CRAFTING_FILTERS.SAKURA_BOOK ="小樱的魔法书"
AddRecipeFilter中的常用变量说明如下:
name
(string): 过滤器的ID。主要用于两处,一是STRINGS.UI.CRAFTING_FILTERS[name]
。赋值给出在UI界面上显示的过滤器名字,二是在其它API使用过滤器作为参数时用于指代。atlas
(string 或 function): 图标的图集,可以是字符串或函数。image
(string 或 function): 显示在制作菜单中的图标,可以是字符串或函数。(可选) image_size
(table): 自定义图像尺寸,默认64。(可选) custom_pos
(table): 自定义的过滤器位置,默认为false。 如果为 true,则过滤器图标不会被添加到网格中,而是把这个分类下的物品都放在mod物品分类下。
此时制作栏内还没有任何配方,若想添加配方到这个制作栏,有以下两种方法:
3.1 添加已有配方到制作栏
--第一个参数为配方名称,第二个参数为过滤器名称
AddRecipeToFilter("sakura_card","SAKURA_BOOK")
3.2 添加新配方到制作栏
AddRecipe2(
"sakura_pinkcard", --配方名称
--配方(如果使用mod物品则需要注册图片)
{Ingredient("pink_gem", 1,"images/pink_gem.xml",nil,"pink_gem.tex"),
Ingredient("sakura_card", 1,"images/sakura_card.xml",nil,"sakura_card.tex")},
TECH.SAKURA_TECH_ONE, --所需科技
{
nounlock = true, --是否可解锁,即制作一次后永久解锁,true为不可解锁,false为可解锁
numtogive = 2 --一次制作的数量,默认为1
atlas="images/sakura_pinkcard.xml", --配方图
image="sakura_pinkcard.tex",
product="pink_gem" --产品,默认产品即为配方名称
},
{"WEAPONS","SAKURA_BOOK"} --添加到过滤器(制作栏)
)
注意:如果在添加制作栏之前添加了使用该制作栏的配方,则配方中添加的制作栏无效
四、全部代码
上面除为原型站/制作站实体添加原型站/制作站组件的代码应添加到对应实体中,其余代码均应严格按顺序添加到modmain中。
如果想使modmain界面简捷,使用“modimport(“scrips/文件名”)”将代码移动到scrips文件夹下的“文件名.lua”中,可按喜好将代码转移到多个文件中,但一定要保证调用顺序不变!
所有modmain代码如下:
local TechTree = require("techtree")
--------------------------------------------------------------------------
--[[ 修改默认的科技树生成方式 ]]
--------------------------------------------------------------------------
table.insert(TechTree.AVAILABLE_TECH, "SAKURA_TECH") --其实就是加个自己的科技树名称
local Create_old = TechTree.Create
TechTree.Create = function(t, ...)
local newt = Create_old(t, ...)
newt["SAKURA_TECH"] = newt["SAKURA_TECH"] or 0
return newt
end
--------------------------------------------------------------------------
--[[ 制作等级 ]]
--------------------------------------------------------------------------
TECH.NONE.SAKURA_TECH = 0
TECH.SAKURA_TECH_ONE = { SAKURA_TECH = 1 }
-- _G.TECH.ELECOURMALINE_TWO = { SAKURA_TECH = 2 } --解锁等级中间隔一个等级,能使得没法解锁时,不会显示出来
TECH.SAKURA_TECH_THREE = { SAKURA_TECH = 3 }
--------------------------------------------------------------------------
--[[ 解锁等级 ]]
--------------------------------------------------------------------------
for _, v in pairs(TUNING.PROTOTYPER_TREES) do
v.SAKURA_TECH = 0
end
--ELECOURMALINE_ONE可以改成任意的名字,这里和TECH.ELECOURMALINE_ONE名字相同只是懒得改了
TUNING.PROTOTYPER_TREES.SAKURA_TECH_ONE = TechTree.Create({ SAKURA_TECH = 1 })
TUNING.PROTOTYPER_TREES.SAKURA_TECH_THREE = TechTree.Create({ SAKURA_TECH = 3 })
--------------------------------------------------------------------------
--[[ 修改全部制作配方,对缺失的值进行补充 ]]
--------------------------------------------------------------------------
for _, v in pairs(AllRecipes) do
if v.level.SAKURA_TECH == nil then
v.level.SAKURA_TECH = 0
end
end
--------------------------------------------------------------------------
--[[ 显示不能解锁的配方 ]]
--------------------------------------------------------------------------
if not TheNet:IsDedicated() then
local craftingmenu_widget = require "widgets/redux/craftingmenu_widget"
local ApplyFilters_old = craftingmenu_widget.ApplyFilters
craftingmenu_widget.ApplyFilters = function(self, ...)
if
(self.current_filter_name == "SAKURA_BOOK") and
CRAFTING_FILTERS[self.current_filter_name] ~= nil
then
self.filtered_recipes = {}
local filter_recipes = FunctionOrValue(CRAFTING_FILTERS[self.current_filter_name].default_sort_values) or nil
if filter_recipes == nil then
return ApplyFilters_old(self, ...)
end
for i, recipe_name in metaipairs(self.sort_class) do
local data = self.crafting_hud.valid_recipes[recipe_name]
if data and filter_recipes[recipe_name] ~= nil then
table.insert(self.filtered_recipes, data)
end
end
if self.crafting_hud:IsCraftingOpen() then
self:UpdateRecipeGrid(self.focus and not TheFrontEnd.tracking_mouse)
else
self.recipe_grid.dirty = true
end
else
return ApplyFilters_old(self, ...)
end
end
end
--------------------------------------------------------------------------
--[[ 添加制作站 ]]
--------------------------------------------------------------------------
AddPrototyperDef("sakura_book", { --第一个参数是指玩家靠近时会解锁科技的prefab名
icon_atlas = "images/sakura_book.xml", icon_image = "sakura_book.tex",
is_crafting_station = true,
action_str = "SAKURA_BOOK", --台词已在语言文件中
filter_text = "小樱的魔法书",
})
--------------------------------------------------------------------------
--[[ 添加配方 ]]
--------------------------------------------------------------------------
AddRecipe2(
"sakura_pinkcard",
{Ingredient("pink_gem", 1,"images/pink_gem.xml",nil,"pink_gem.tex"),
Ingredient("sakura_card", 1,"images/sakura_card.xml",nil,"sakura_card.tex")},
TECH.SAKURA_TECH_ONE,
{
nounlock = true,
atlas="images/sakura_pinkcard.xml",
image="sakura_pinkcard.tex",
product="pink_gem"
},
{"WEAPONS","SAKURA_BOOK"}
)