Jump to content

Recommended Posts

So, I've been working on an item mod. It's working perfectly so far except I just can't figure out how to add one of the features I want to.

 

It's meant to be a character specific item that lets the character regain a small amount of sanity over time whilst being kept in their inventory. However, it's not an equipable item.

 

Could anyone help me figure out the code for this? Everything I've tried so far has resulted in a crash.

Link to comment
https://forums.kleientertainment.com/forums/topic/53517-help-with-item-mod/
Share on other sites

@LordMogar You could create a PeriodicTask to run when the item is given to the character (picked up), and remove it when it's taken away (dropped, put in chest, etc).

The inventoryitem component pushes events: onputininventory, ondropped, and onpickup. You can see how they function in "..\scripts\components\inventoryitem.lua".

 

Syntax.

-- Where inst is the item's instance-- Replace event_name according to your code designinst:ListenForEvent("event_name", function(inst, data)    -- Activate PeriodicTask    local task = inst:DoPeriodicTask(1, function()        -- Heal or something    end)    -- Deactivate PeriodicTask    -- Ideally, this would be associated with another event listener, not inside this function    task:Cancel()end)

I've been messing with the stuff you gave me for a while now and it keeps crashing. I'm not sure I'm doing this entirely right. :/

 

    inst:ListenForEvent("onputininventory", function(inst, data)
    local task = inst:DoPeriodicTask(1, function(inst) inst.components.sanity:DoDelta(20) end)
 
    inst:ListenForEvent("ondropped", function(inst, data)
    task:Cancel()
end)
 
 
Here's the error it keeps giving.
 
42: ')' expected (to close '(' at line 30) near 'return'

@LordMogar I don't think you've completely grasped the concept of functions and variables yet.

Does this make more sense?

-- This function will be called when the ondropped event is pushed.local function SomeFunction(inst, data)    print("Item dropped!")end-- Associates the SomeFunction function with the ondroppped event.inst:ListenForEvent("ondropped", SomeFunction)

-

 

Edit: Couldn't find the post explaining this topic in detail.

 

Edit 2:

local taskinst:ListenForEvent("onputininventory", function(inst, data)	task = inst:DoPeriodicTask(1, function()		-- Do something	end)end)inst:ListenForEvent("ondropped", function(inst, data)	if task then		task:Cancel()		task = nil	endend)
Edited by Blueberrys

No, I'm not very good with this stuff unfortunately, I'm surprised I've gotten as far in with the process of making mods as I have.

 

I tried applying the script from your second edit. I added in the sanity component and got past the main menu and ingame, a step up from previous attempts. This time however upon picking up the item the game crashes and prints the error, "attempt to index field 'sanity' (a nil value)".

 

Here's the whole .lua file for my item's prefab. Did I forget to add something?

local assets ={    Asset("ANIM", "anim/bear.zip"),    Asset("SOUND", "sound/common.fsb"),}local function fn()    local inst = CreateEntity()    inst.entity:AddTransform()    inst.entity:AddAnimState()    inst.entity:AddNetwork()    MakeInventoryPhysics(inst)    inst.AnimState:SetBank("bear")    inst.AnimState:SetBuild("bear")    inst.AnimState:PlayAnimation("idle")    if not TheWorld.ismastersim then        return inst    end    inst:AddComponent("inspectable")    inst:AddComponent("inventoryitem")    inst.components.inventoryitem.atlasname = "images/inventoryimages/bear.xml"local task inst:ListenForEvent("onputininventory", function(inst, data)    task = inst:DoPeriodicTask(1, function()    inst.components.sanity:DoDelta(20)    end)end) inst:ListenForEvent("ondropped", function(inst, data)    if task then        task:Cancel()        task = nil    endend)    MakeHauntableLaunch(inst)    return instendreturn Prefab( "common/inventory/bear", fn, assets) 

@LordMogar I figured this would arise. The inst you are referring to isn't the player instance, it's the item's instance.

You can access the owner of the item like so.

inst.owner.components.sanity:DoDelta(20)

I'd suggest checking if everything is valid too.

if inst.owner and inst.owner.components.sanity then    -- ...end

Well, the game isn't crashing at all anymore. However the item has gone back to doing nothing at all when in the inventory, so the desired effect isn't working. :/ I'm probably not using this correctly? Like I've mentioned I'm not good with this.

if inst.owner and inst.owner.components.sanity thenlocal task inst:ListenForEvent("onpickup", function(inst, data)   inst.task = inst:DoPeriodicTask(1, function() inst.owner.components.sanity:DoDelta(20) end)end)inst:ListenForEvent("ondropped", function(inst, data)    if task then        task:Cancel()        task = nil    endend)end

@LordMogar

-- inst.owner may be nil over here-- you don't want to check it until the person has the itemlocal task  inst:ListenForEvent("onpickup", function(inst, data)   -- Why was this inst.task? it should be just task   -- Unless you're going to use inst.task elsewhere too.   task = inst:DoPeriodicTask(1, function()      if inst.owner and inst.owner.components.sanity then      -- If statement is for this part         inst.owner.components.sanity:DoDelta(20)      end   end)end) inst:ListenForEvent("ondropped", function(inst, data)    if task then        task:Cancel()        task = nil    endend) 

Edit: Read comments above again, changed them a bit.

Edit2: Changed code a bit. Re-read.

Edited by Blueberrys

@LordMogar Just looked through the inventoryitem code. I think the inst.owner variable might not be set upon picking up items. Luckily, the event passes that information.

 

Change this part.

inst:ListenForEvent("onpickup", function(inst, data)   -- data.owner contains the instance of whoever picked the item   if data.owner and data.owner.components.sanity then      task = inst:DoPeriodicTask(1, function()         data.owner.components.sanity:DoDelta(20)      end)   endend)

@LordMogar Ensure the "task" variable is only being used once, and you're using it consistantly. Not inst.task and task, just one or the other.

local task -- Puts variable in outer scope so it can be accessed in both functions-- Inside the pickup function    if not task then -- Ensure it won't be overwritten unless it's nil        task = something    end-- Inside the drop function    if task then        task:Cancel()    end

Edit: fixed "if not task"

Edited by Blueberrys

Only task is being used, no inst.task or anything like that.

local task   inst:ListenForEvent("onpickup", function(inst, data)   if data.owner and data.owner.components.sanity then      task = inst:DoPeriodicTask(1, function()         data.owner.components.sanity.dapperness = 0.1      end)   endend)  inst:ListenForEvent("ondropped", function(inst, data)    if task then        task:Cancel()        task = nil    endend) 

@LordMogar Re-read my post, notice the if statements. Try to figure it out, this one is simple if you give it some thought. If you still can't get it, ask. Programming is all about figuring out solutions for problems, you're gonna have to practice it yourself if you wanna make something worthwhile.

I'm afraid I still don't get it. Maybe I've been staring at it for too long? I've noted that in your post you said to include "if task then" inside the pickup function, which my code lacks. However I don't see where or how to apply that if needed, considering it doesn't fit in the context of mine.

 

Does that have anything to do with why it isn't working?

@LordMogar Yup, that's the part.

local task    inst:ListenForEvent("onpickup", function(inst, data)   if data.owner and data.owner.components.sanity then      if not task then -- Fits right here         -- You don't want the task variable below to be overwritten unless it's nil         task = inst:DoPeriodicTask(1, function()            data.owner.components.sanity.dapperness = 0.1         end)      end   endend)   inst:ListenForEvent("ondropped", function(inst, data)    if task then        task:Cancel()        task = nil    endend)

Edit: Whoops, completely reversed that. Should be "if not task then". Fixed. Sorry bout that, haha.

Edited by Blueberrys

@LordMogar Ah.. I just realize you changed the sanity DoDelta command to a dapperness value.

 

If you're using dapperness, then you won't have to use a PeriodicTask at all.

local ownerinst:ListenForEvent("onpickup", function(inst, data)   owner = data.owner   if owner and owner.components.sanity then      owner.components.sanity.dapperness = 0.1   endend)inst:ListenForEvent("ondropped", function(inst, data)   if owner and owner.components.sanity then      owner.components.sanity.dapperness = 0   endend)

Thanks a lot! Works perfectly now and I even learned a couple of things, haha. :razz:

 

Yeah I realized sanity DoDelta wasn't at all what I was looking for, so I changed it. I probably should have mentioned, oops.

 

Edit: Here's the item I was working on, if you were curious. http://i.imgur.com/ss8egLG.png

Edited by LordMogar

Thanks a lot! Works perfectly now and I even learned a couple of things, haha. :razz:

 

Yeah I realized sanity DoDelta wasn't at all what I was looking for, so I changed it. I probably should have mentioned, oops.

 

Edit: Here's the item I was working on, if you were curious. http://i.imgur.com/ss8egLG.png

 

Thats pretty cool!

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...