Jump to content

Custom Character Perks; Coding help?


Recommended Posts

I'm making a custom Character, and trying to figure out how to code the perks I want him to have. They are;

-Sanity gain around another custom Character
-Night vision
-Slowed hunger depletion

-Starts with an Axe and a Shovel
-Can't be put to sleep by mandrake based items
-Speed boost

If anyone could help me figure out the coding for this I would greatly appreciate it!

Edited by CreativexFreedo
Forgot an item
Link to comment
Share on other sites

First of all, welcome to DS/DST modding! :) Take a look at the newcomer post to get a good entry into this whole modding thing. There are a bunch of nice things to know, especially about how to debug your mods and how to search the forum efficiently for solutions.

Starting items

Look at this post
 

Slower hunger

-- 80% of normal hunger rate
inst.components.hunger:SetRate(GLOBAL.TUNING.WILSON_HUNGER_RATE * 0.80)


Sanity gain around another custom Character

There are a few ways to go about this. I like to do it with a task, because it lets you have more control. In your character's masterpostinit, put this in, and change the "YOUR_CUSTOM_CHARACTER_PREFAB_NAME" to...well, you guessed it:

-- DoPeriodicTask calls the given function every X seconds.
-- I set it to 1.0. You can set it to e.g. 0.5 seconds if you want.
inst:DoPeriodicTask(1.0, function(inst)
	-- Do nothing if the player is dead.
	if inst.components.health:IsDead() or inst:HasTag("playerghost") then
		return
	end
	
	-- Store the position of the player in x, y, z variables.
	local x,y,z = inst.Transform:GetWorldPosition()
	
	-- Description of important function, which finds specific entities within a range:
	-- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	
	-- We have limited it to any player that is not a ghost or in limbo.
	-- I have set the radius to be the one used for standard negative auras. You can set it to whatever radius you want.
	local ents = TheSim:FindEntities(x, y, z, TUNING.SANITY_EFFECT_RANGE, {"player"}, {"playerghost", "INLIMBO"}, nil)

	for i, v in ipairs(ents) do
		if v and v:IsValid() and v.prefab == "YOUR_CUSTOM_CHARACTER_PREFAB_NAME" then
			inst.components.sanity:DoDelta(1, true) -- "true" disables the pulse on the badge and disables that it plays a sound.
		end
	end
end)
 


Increased Movement Speed

-- 20% speed boost in all situations
inst.components.locomotor:SetExternalSpeedMultiplier(inst, "myinnatecharacterspeedmodifier", 1.20)


Night Vision

This is a more difficult one, since it has to be networked. Start with the others. This post does it, but it's long-winded. I think you'd be better off starting a new thread for this particular feature.


Can't be put to sleep by mandrake based items

This is a difficult one, since the function used by mandrakes to make entities sleepy is local, and is only referenced locally. To get at that function, you'd have to employ the Upvalue Hacker. Alternatively, you can take a closer look at the code, see what it does to your character, and then systematically negate those effects in your character's code. The lines of code from the mandrake which are important, are these:

if v:HasTag("player") then
	v:PushEvent("yawn", { grogginess = 4, knockoutduration = time + math.random() })
elseif v.components.sleeper ~= nil then
	v.components.sleeper:AddSleepiness(7, time + math.random())
elseif v.components.grogginess ~= nil then
	v.components.grogginess:AddGrogginess(4, time + math.random())
else
	v:PushEvent("knockedout")
end

I think, since your player's entity always has the "player" tag on them, they will only be affected by the first if-statement, while other entities are affected by the other three. The "yawn" event isn't handled by a ListenForEvent trigger, but instead by the stategraph. You will have to edit your character's stategraph code and disable the application of grogginess and/or the knockedoutduration. This is another kind of advanced thing to get to work, but there are plenty of threads on the forum that does something like this.

Link to comment
Share on other sites

35 minutes ago, CreativexFreedo said:

I can't seem to find where to put the Sanity Gain?

That whole chunk of code just goes at the bottom of your master_postinit function within your character's Lua file.

Remember to substitute the character prefab name of that other custom character.

Link to comment
Share on other sites

Yes, it will work because that character has a certain prefab name, which you put in instead of "YOUR_CUSTOM_CHARACTER_PREFAB_NAME". If you have the mod, find the files for it in your "mods" folder, find the character prefab Lua file, scroll to the bottom, and the first parameter in the call to the MakePlayerCharacter function should be their prefab name, e.g. in this example, the character's prefab name is "gir".

return MakePlayerCharacter("gir", prefabs, assets, common_postinit, master_postinit, start_inv)

 

Link to comment
Share on other sites

inst:DoPeriodicTask(1.0, function(inst)

means it calls the function every 1.0 seconds, and using the DoDelta function we add 1 sanity each time, so right now it's 1 sanity per second. You can change either number to whatever you want, but I advise only changing the amount added by DoDelta. We don't want the task to run too frequently or too seldom.

Link to comment
Share on other sites

5 minutes ago, suteneko said:

I'd looked in the tuning file thinking it'd shed light on my question but realized nothing in the code referenced tuning so I thought I'd ask.

Yeah, I try to refrain from using TUNING variables, unless I specifically want other mods to have an effect on my values. The thing is, if you use an existing TUNING variable, you run the risk of some other mod changing that variable for their purposes, and then your mod will be affected by that. Say I use TUNING.WILSON_HUNGER_RATE as the hunger rate for my character or in some calculation I do for something unrelated. If you use my Metabolizer mod which directly changes that TUNING variable, then your character's hunger rate will be affected by that. Usually you would want that, because then you can use my mod the change the hunger rate of all characters on the server respective of their settings (given that they use a multiple of that TUNING variable to set the hunger rate for their character, i.e., TUNING.WILSON_HUNGER_RATE * 0.8), but if you're doing some other calculation, you might want a very specific result using the vanilla value of this TUNING variable.

Link to comment
Share on other sites

6 minutes ago, Ultroman said:

Yeah, I try to refrain from using TUNING variables, unless I specifically want other mods to have an effect on my values. The thing is, if you use an existing TUNING variable, you run the risk of some other mod changing that variable for their purposes, and then your mod will be affected by that. Say I use TUNING.WILSON_HUNGER_RATE as the hunger rate for my character or in some calculation I do for something unrelated. If you use my Metabolizer mod which directly changes that TUNING variable, then your character's hunger rate will be affected by that. Usually you would want that, because then you can use my mod the change the hunger rate of all characters on the server respective of their settings (given that they use a multiple of that TUNING variable to set the hunger rate for their character, i.e., TUNING.WILSON_HUNGER_RATE * 0.8), but if you're doing some other calculation, you might want a very specific result using the vanilla value of this TUNING variable.

Oh, okay, that makes sense. I hadn't thought of that since I haven't picked up too many quality-of-life mods. Thank you for the clarification (again)! You're pretty much my hero tonight xD

Link to comment
Share on other sites

@Ultroman I was finally able to test to see if the Sanity Gain with specified character worked and... it didn't D:

Spoiler

	-- DoPeriodicTask calls the given function every X seconds.
	-- I set it to 1.0. You can set it to e.g. 0.5 seconds if you want.
	inst:DoPeriodicTask(1.0, function(inst)
		 -- Do nothing if the player is dead.
		 if inst.components.health:IsDead() or inst:HasTag("playerghost") then
			 return
		 end
	
		 -- Store the position of the player in x, y, z variables.
		 local x,y,z = inst.Transform:GetWorldPosition()
	
		 -- Description of important function, which finds specific entities within a range:
		 -- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
		 -- We have limited it to any player that is not a ghost or in limbo.
		 -- I have set the radius to be the one used for standard negative auras. You can set it to whatever radius you want.
		 local ents = TheSim:FindEntities(x, y, z, TUNING.SANITY_EFFECT_RANGE, {"player"}, {"playerghost", "INLIMBO"}, nil)

		 for i, v in ipairs(ents) do
			 if v and v:IsValid() and v.prefab == "NOCTIUM" then
				 inst.components.sanity:DoDelta(1, true) -- "true" disables the pulse on the badge and disables that it plays a sound.
			 end
		 end
	end)

 

This is a copy paste of how I have it in my master_postinit. No Sanity was gained when they were near each other.

Sorry for throwing all these questions and issues at you D:

Link to comment
Share on other sites

Is it only for players or am i doing something wrong? It does not work for me and idk what is the problem...

 

-- DoPeriodicTask calls the given function every X seconds.
-- I set it to 1.0. You can set it to e.g. 0.5 seconds if you want.
inst:DoPeriodicTask(1.0, function(inst)
	-- Do nothing if the player is dead.
	if inst.components.health:IsDead() or inst:HasTag("playerghost") then
		return
	end
	
	-- Store the position of the player in x, y, z variables.
	local x,y,z = inst.Transform:GetWorldPosition()
	
	-- Description of important function, which finds specific entities within a range:
	-- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	
	-- We have limited it to any player that is not a ghost or in limbo.
	-- I have set the radius to be the one used for standard negative auras. You can set it to whatever radius you want.
	local ents = TheSim:FindEntities(x, y, z, 40, {"catcoon"}, {"playerghost", "INLIMBO"}, nil)

	for i, v in ipairs(ents) do
		if v and v:IsValid() and v.prefab == "esctemplate" then
			inst.components.sanity:DoDelta(-5, true) -- "true" disables the pulse on the badge and disables that it plays a sound.
		end
	end
end)

no crush no error just not loses sanity near catcoon

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