Jump to content

Sanity through dancing


Recommended Posts

I'm making a Shantae mod and want to incorporate dancing into the mod. I figure that transforming would be too much, so I want her to regenerate sanity while losing hunger while doing the dance emotes, /dance, /step, /robot, and most importantly, /chicken. I tired to look at the Isabelle mod for help, but it didn't go so well... Any help?

Speaking of emotes, is there a tutorial on making an new animation? I tried to look for one but couldn't find one. Or I was looking in the wrong places. I wanna see if I can make an emote exclusively for Shantae. (As amusing as it would be to see Wilson belly dance, I can't help but feel like that would be a bit out of character. Just a bit.)

Link to comment
Share on other sites

Luckily for you, dancing emotes apply a statetag to the player, namely "dancing". In your update-function, do something like this:

if inst.sg:HasStateTag("dancing") then
	-- do your thing
end

...where inst is the player instance.

Whenever the player's state changes, the "dancing" statetag is removed automatically by the system.

Here's a tutorial for custom character animations. You'll probably need more than that, though. Look at the pinned posts in the forum and existing mods for the rest. I never did a character mod.

Link to comment
Share on other sites

5 hours ago, Ultroman said:

Luckily for you, dancing emotes apply a statetag to the player, namely "dancing". In your update-function, do something like this:


if inst.sg:HasStateTag("dancing") then
	-- do your thing
end

...where inst is the player instance.

Whenever the player's state changes, the "dancing" statetag is removed automatically by the system.

Here's a tutorial for custom character animations. You'll probably need more than that, though. Look at the pinned posts in the forum and existing mods for the rest. I never did a character mod.

I use the emotes, but nothing's happening. I think I may be doing it wrong. This is how I have it set up.

local function dance_sanity_update(inst)
    if inst.sg:HasStateTag("dancing") then
	inst.components.sanity.dapperness = TUNING.DAPPERNESS_SMALL
	end
end

 

Link to comment
Share on other sites

Why are you changing the dapperness variable? That only changes how fancy the player feels when wearing nice clothing, which gives him a slight sanity buff. If your dance_sanity_update function is called every frame, you should simply do inst.components.sanity:DoDelta(insert appropriate parameters).

Can I see the code where you use this function? Preferably the whole modmain file.

Link to comment
Share on other sites

1 hour ago, Ultroman said:

Why are you changing the dapperness variable? That only changes how fancy the player feels when wearing nice clothing, which gives him a slight sanity buff. If your dance_sanity_update function is called every frame, you should simply do inst.components.sanity:DoDelta(insert appropriate parameters).

Can I see the code where you use this function? Preferably the whole modmain file.

I see. I don't think I need to send you the info though. I think I can use the bedrolls as references. They do the thing I'm trying to do.

Link to comment
Share on other sites

2 hours ago, Ultroman said:

Good call. They do exactly what you need.

Still nothin'... The code I'm using is

local function dancer(inst)
    if inst.sg:HasStateTag("dancing") then
	dancer.components.sanity:DoDelta(inst.sanity_tick, true)
	end
end

Based off the Bedroll's code

sleeper.components.sanity:DoDelta(inst.sanity_tick, true)

I figured it wouldn't work because of the sleeper part. But I guess that's not the case...

Is there a way to see how all those tags work? That might provide insight.

Link to comment
Share on other sites

In order to call a function on something, that something has to be declared somewhere. In your code, you changed "inst", which is a parameter you get into the function, with "dancer", which isn't declared anywhere. It was "inst", because that's the object we're working with. In the bedroll's code, one of the parameters/variables is called "sleeper", which is why they use that object.

Anyway, since you're using a variable in your code that isn't there, and you didn't mention it crashing, I'm guessing your function is never called, or the way we're trying to use the stategraph isn't right. I'll code a small sample to see if I can get it going, so you can see how it works.

If you look in the "stategraphs" folder, and find "SGWilson", that's the standard stategraph. It has all the events we can look at.

Please attach a zip-file with your mod, so I can see what's going on. I have a hunch that your function isn't executed anywhere.

Edited by Ultroman
Link to comment
Share on other sites

local function changevariables(inst)
	inst.components.sanity:DoDelta(inst.dance_sanity_change, false)
end

local function dancecheck(inst, data)
	if inst then
		if data and data.statename and data.statename == "emote" and inst.sg and inst.sg:HasStateTag("dancing") then
			if inst.dancetask == nil then
				inst.dancetask = inst:DoPeriodicTask(inst.dancetask_tick_time, changevariables, nil)
			end
		elseif inst.dancetask ~= nil then
			inst.dancetask:Cancel()
			inst.dancetask = nil
		end
	end
end

-- Put the lines below, at the bottom of your fn() function (the one that sets up everything for the character, adding components and such)
inst.dance_sanity_change = 0.5
inst.dancetask_tick_time = 1
inst:ListenForEvent("newstate", dancecheck)

You can set dance_sanity_change and dancetask_tick_time to whatever you want. The first parameter of DoPeriodicTask is the time (dancetask_tick_time) between calls to the given function (changevariables). I can't remember if it's in number of frames or seconds. Play around with it.

In the DoDelta call, I set the last parameter to false, which makes it apply the change immediately, whereas setting it to true, will apply the change over time.

Edited by Ultroman
Link to comment
Share on other sites

5 hours ago, Ultroman said:

local function changevariables(inst)
	inst.components.sanity:DoDelta(inst.dance_sanity_change, false)
end

local function dancecheck(inst, data)
	if inst then
		if data and data.statename and data.statename == "emote" and inst.sg and inst.sg:HasStateTag("dancing") then
			if inst.dancetask == nil then
				inst.dancetask = inst:DoPeriodicTask(inst.dancetask_tick_time, changevariables, nil)
			end
		elseif inst.dancetask ~= nil then
			inst.dancetask:Cancel()
			inst.dancetask = nil
		end
	end
end

-- Put the lines below, at the bottom of your fn() function (the one that sets up everything for the character, adding components and such)
inst.dance_sanity_change = 0.5
inst.dancetask_tick_time = 1
inst:ListenForEvent("newstate", dancecheck)

You can set dance_sanity_change and dancetask_tick_time to whatever you want. The first parameter of DoPeriodicTask is the time (dancetask_tick_time) between calls to the given function (changevariables). I can't remember if it's in number of frames or seconds. Play around with it.

In the DoDelta call, I set the last parameter to false, which makes it apply the change immediately, whereas setting it to true, will apply the change over time.

So my problem was that I had an On position, but never an Off position to switch over to. Thanks!

Also, I decided to drop the hunger drain. Considering how slow the sanity gain is, you lose just as much hunger by default.

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