Jump to content

Recommended Posts

Hello there wonderful forum! After month of not really doing any modding, I have returned! 

Anyway. I was wondering if it would be possible to create a few of the smaller musical instruments in game for my custom character.

the main goal is to create an item (let's say it's a ukulele, as that is the one I want the most) that when used, it plays a sound, and something happens. So basicly a pan flute but with a texture and animation depending on the item.

is this posible for me to do? I saw a few posts related to animating with spriter being hard, so if I can't do custom animations, at the very least could I make an instrument (harmonica?) by modifying the code of the pan flute to suit my needs?

I recommend modifying the texture of the panflute, and then copying + modifying the code of the panflute. Start small and keep testing to make sure everything works as intended (start by merely changing the name).

If you get that to work, you might want to consider playing around with Spriter.

Edited by Joachim

Just trying to think of existing animations that might make sense for a string instrument... you might be able to use the animation for the one-man-band? It does involve some hand movements and foot-tapping. It would probably be pretty tricky to position the instrument in it, though.

Edited by rezecib

Hello again! Due to the related topic, instead of making a new entire post for this question, i'm just going to add to this conversation

The instrument project is going well, I have successfully added not one, NOT THREE, But TWO whole new items, as of now, they are nearly direct copies of  the pan flute and the beefalo horn.

I got them to be craftable in their own unique way, and they lose durability at different rates than their original counterparts.

My question is this... I want these items to do separate things, but for the sake of simplicity, i will only ask about the pan flute. I want this item to put everything around it to sleep, but if it puts a player to sleep, it gives them similar effect to using a bedroll, but without the effect of using hunger.

So basicly i am attempting to make this flute:

  1. do the pan flute action (put everything to sleep around it)
  2. Put players to sleep bedroll style (raising sanity, but lowering hunger)
  3. Remove the lowering hunger part of the bedroll sleep

Since it is a copy of the panflute, number 1 is basically finished, so i need some help with the other 2.

Thanks in advance! and sorry if this is a nuisance to anyone.

I think in local function onsleeptick(inst, sleeper) you should remove

    if sleeper.components.hunger ~= nil then
        sleeper.components.hunger:DoDelta(TUNING.SLEEP_HUNGER_PER_TICK, true, true)
        isstarving = sleeper.components.hunger:IsStarving()
    end


As for uses:

    inst:AddComponent("finiteuses")
    inst.components.finiteuses:SetConsumption(ACTIONS.SLEEPIN, 1)
    inst.components.finiteuses:SetMaxUses(20)
    inst.components.finiteuses:SetUses(20)

 

48 minutes ago, Zer000 said:

I think in local function onsleeptick(inst, sleeper) you should remove

    if sleeper.components.hunger ~= nil then
        sleeper.components.hunger:DoDelta(TUNING.SLEEP_HUNGER_PER_TICK, true, true)
        isstarving = sleeper.components.hunger:IsStarving()
    end


As for uses:

    inst:AddComponent("finiteuses")
    inst.components.finiteuses:SetConsumption(ACTIONS.SLEEPIN, 1)
    inst.components.finiteuses:SetMaxUses(20)
    inst.components.finiteuses:SetUses(20)

 

I'm not exactly sure where to put the first bit. here is the code i have for my item

Spoiler

local assets =
{
    Asset("ANIM", "anim/august_flute.zip"),
    
    Asset("ATLAS", "images/inventoryimages/august_flute.xml"),
    Asset("IMAGE", "images/inventoryimages/august_flute.tex"),
}

local function HearPanFlute(inst, musician, instrument)
    if inst ~= musician and
        (TheNet:GetPVPEnabled() or not inst:HasTag("player")) and
        not (inst.components.freezable ~= nil and inst.components.freezable:IsFrozen()) and
        not (inst.components.pinnable ~= nil and inst.components.pinnable:IsStuck()) then
        if inst.components.sleeper ~= nil then
            inst.components.sleeper:AddSleepiness(10, TUNING.PANFLUTE_SLEEPTIME)
        elseif inst.components.grogginess ~= nil then
            inst.components.grogginess:AddGrogginess(10, TUNING.PANFLUTE_SLEEPTIME)
        else
            inst:PushEvent("knockedout")
        end
    end
end

local function fn()
    local inst = CreateEntity()
     local trans = inst.entity:AddTransform()
    local anim = inst.entity:AddAnimState()
    
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst:AddTag("flute")
    inst:AddTag("august_flute")
    
    inst.AnimState:SetBank("pan_flute")
    inst.AnimState:SetBuild("august_flute")
    inst.AnimState:PlayAnimation("idle")

    if not TheWorld.ismastersim then
        return inst
    end
    
    inst.entity:SetPristine()
    
    inst:AddComponent("inspectable")
    inst:AddComponent("instrument")
    inst.components.instrument.range = TUNING.PANFLUTE_SLEEPRANGE
    inst.components.instrument:SetOnHeardFn(HearPanFlute)

    inst:AddComponent("tool")
    inst.components.tool:SetAction(ACTIONS.PLAY)

    inst:AddComponent("finiteuses")
    inst.components.finiteuses:SetMaxUses(TUNING.PANFLUTE_USES)
    inst.components.finiteuses:SetUses(TUNING.PANFLUTE_USES)
    inst.components.finiteuses:SetOnFinished(inst.Remove)
    inst.components.finiteuses:SetConsumption(ACTIONS.PLAY, 2.5)
     
    
    
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.imagename = "august_flute"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/august_flute.xml"
    
    
    MakeHauntableLaunch(inst)
    AddHauntableCustomReaction(inst, function(inst, haunter)
        if math.random() <= TUNING.HAUNT_CHANCE_HALF then
            if inst.components.finiteuses then
                inst.components.finiteuses:Use(1)
                inst.components.hauntable.hauntvalue = TUNING.HAUNT_MEDIUM
                return true
            end
        end
        return false
    end, true, false, true)

    return inst
end

return Prefab("common/inventory/august_flute", fn, assets, prefabs)

As for the second bit, should i replace the uses part with yours?

24 minutes ago, Augustusc said:

As for the second bit, should i replace the uses part with yours?

No, this is just a way to configure uses..But it looks like you know how to change them already.Maybe you only need to add   inst.components.finiteuses:SetConsumption(ACTIONS.SLEEPIN, 1)

As for sleeping function, you can check bedroll lua and add lines to your prefab_name.lua
Just add lines about sleeping after assets

Starting with local function wakeuptest(inst, phase)
Ending with local function onuse_straw(inst, sleeper)
    sleeper.AnimState:OverrideSymbol("swap_bedroll", "swap_bedroll_straw", "bedroll_straw")
end

And don't forget to add

    inst:AddComponent("sleepingbag")
    inst.components.sleepingbag.onsleep = onsleep
    inst.components.sleepingbag.onwake = onwake

after 

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

Spoiler

I don't really sure if it will help, but it should do something you want

 

26 minutes ago, Zer000 said:

No, this is just a way to configure uses..But it looks like you know how to change them already.Maybe you only need to add   inst.components.finiteuses:SetConsumption(ACTIONS.SLEEPIN, 1)

As for sleeping function, you can check bedroll lua and add lines to your prefab_name.lua
Just add lines about sleeping after assets

Starting with local function wakeuptest(inst, phase)
Ending with local function onuse_straw(inst, sleeper)
    sleeper.AnimState:OverrideSymbol("swap_bedroll", "swap_bedroll_straw", "bedroll_straw")
end

And don't forget to add

    inst:AddComponent("sleepingbag")
    inst.components.sleepingbag.onsleep = onsleep
    inst.components.sleepingbag.onwake = onwake

after 

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

  Reveal hidden contents

I don't really sure if it will help, but it should do something you want

 

So i tried to do this, but i crashed after using it.

I do want to note that i changed from the pan flute "playing a lullaby" to becoming a bedroll that crashed the game after the laying the bed down and sleeping animation played.

I'm am not sure if it was just a bug that caused that use change, but just incase the way i worded my request was confusing, i am trying to make my item be a panflute that puts players in the bedroll sleep state, and then remove the starving aspect of the bedroll sleep state when a player is asleep from the sue of this flute.

anyway.I attached the error i got, and incase i put the code in wrong, here is the code for the item

Spoiler

local assets =
{
    Asset("ANIM", "anim/august_flute.zip"),
    
    Asset("ATLAS", "images/inventoryimages/august_flute.xml"),
    Asset("IMAGE", "images/inventoryimages/august_flute.tex"),
}

local function HearPanFlute(inst, musician, instrument)
    if inst ~= musician and
        (TheNet:GetPVPEnabled() or not inst:HasTag("player")) and
        not (inst.components.freezable ~= nil and inst.components.freezable:IsFrozen()) and
        not (inst.components.pinnable ~= nil and inst.components.pinnable:IsStuck()) then
        if inst.components.sleeper ~= nil then
            inst.components.sleeper:AddSleepiness(10, TUNING.PANFLUTE_SLEEPTIME)
        elseif inst.components.grogginess ~= nil then
            inst.components.grogginess:AddGrogginess(10, TUNING.PANFLUTE_SLEEPTIME)
        else
            inst:PushEvent("knockedout")
        end
    end
end
-------
local function wakeuptest(inst, phase)
    if phase ~= "night" then
        inst.components.sleepingbag:DoWakeUp()
    end
end

local function onwake(inst, sleeper, nostatechange)
    if inst.sleeptask ~= nil then
        inst.sleeptask:Cancel()
        inst.sleeptask = nil
    end

    inst:StopWatchingWorldState("phase", wakeuptest)

    if not nostatechange then
        if sleeper.sg:HasStateTag("bedroll") then
            sleeper.sg.statemem.iswaking = true
        end
        sleeper.sg:GoToState("wakeup")
    end

    if inst.components.finiteuses == nil or inst.components.finiteuses:GetUses() <= 0 then
        if inst.components.stackable ~= nil then
            inst.components.stackable:Get():Remove()
        else
            inst:Remove()
        end
    end
end

local function onsleeptick(inst, sleeper)
    local isstarving = sleeper.components.beaverness ~= nil and sleeper.components.beaverness:IsStarving()

    if sleeper.components.sanity ~= nil and sleeper.components.sanity:GetPercentWithPenalty() < 1 then
        sleeper.components.sanity:DoDelta(inst.sanity_tick, true)
    end

    if not isstarving and inst.components.sleepingbag.healthsleep and sleeper.components.health ~= nil then
        sleeper.components.health:DoDelta(TUNING.SLEEP_HEALTH_PER_TICK, true, "bedroll", true)
    end

    if sleeper.components.temperature ~= nil then
        if inst.sleep_temp_min ~= nil and sleeper.components.temperature:GetCurrent() < inst.sleep_temp_min then
            sleeper.components.temperature:SetTemperature(sleeper.components.temperature:GetCurrent() + TUNING.SLEEP_TEMP_PER_TICK)
        elseif inst.sleep_temp_max ~= nil and sleeper.components.temperature:GetCurrent() > inst.sleep_temp_max then
            sleeper.components.temperature:SetTemperature(sleeper.components.temperature:GetCurrent() - TUNING.SLEEP_TEMP_PER_TICK)
        end
    end

    if isstarving then
        inst.components.sleepingbag:DoWakeUp()
    end
end

local function onsleep(inst, sleeper)
    -- check if we're in an invalid period (i.e. daytime). if so: wakeup
    inst:WatchWorldState("phase", wakeuptest)

    if inst.sleeptask ~= nil then
        inst.sleeptask:Cancel()
    end
    inst.sleeptask = inst:DoPeriodicTask(TUNING.SLEEP_TICK_PERIOD, onsleeptick, nil, sleeper)
end

local function onuse_straw(inst, sleeper)
    sleeper.AnimState:OverrideSymbol("swap_bedroll", "swap_bedroll_straw", "bedroll_straw")
end
-------
local function fn()
    local inst = CreateEntity()
     local trans = inst.entity:AddTransform()
    local anim = inst.entity:AddAnimState()
    
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst:AddTag("flute")
    inst:AddTag("august_flute")
    
    inst.AnimState:SetBank("pan_flute")
    inst.AnimState:SetBuild("august_flute")
    inst.AnimState:PlayAnimation("idle")

    if not TheWorld.ismastersim then
        return inst
    end
    
    inst.entity:SetPristine()
----    

    if not TheWorld.ismastersim then
        return inst
    end


    inst:AddComponent("sleepingbag")
    inst.components.sleepingbag.onsleep = onsleep
    inst.components.sleepingbag.onwake = onwake
----    
    inst:AddComponent("inspectable")
    inst:AddComponent("instrument")
    inst.components.instrument.range = TUNING.PANFLUTE_SLEEPRANGE
    inst.components.instrument:SetOnHeardFn(HearPanFlute)

    inst:AddComponent("tool")
    inst.components.tool:SetAction(ACTIONS.PLAY)

    inst:AddComponent("finiteuses")
    inst.components.finiteuses:SetMaxUses(TUNING.PANFLUTE_USES)
    inst.components.finiteuses:SetUses(TUNING.PANFLUTE_USES)
    inst.components.finiteuses:SetOnFinished(inst.Remove)
    --inst.components.finiteuses:SetConsumption(ACTIONS.PLAY, 2.5)
    inst.components.finiteuses:SetConsumption(ACTIONS.SLEEPIN, 1)     
    
    
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.imagename = "august_flute"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/august_flute.xml"
    
    
    MakeHauntableLaunch(inst)
    AddHauntableCustomReaction(inst, function(inst, haunter)
        if math.random() <= TUNING.HAUNT_CHANCE_HALF then
            if inst.components.finiteuses then
                inst.components.finiteuses:Use(1)
                inst.components.hauntable.hauntvalue = TUNING.HAUNT_MEDIUM
                return true
            end
        end
        return false
    end, true, false, true)

    return inst
end

return Prefab("common/inventory/august_flute", fn, assets, prefabs)

 

Capture.PNG

Looks like you have problem with sanity per tick value..try make it 1 or 3 dunno
(here)
    if sleeper.components.sanity ~= nil and sleeper.components.sanity:GetPercentWithPenalty() < 1 then
        sleeper.components.sanity:DoDelta(inst.sanity_tick, true)
    end

After much thinking, I have decided i am going to go a different route with this. I have decided that i want the flute to increase sanity of all (including the person playing it) to gain X amount of sanity. and i want to the flute to NOT put people to sleep.

With that being said, i also would like to know how to make an item usable by ONLY the character i made, so similar to woodie's axe but without the talking part.

 

Thanks again! and sorry for any trouble i have caused with this decision. 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...