Jump to content

Help trying to pick up Rabbits and Birds (Custom Perk)


Recommended Posts

Hi there! it's been a rather long time since I've dabbled with modding DST. I'm trying to recreate a character of mine who has a few tricky perks that I haven't been able to really figure out how to implement yet. I'm pretty much still a n00b when it comes to coding, but I found I learn best with a hands on approach, so please forgive my silly errors. ^^

One of my character's perks is that she can befriend nearly anything. I've managed to increase the loyalty time for followers, and also managed to keep prey creatures from running from her on sight. My next move is to make it so she can pick up a rabbit or bird she walks up to. (or at least try to- perhaps nerfing her a bit so that she can try and if by random chance the action fails the prey animal runs away like normal for a short time?) I'd also like to remove the option to murder them in her inventory- cuz she isn't very murder-y to begin with.

I would be very thankful if someone could help point me in the right way or give me some coding tips for this. I'll keep poking around in the scripts to see if I can find anything else helpful...

Thanks for taking a look! <3

Link to comment
Share on other sites

I think what you would need to do is to edit each of the small animals prefabs by using addprefabpostinit in order to accomplish this, I would take a look at the rabbit.lua under the prefabs folder as there should be something that enables characters to pick up the rabbit after being caught in a trap which I'm guessing it would be related to the inventoryitem component. Hopefully that'll get you going in the right direction.

Link to comment
Share on other sites

So after some searching in the prefabs I found the following put in my modmain.lua allows me to pick up rabbits, (After removing the scarytoprey tag for my character of course.)
 

AddPrefabPostInit("rabbit", function(inst)
              inst.components.inventoryitem.canbepickedup = true
              inst.components.health.canmurder = false             
            --still need to figure out how to keep my character from being able to attack 

end
)

My first problem is that once She picks up the rabbit and sets it down again she no longer has the option to pick it up again.

 

Now i'm stumped as to how to make those apply only for my character. I've given her the tag "veryfriendly" and increased her follower loyalty with a separate function in the modmain.lua as well.

AddComponentPostInit("follower", function(self)
    local _AddLoyalityTime = self.AddLoyaltyTime
    function self:AddLoyaltyTime(time, ...)
        if self.leader and self.leader:HasTag("veryfriendly") and GLOBAL.GetTime() > 0 then
            time = time * 100 
        end
        _AddLoyalityTime(self, time, ...)
    end
end
)

Would I use something similar to if self.leader:HasTag in the AddPrefabPostInit?

 

 

I wish this was Java...Java makes sense to me..

Link to comment
Share on other sites

So you'll want to put in a check for these lines to see who the character is attempting to pick up the rabbit.

I'm guessing you could do an if statement for that.

if prefab.name == "yourcharactersname" then

inst.components.inventoryitem.canbepickedup = true

inst.components.health.canmurder = false

end

For the special component you made yeah you'll need to add the tag into each friendly follower via addprefabpostinit.

As far as attacking them I'm not sure.

 

Link to comment
Share on other sites

Hmmmm..

AddPrefabPostInit("rabbit", function(inst)
	if prefab.name == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Keeps crashing my game with a not enough memory error. Am I blind here, or just not implementing this code correctly?

Link to comment
Share on other sites

5 hours ago, whatsherface said:

Hmmmm..


AddPrefabPostInit("rabbit", function(inst)
	if prefab.name == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Keeps crashing my game with a not enough memory error. Am I blind here, or just not implementing this code correctly?

I would check your error log. You can find that in My Documents > Klei > Dont Starve Together and it should be client error log.txt. The crash error will be near the bottom.

Link to comment
Share on other sites

Okay! Finally had a moment to sit down and take a look, turns out my problem is that the game is having trouble recognizing the "If prefab.name ==" part because of this error: "attempt to index global 'prefab' (a nil value)" I think its a fix as simple as this? But I'm having a slow brain day...what local variable do I put there?

AddPrefabPostInit("rabbit", function(inst)
    local prefab =  ???*
    if prefab.name == "esctemplate" then
        inst.components.inventoryitem.canbepickedup = true
        inst.components.health.canmurder = false
    end
end)

Thank you so much for all the help you've been giving me. <3

Link to comment
Share on other sites

So I tried something else that I thought would make sense based on searching the web and forums for similar problems....

AddPrefabPostInit("rabbit",function(inst)
	if GLOBAL.ThePlayer and GLOBAL.ThePlayer:HasTag("veryfriendly)" then 
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

However this doesn't do anything in game. I can approach like normal but I cannot pick up the rabbits.

How would I go about checking if the player character is this custom one successfully?

Link to comment
Share on other sites

23 hours ago, whatsherface said:

Okay! Finally had a moment to sit down and take a look, turns out my problem is that the game is having trouble recognizing the "If prefab.name ==" part because of this error: "attempt to index global 'prefab' (a nil value)" I think its a fix as simple as this? But I'm having a slow brain day...what local variable do I put there?


AddPrefabPostInit("rabbit", function(inst)
    local prefab =  ???*
    if prefab.name == "esctemplate" then
        inst.components.inventoryitem.canbepickedup = true
        inst.components.health.canmurder = false
    end
end)

Thank you so much for all the help you've been giving me. <3

You can swap out prefab.name for GLOBAL.ThePlayer.prefab

Link to comment
Share on other sites


AddPrefabPostInit("rabbit", function(inst)	
	if GLOBAL.ThePlayer.prefab == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Gives me a "attempt to index global 'ThePlayer' (a nil value)"

I feel like I'm going around in circles here. I'm sorry...

Link to comment
Share on other sites

11 hours ago, whatsherface said:


AddPrefabPostInit("rabbit", function(inst)	
	if GLOBAL.ThePlayer.prefab == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Gives me a "attempt to index global 'ThePlayer' (a nil value)"

I feel like I'm going around in circles here. I'm sorry...

inst.prefab instead, sorry I'm decent at coding this lol.

Link to comment
Share on other sites

Yay! It didn't crash! The only problem now is the second part isn't working now. I can't pick up rabbits as my character, and I still can murder them in my inventory. I'm not sure if the inst.prefab == "name" is properly checking for my character's prefab.

AddPrefabPostInit("rabbit", function(inst)	
	if inst.prefab == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Do you have a Ko-fi? Your help has been wonderful. I want to thank you for your patience with me. ^^

Edited by whatsherface
Link to comment
Share on other sites

I'm actually second guessing myself now. I believe since you're adding the prefab Postinit to the rabbit prefab inst.prefab will be "rabbit". You can double check by doing this.

AddPrefabPostInit("rabbit", function(inst)	
	print (inst.prefab)
	if inst.prefab == "esctemplate" then
		inst.components.inventoryitem.canbepickedup = true
		inst.components.health.canmurder = false
	end
end)

Once you launch the game you can check the print by either hitting the ` key or you can do Control + L. If inst.prefab turns out to be "rabbit" then we'll need to change it. 

Link to comment
Share on other sites

I'm wondering if this AddPrefabPostInit is happening before ThePlayer is being established. If it is then we may need to do this another way. You can do a print (ThePlayer) in the same spot to see if it's nil or not. If it's nil then we would need to somehow either call AddPrefabPostInit after your character is created or the alternative would be to basically overwrite the rabbit prefab with your own custom rabbit.

Link to comment
Share on other sites

You may be able to do a DoTaskInTime to call the AddPrefabPostInit or add it into the function. That would allow ThePlayer time to get established. I do think overwriting the rabbit can cause issues if anyone else has created a mod that modifies the rabbit.lua. 

Link to comment
Share on other sites

Okay! It worked!

For anyone who wants to use this code or modify it, here is the functional code:

-- Character can pick up + cannot murder in inventory
AddPrefabPostInit("rabbit", function(inst)	
		inst:DoTaskInTime(10, function() 
			if GLOBAL.ThePlayer.prefab == "esctemplate" then
				inst.components.inventoryitem.canbepickedup = true
				inst.components.health.canmurder = false
			end
		end)
end)

 

My only problem now is that once my character sets down a rabbit from her inventory she cannot pick it up again. Any ideas?

Edited by whatsherface
Link to comment
Share on other sites

2 hours ago, whatsherface said:

Okay just now noticed a new crash...With this code if I spend too long in the character select screen it crashed with a ThePlayer is nil error again...

The good thing is we now know it's because ThePlayer doesn't exist yet. I think what you may be able to do is 

-- Character can pick up + cannot murder in inventory
AddPrefabPostInit("rabbit", function(inst)	
		local taskRabbit = nil
		
		taskRabbit = inst:DoPeriodicTask(5, function() 
			if GLOBAL.ThePlayer.prefab ~= nil then
				if GLOBAL.ThePlayer.prefab == "esctemplate" then
					inst.components.inventoryitem.canbepickedup = true
					inst.components.health.canmurder = false
					taskRabbit:Cancel()
				end
			end
		end)
end)

What this should do is it will perform the function every 5 seconds, if ThePlayer doesn't exist then nothing will happpen and the function will just be called again in 5 seconds. Once it succeeds it'll apply your updates and then cancel the periodictask.

Link to comment
Share on other sites

I get a "attempt to index field 'ThePlayer' (a nil value)" crash again. If I spend more than 5 seconds selecting my character. Eughhhh...

Also I'm still unable to pick the rabbits back up after setting them down. Other than that it works fine.

Link to comment
Share on other sites

11 minutes ago, whatsherface said:

I get a "attempt to index field 'ThePlayer' (a nil value)" crash again. If I spend more than 5 seconds selecting my character. Eughhhh...

Also I'm still unable to pick the rabbits back up after setting them down. Other than that it works fine.

If you'd like to share your file I can troubleshoot it for you.

Link to comment
Share on other sites

https://github.com/xWhatsherfacex/Don-t-Starve/blob/master/modmain.lua

Here's the github for it, as well as the steam workshop page:

https://steamcommunity.com/sharedfiles/filedetails/?id=1392534

 

Just tested it with more than one player. My friend playing wilson was also able to pick up them and unable to murder in the inventory...

Edited by whatsherface
Link to comment
Share on other sites

Yeah the code adds the ability to pickup the rabbit for everyone, I don't believe you can actually insert an if statement into the rabbit prefab using AddPrefabPostInit which is another issue and it seems the reason why you can't pick up the rabbit after setting it down has to do with the Rabbit stategraph.

 State{
        name = "stunned",
        tags = {"busy", "stunned"},
        
        onenter = function(inst) 
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("stunned_loop", true)
            inst.sg:SetTimeout(GetRandomWithVariance(6, 2) )
            if inst.components.inventoryitem then
                inst.components.inventoryitem.canbepickedup = true
            end
        end,
        
        onexit = function(inst)
            if inst.components.inventoryitem then
                inst.components.inventoryitem.canbepickedup = false
            end
        end,
        
        ontimeout = function(inst) inst.sg:GoToState("idle") end,
    },

It seems that after being set down and stunned he won't be able to be picked up again. I personally can't think of a way around this without overwriting the rabbit prefab and stategraph unfortunately :/

Link to comment
Share on other sites

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
 Share

×
  • Create New...