Jump to content

help with .lua Perks for character mod


Recommended Posts

Hi! name's Ti and I'm making my first mod, I'm kind of a programmer so I have a little bit of code understanding yet .lua is absolutely new to me and the way to address things in-game has been really difficult to understand, so I'm leaving aside my stubbornness about never asking for help and.. well... asking for help ;-; 

I'm making a character mod and so far everything is working fine, the only problem I have are the perks I'm trying to give to the character... I know what I want to do but can't figure out how to do it with the knowledge I have of .lua as programming language...

so basically there are two perks I'm trying to make (besides a custom item that I haven't quite added yet) and those are

-if the character is idle for a certain amount of time, they start losing sanity (I have figured out the time and how to calculate it, what I can't actually program is how to find the character's position and if they moved or not)

-time to time the character is supposed to "forget" recipes from the crafting tab, so they should get locked again, making it impossible to craft unless there's a science machine/alchemy engine.(as if they've never learned it) 

If anyone has an idea of how to do this or point me to a guide that can help me understand the game programming more I'd really appreciate it... 

 

Link to comment
Share on other sites

For checking whether the character is standing still, there are a couple of ways.

This first one looks at the actual motorspeed of the character, which means if the character is moved without input from the player, like when pushed by an AoE or something, the motorspeed is going to be not 0. The following code keeps updating a variable called LastMovementTime on the player instance, which holds the last time any movement of the character was detected.

inst.LastMovementTime = -100 -- just setting a starting value to something ridiculously low, so it isn't nil

inst:DoPeriodicTask(0.2, function(inst)
	if inst.Physics:GetMotorSpeed() ~= 0 then
		inst.LastMovementTime = GLOBAL.GetTime()
	end
end

You can then check against the current time, to see if enough time has passed to apply the sanity loss. The following example already has the code from the snippet above, so you don't need both.

inst.LastMovementTime = -100 -- just setting a starting value to something ridiculously low, so it isn't nil
local sanityLossPerSecond = 0.5
local periodicTaskInterval = 0.2 -- keep this below 1.0, so there isn't too large a period between updating. It'll reduce the margin of error for the edgecases.

inst:DoPeriodicTask(periodicTaskInterval, function(inst)
	if inst.Physics:GetMotorSpeed() ~= 0 then
		inst.LastMovementTime = GLOBAL.GetTime()
	end
	if GLOBAL.GetTime() - inst.LastMovementTime > delayBeforeLosingSanity then
		-- remove sanity
		inst.components.sanity:DoDelta(sanityLossPerSecond * periodicTaskInterval)
	end
end

I'm not 100% sure, but I think this next example will react only to voluntary movement, so if the character is pushed/moved by some physics-stuff, it will still count as standing still.

inst.LastMovementTime = -100 -- just setting a starting value to something ridiculously low, so it isn't nil
local sanityLossPerSecond = 0.5
local periodicTaskInterval = 0.2 -- keep this below 1.0, so there isn't too large a period between updating. It'll reduce the margin of error for the edgecases.

inst:DoPeriodicTask(periodicTaskInterval, function(inst)
	if inst.components.locomotor.isrunning then
		inst.LastMovementTime = GLOBAL.GetTime()
	end
	if GLOBAL.GetTime() - inst.LastMovementTime > delayBeforeLosingSanity then
		-- remove sanity
		inst.components.sanity:DoDelta(sanityLossPerSecond * periodicTaskInterval)
	end
end

This code should go at the bottom of your character's fn() or post-init function.

Also, you will help yourself A LOT if you just took a short course in LUA. Here's a crash course, and I advise you to take more.

About forgetting recipes, that is pretty complex, due to the complexity of the whole recipe-system. There are functions for learning recipes, but not for removing them. There is a similar topic on the forum here, where someone wanted to do exactly that. Search around and you should find it. Not sure if they ever figured it out, though.

Edited by Ultroman
Link to comment
Share on other sites

Thank you! @Ultroman that was really helpful!! 

tho the GLOBAL variable doesn't really work outside modmain.lua, in <character>.lua is not necessary. I was in the right tracks but couldn't figure out how to actually write down what I needed. DoDelta is also not a great visual so I changed the code a to sanity.dapperness and added a few things and now is working perfectly! exactly how I wanted it to be! thank you for linking the lua tutorial too! but my problem is not with lua itself but some of the games' way to use it, your example though was extremely helpful!! 

As for the second perk I did see the thread about someone else trying to do the same thing, but I didn't see any concrete answer, some methods that didn't really worked or had some visual issues, though I think I can implement what I'm looking for in a different way :D 

Again, Thank you for your reply! it was really helpful and I got it working in no time !

Link to comment
Share on other sites

Well I got a solution for forgetting things overtime.

Spoiler

AddComponentPostInit("builder", function(self)
	self.RemoveRecipe = function(self, recname)
		if table.contains(self.recipes, recname) then
			for k, v in ipairs(self.recipes) do
				if v == recname then
					table.remove(self.recipes, k)
					break
				end
			end
		end
		self.inst.replica.builder:RemoveRecipe(recname)--already exists
	end
	self.LockRecipe= function(self, recname)
		local recipe = GLOBAL.GetValidRecipe(recname)
		if recipe ~= nil and not recipe.nounlock then
			--print("Locking: ", recname)
			self:RemoveRecipe(recname)
			self.inst:PushEvent("lockrecipe", { recipe = recname })
		end
	end
end)

This needs to go into modmain

To forget random ones we need to

Spoiler

local function forget(inst)--goes above the Postinit
	if inst.components.builder then
		local size = #inst.components.builder.recipes
		if size > 0 then
			local rand = math.random(1,size)
			inst.components.builder:LockRecipe(inst.components.builder.recipes[rand])
		end
	end
end
--Common Postinit
--Master Postinit
inst.forgetful = inst:DoPeriodicTask(10, forget)--adjust to your liking

This goes into your character's prefab file

If you want to lose sanity or do other things whenever you forget you can inst:ListenForEvent("lockrecipe", yourfunction) with your function being a -dodelta to sanity etc.

Link to comment
Share on other sites

2 hours ago, Tiafu said:

DoDelta is also not a great visual so I changed the code a to sanity.dapperness and added a few things and now is working perfectly!

 

What do you mean DoDelta is not a great visual? You can add a value to the "overtime" parameter, to control whether you want it to pulse (and make the noise) when regenerating. Adding "false" after the number lets it pulse and make noise (this is default behavior if you do not add the parameter, so this was what you had with my code), and if you don't want it to give the pulse and noise, you just put in "true".

inst.components.sanity:DoDelta(sanityLossPerSecond * periodicTaskInterval, true)

The problem with using the sanity.dapperness value, is that everyone else uses it, so you can't really trust its value over time, so you can't save it, and reset it later. All you can do is add your specific value to it, and when you want to remove it again, subtract your specific value from it. Otherwise, you might mess up something that another mod is doing to it.

Edited by Ultroman
Link to comment
Share on other sites

@IronHunter OH GOSH THANK YOU!!!! That works PERFECTLY AAHH!!! THANK YOU SO MUCH!!!!!! 

1 hour ago, Ultroman said:

The problem with using the sanity.dapperness value, is that everyone else uses it, so you can't really trust its value over time, so you can't save it, and reset it later. All you can do is add your specific value to it, and when you want to remove it again, subtract your specific value from it. Otherwise, you might mess up something that another mod is doing to it.

wait does that mean that if if something else is causing a drop/gain in sanity with sanity.dapperness it'll mess up? I haven't tested the mod enough but I'm doing it right now. I'm not super clear on what kind of problems it can cause...

Link to comment
Share on other sites

14 hours ago, Tiafu said:

 

wait does that mean that if if something else is causing a drop/gain in sanity with sanity.dapperness it'll mess up?

5
5

It depends on how you use it. As I said, if you have one specific value, which you add or subtract to/from dapperness at one point, and then do the reverse (add or subtract the value) after a while, you should be fine. You just can't trust saving the "current" dapperness, then change it, and then later reset it to the saved value, because it might have changed in between.

Edited by Ultroman
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...