0开始做一把武器


提供一个模板:
链接:https://pan.quark.cn/s/fbc0b43aa287 提取码:nFbt
这个模板包含了基础框架,一把武器和汉化部分.


  1. 利用模板给出的框架,进行简单地替换,做出年轻人的第一把刀
  2. 给新武器添加配方,使玩家在游戏内可以获得
  3. 写一个最简单的component,给武器添加升级系统
  4. 给武器添加暴击系统
  5. 给武器添加击杀怪物回复血量
  6. 给武器添加击晕怪物能力

  1. 利用模板给出的框架,进行简单地替换,来做出年轻人的第一把刀

将模板丢到游戏目录mods文件夹内,开始我们的第一步
图片制作分三部分:
武器被手持: \exported\swap_temp_myfirstsword\
武器在地面: \exported\ground_temp_myfirstsword\
武器在物品栏: \images\inventoryimages\xxx.tex

把anim文件夹里原来的两个zip删掉,我们先做手持部分(为了保证武器正确的被握在手部,这一部分我们用替换):
首先我们确定武器名字,例如:mybat
将exported目录下的swap_temp_myfirstsword更名为swap_mybat
将exported\swap_mybat目录下的文件夹swap_temp_myfirstsword更名为swap_mybat
将exported\swap_mybat\swap_mybat\目录下的图片文件名中的temp_myfirstsword改成mybat
将exported\swap_mybat目录下scml文件更名为swap_mybat.scml并用类似notepad++的软件编辑它,搜索所有temp_myfirstsword,全部替换为mybat
将exported\swap_mybat\swap_mybat\swap_mybat-0.png用PS打开,将事先准备好的武器图片丢进去调整好手持位置,再删掉原图保存一下即可(图层大小请勿修改)

地面图片就不用那么讲究了:
将exported\下的ground_temp_myfirstsword更名为ground_mybat,文件夹内东西删掉,把事先准备的图片丢进去
打开spriter,ctrl+N新建项目,将目录粘贴好(…\steam\steamapps\common\Don't Starve Together\mods\mybat\exported\ground_mybat</span>),
将右上角出现的图片拖进中间工作区域,稍微调整下位置到十字线偏下,在拖动图片上的红点到刀柄位置
将右下动画窗格的entity_000改成武器名字mybat,NewAnimation改成idle(这是约定俗成的东西)
保存,文件名mybat.scml

物品栏图片:
打开\images\inventoryimages\
将xml文件更名为mybat.xml,打开将里面的temp_myfirstsword替换成mybat,保存
ps打开png文件,将图片放进去,调整好保存
打开textool,勾上Pre-multiply Alpha,将png转换成tex,记得更名为mybat.tex

到此为止图片部分全部结束

代码部分就非常简单了(全是替换,会就别看了):
将\scripts\prefabs\,目录下的lua文件更名,比如叫study_mybat,打开将里面所有temp_myfirstsword替换成mybat保存
打开modmain,将PrefabFiles = {}里面的temp_myfirstsword(这个就是上面prefabs文件夹下的文件名)替换成study_mybat保存

下面我们还要做一个汉化部分:
打开modmain,替换

1TUNING.CONFIG_TEMP_MYFIRSTSWORD_LANGUAGE = GetModConfigData("temp_myfs_language")
2modimport("scripts/util/temp_myfirstsword_chs.lua")
3modimport("scripts/util/temp_myfirstsword_en.lua")

1TUNING.CONFIG_MYBAT_LANGUAGE = GetModConfigData("mybat_language")
2modimport("scripts/util/mybat_chs.lua")
3modimport("scripts/util/mybat_en.lua")

再把
\scripts\util目录下的两个文件分别更名为mybat_chs.lua和mybat_en.lua
再分别打开这两个文件:
将TUNING.CONFIG_TEMP_MYFIRSTSWORD_LANGUAGE改成TUNING.CONFIG_MYBAT_LANGUAGE
将TEMP_MYFIRSTSWORD改成MYBAT

最后打开modinfo:
temp_myfs_language替换为mybat_language

(简单讲下上面这一大串: modimport可以给modmain添加文件,一个chs(汉化)一个en分开方便编辑,GetModConfigData是获取modinfo的配置信息,将它放到tuning表里,就可以用来判断用户选的是en还是chs了)
这代码替换部分看着很麻烦,让大家把名字全改了,主要目的是告诉大家抄的时候,最起码把名字改一改
而不是抄完了之后,mod做好上传工坊,发个简介:本mod可能与xxx mod不兼容.
维护社区环境,从我做起

最后打开游戏,等待两个动画文件自动生成完毕就ok了
控制台c_give("mybat")获取


  1. 给新武器添加配方,使玩家在游戏内可以获得
    我们在\scripts\util目录下新建一个mybat_recipes.lua,方便日后添加其他配方
    别忘了在modmain中添加:

modimport("scripts/util/mybat_recipes.lua")

为制作栏添加图片:
在images\中添加一个128x128的"mybattab.tex"图片,再拷一个xml过来就ok了

打开mybat_recipes.lua:

 1local Ingredient = GLOBAL.Ingredient
2local TECH = GLOBAL.TECH
3local RECIPETABS = GLOBAL.RECIPETABS
4
5RECIPETABS.MYBAT_TAB = {str = "MYBAT_TAB"sort = 999, icon = "mybattab.tex", icon_atlas = "images/mybattab.xml"}
6
7local mybat_recipe = AddRecipe("mybat",
8{GLOBAL.Ingredient("log"2), GLOBAL.Ingredient("goldnugget"1), GLOBAL.Ingredient("rope"1)},
9RECIPETABS.MYBAT_TAB, TECH.SCIENCE_ONE,
10nilnilnil1nil,
11"images/inventoryimages/mybat.xml""mybat.tex")


  1. 写一个最简单的component,给武器添加升级系统
    升级系统多种多样,比如散步升级,获得物品升级,打怪升级等,还有像经验条这种东西,需要当前经验条升满才升级.
    我们这里做一个非常简单的每获得一个黄金或者具有黄金价值的物品,升xxx级,每一级增加武器伤害.
    新建scripts\components\mybatlvlup.lua:
 1local mybatlvlup = Class(function(self, inst)
2    self.inst = inst
3
4    self.level_mybat = 0 --武器基础等级
5    self.updmg = 0 --面板增加值
6end,
7nil,
8{
9})
10----save&load
11function mybatlvlup:OnSave()
12    local data = {
13        level_mybat = self.level_mybat,
14        updmg = self.updmg,
15    }
16    return data
17end
18function mybatlvlup:OnLoad(data)
19    self.level_mybat = data.level_mybat or 0
20    self.updmg = data.updmg or 0
21end
22----
23function mybatlvlup:DoDelta_level_mybat(delta)
24    self.level_mybat = self.level_mybat + delta
25end
26function mybatlvlup:calcupdmg() --设置伤害计算公式
27    self.updmg = math.floor(5*math.exp(math.log10(self.level_mybat)))
28end
29----
30return mybatlvlup

上面这就是一个最简单的component模板,看一下就懂,不逐句解释了.

下面我们在mybat的fn()下面为它添加这个成分:

inst:AddComponent("mybatlvlup") --添加新成分
inst:AddComponent("trader") --添加trader使其能接受可交易物品
inst.components.trader:SetAbleToAcceptTest(itemstype)
inst.components.trader.onaccept = OnGetItems
inst:DoTaskInTime(0, function()
applylevel(inst)
end)

看下itemstype,OnGetItems,applylevel怎么写:

 1local function applylevel(inst) --设置武器面板的函数
2    inst.components.mybatlvlup:calcupdmg()
3    inst.components.weapon:SetDamage(31+inst.components.mybatlvlup.updmg)
4end
5
6local function itemstype(inst, item)
7    if item.prefab == "goldnugget" or item.components.tradable.goldvalue > 0 then
8        return true --物品是黄金或黄金价值大于0时才能接受
9    end
10    return false
11end
12
13local function OnGetItems(inst, giver, item)
14    local level_mybat = inst.components.mybatlvlup.level_mybat
15    if item.prefab == "goldnugget" then
16        inst.components.mybatlvlup:DoDelta_level_mybat(1)
17        applylevel(inst)
18    elseif item.components.tradable.goldvalue > 0 then
19        local igv = item.components.tradable.goldvalue
20        inst.components.mybatlvlup:DoDelta_level_mybat(igv)
21        applylevel(inst)
22    end
23end


  1. 给武器添加暴击系统
    设定模板:有基础暴击率,可通过接受xx物品提升,到xx%封顶.
    有基础暴击乘数,可通过接受xx物品提升,到xx倍率封顶.
    设定:基础暴击率5%,每10个蜂蜜提升1%暴击率,暴击率最高30%
    基础暴击伤害乘数1.2,可通过接受龙鳞提升,无上限. (可以自己添加一些怪物的掉落物,来让这个提升过程看起来更合理)

scripts\components\mybatlvlup.lua:

 1local mybatlvlup = Class(function(self, inst)
2    self.inst = inst
3
4    self.level_mybat = 0
5    self.updmg = 0 
6
7    self.cc_basic = 0
8    self.cc = 5 --[5,30] 暴击率
9
10    self.cdm_basic = 0
11    self.cdm = 1.2 --爆伤乘数
12end,
13nil,
14{
15})
16----save&load
17function mybatlvlup:OnSave()
18    local data = {
19        level_mybat = self.level_mybat,
20        updmg = self.updmg,
21        cc_basic = self.cc_basic,
22        cc = self.cc,
23        cdm_basic = self.cdm_basic,
24        cdm = self.cdm,
25    }
26    return data
27end
28function mybatlvlup:OnLoad(data)
29    self.level_mybat = data.level_mybat or 0
30    self.updmg = data.updmg or 0
31    self.cc_basic = data.cc_basic or 0
32    self.cc = data.cc or 5
33    self.cdm_basic = data.cdm_basic or 0
34    self.cdm = data.cdm or 1.2
35end
36----
37function mybatlvlup:DoDelta_level_mybat(delta)
38    self.level_mybat = self.level_mybat + delta
39end
40function mybatlvlup:calcupdmg()
41    self.updmg = math.floor(5*math.exp(math.log10(self.level_mybat)))
42end
43
44function mybatlvlup:DoDelta_cc_basic(delta)
45    self.cc_basic = self.cc_basic + delta
46end
47function mybatlvlup:calccc() 
48    self.cc = 5 + math.floor(self.cc_basic/10--每10个cc_basic增加1%暴击率
49end
50
51function mybatlvlup:DoDelta_cdm_basic(delta)
52    self.cdm_basic = self.cdm_basic + delta
53end
54function mybatlvlup:calccdm() --爆伤乘数提升公式,用的是log函数,这样提升空间没有上限,但是越往后越难升
55    self.cdm = math.floor(((math.log10(self.cdm_basic+1)/math.log10(5))+1)*10)/10
56end
57----
58function mybatlvlup:ch(attacker,target,max)
59    if math.random(0,max) <= self.cc then --随机一个0到100的数,小于cc则暴击
60        local wp_panel = 31 + self.updmg
61        local fin_dmg = wp_panel * self.cdm
62        local bonus_dmg = fin_dmg - wp_panel
63        target.components.combat:GetAttacked(attacker, bonus_dmg) 
64        --[[这一段我们是要放到武器攻击onattack里触发的,所以GetAttacked可以看成追加伤害
65        追加伤害 = 武器面板*爆伤乘数 - 武器面板
66        下面添加了一个暴击音效和动画
67        ]]

68        if attacker.SoundEmitter and attacker.components.talker then
69            attacker.SoundEmitter:PlaySound("dontstarve/common/whip_large")
70            attacker.components.talker:Say("Critical Hit!".." \n ".." \n ".." \n ")
71        end
72        local chfx = SpawnPrefab("impact")
73        chfx.Transform:SetScale(math.random(1,5), math.random(1,5), math.random(1,5))
74        chfx.Transform:SetPosition(target.Transform:GetWorldPosition())
75    end
76end
77----
78return mybatlvlup

预制物这边很简单:

 1local function itemstype(inst, item)
2    if item.prefab == "goldnugget" or item.components.tradable.goldvalue > 0 then
3        return true
4    end
5    if item.prefab == "honey" and inst.components.mybatlvlup.cc_basic < 250 then return true end
6    if item.prefab == "dragon_scales" then return true end
7    return false
8end
9
10local function OnGetItems(inst, giver, item)
11    local level_mybat = inst.components.mybatlvlup.level_mybat
12    if item.prefab == "goldnugget" then
13        inst.components.mybatlvlup:DoDelta_level_mybat(1)
14        applylevel(inst)
15    elseif item.components.tradable.goldvalue > 0 and item.prefab ~= "honey" and item.prefab ~= "dragon_scales" then
16        local igv = item.components.tradable.goldvalue
17        inst.components.mybatlvlup:DoDelta_level_mybat(igv)
18        applylevel(inst)
19    end
20
21    if item.prefab == "honey" then
22        if inst.components.mybatlvlup.cc_basic < 250 then
23            inst.components.mybatlvlup:DoDelta_cc_basic(1)
24            inst.components.mybatlvlup:calccc()
25            if giver.components and giver.components.talker then
26                giver.components.talker:Say("Critical Chance: "..inst.components.mybatlvlup.cc.."%",2,true)
27            end
28        end
29    end
30
31    if item.prefab == "dragon_scales" then
32        inst.components.mybatlvlup:DoDelta_cdm_basic(5)
33        inst.components.mybatlvlup:calccdm()
34        if giver.components and giver.components.talker then
35            giver.components.talker:Say("Critical Dmg Mult: "..inst.components.mybatlvlup.cdm,2,true)
36        end
37    end
38end
39
40inst.components.weapon.onattack = onattack --别忘了加这句
41local function onattack(inst, attacker, target)
42    inst.components.mybatlvlup:ch(attacker,target,100)
43end

由于"dragon_scales"没有可交易component,我们要在modmain里面添加:

 1--trade
2local mybatcouldtradetab = {
3   "dragon_scales",
4}
5local function couldtrade( inst )
6    if inst.components and inst.components.tradable then
7    else
8           inst:AddComponent("tradable")
9       end
10end
11for k,v in pairs(mybatcouldtradetab) do
12   AddPrefabPostInit(v, couldtrade) 
13end


  1. 给武器添加击杀怪物回复血量
    给武器添加一个可解锁的击杀回复能力,例如给武器一个物品"x"来解锁.
 1local function onkillmybat(inst, data)
2    local victim = data.victim
3    local victim_pos = victim:GetPosition()
4    local killregenmul = 0.01    
5    ----killregen
6    if victim.components.health ~= nil then
7        if inst:HasTag("mybat_allowmekillregen"then --如果持有者有Tag,则才能击杀回复
8            local victim_hp = math.ceil(victim.components.health.maxhealth)
9            local killregen = math.ceil(victim_hp*killregenmul)
10            if killregen >= 1 then
11                inst.components.health:DoDelta(killregen) --击杀回复怪物血量1%的hp
12            else
13                inst.components.health:DoDelta(1)
14            end
15        end
16    end
17end
18local function onequip(inst, owner)
19    owner.AnimState:OverrideSymbol("swap_object""swap_mybat""swap_mybat")
20    owner.AnimState:Show("ARM_carry")
21    owner.AnimState:Hide("ARM_normal")
22    if inst:HasTag("mybat_allowkillregen"then --装备该武器时判断其是否已解锁能力,是则给持有者一个Tag,并让持有者监听"killed"击杀事件
23        if not owner:HasTag("mybat_allowmekillregen"then
24            owner:AddTag("mybat_allowmekillregen")
25        end
26        owner:ListenForEvent("killed", onkillmybat)
27    end
28end
29
30local function onunequip(inst, owner)
31    owner.AnimState:Hide("ARM_carry")
32    owner.AnimState:Show("ARM_normal")
33    if owner:HasTag("mybat_allowmekillregen"then --卸除该武器,移除持有者的Tag,移除监听的事件函数
34        owner:RemoveTag("mybat_allowmekillregen")
35    end
36    owner:RemoveEventCallback("killed", onkillmybat)
37end
38
39local function itemstype(inst, item)
40    if item.prefab == "x" and not inst:HasTag("mybat_allowkillregen"then
41        return true
42    end 
43    return false
44end
45
46local function OnGetItems(inst, giver, item)
47    if item.prefab == "x" then
48        inst:AddTag("mybat_allowkillregen")
49        local handswp = giver.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
50        if giver.components and giver.components.talker then
51            giver.components.talker:Say("unlock Kill Regen",3,true)
52        end
53        if handswp and handswp:HasTag("mybat_allowkillregen"then
54            giver:AddTag("mybat_allowmekillregen")
55            giver:ListenForEvent("killed", onkillmybat)
56        end
57    end
58    --[[这里原本代码是这样写的:
59    if item.prefab == "x" then
60        inst:AddTag("mybat_allowkillregen")
61        giver:AddTag("mybat_allowmekillregen")
62        giver:ListenForEvent("killed", onkillmybat)
63    end
64    但是这样写有个问题:
65    如果把mybat先卸下,装备另一把武器,那么给mybat一个"x"后,玩家依旧会解锁击杀回复能力,并直到下次装备mybat并卸下之前,能力都不会消失
66    所以修改后的代码:
67    获取一次玩家的手部物品,如果手部物品是有击杀恢复Tag的"mybat",那么才给玩家解锁该能力
68    ]]

69end

再加个saveload就大功告成了:

 1inst.OnSave = onsave
2inst.OnLoad = onload
3local function onsave(inst, data)
4    if inst:HasTag("mybat_allowkillregen"then
5        data.mybat_allowkillregen = true
6    end
7end
8local function onload( inst,data )
9    if data and data.mybat_allowkillregen then
10        inst:AddTag("mybat_allowkillregen")
11    end
12end


  1. 给武器添加击晕怪物能力
    scripts\components\mybatlvlup.lua:
 1function mybatlvlup:stun(target,attacker)
2    if target.brain and target.components.combat and target.components.locomotor and not target:HasTag("mybat_stun"and math.random(1,100) <= self.stun then
3        target:AddTag("mybat_stun")
4
5        SpawnPrefab("lightning_rod_fx").Transform:SetPosition(target.Transform:GetWorldPosition())
6
7        target.components.locomotor:Stop()
8        target.brain:Stop()
9
10        target:DoTaskInTime(2,function(target)
11            target.brain:Start()
12            target:RemoveTag("mybat_stun")
13            end)
14    end
15end