Jump to content

[QUESTION] Modifying All Hat Prefabs


Recommended Posts

I've added a hairfront_hat symbol to my character's build because their hairfront clips through hats normally. What I want to do now is override the OnEquip function in hats.lua. There's a problem though; it's a local function that's created inside of another local function (MakeHat(string)) so I don't think I can access it directly. The hats.lua file doesn't return an actual hats prefab; rather, it returns a whole bunch of hats made by MakeHat(string). I think this prevents me from adding a postinit to it because a hats prefab technically never gets made. Because of this, trying to modify components.equippable.onequipfn for hats didn't work. But I DID get it to work by modifing the onequipfn for the "tophat" prefab specifically.

So here's what I want to know: is there a convenient way to do add a postinit for every prefab that MakeHat() can return, without overwriting the file? Or will I have to go through the list of return values in hats.lua and manually add the post init to every single one?

Link to comment
Share on other sites

Probably not the smartest way but this should work:

On server load you could retrieve the list of all the prefabs

local prefab_list = GLOBAL.Prefabs

then check each of them

for k, v in pairs(prefab_list) do
	local checkinst = v.fn()

	if checkinst.components and checkinst.components.equippable and checkinst.components.equippable.equipslot == GLOBAL.EQUIPSLOTS.HEAD then
		-- this is a hat!
		
		local OriginalFn = v.fn()
		
		v.fn = function()
			local inst = OriginalFn()

			[... do your stuff ...]

			return inst
		end
	end
end

This would be a hacked equivalent of the AddPrefabPostInit function.

Link to comment
Share on other sites

You can use AddPrefabPostInitAny:

AddPrefabPostInitAny(function(inst)
	if inst and inst.components and inst.components.equippable and inst.components.equippable.equipslot = GLOBAL.EQUIPSLOT.HEAD then
		local OldOnequipfn = inst.components.equippable.onequipfn
		local OldOnunequipfn = inst.components.equippable.onunequipfn
		
		inst.components.equippable.onequipfn = function(inst, owner, symbol_override)
			OldOnequipfn(inst, owner, symbol_override)
			if owner.prefab == "YOURCHARACTER" then
				owner.AnimState:Show("HAIRFRONT_HAT")
			end
		end
		
		inst.components.equippable.onunequipfn = function(inst, owner)
			OldOnunequipfn(inst, owner)
			if owner.prefab == "YOURCHARACTER" then
				owner.AnimState:Hide("HAIRFRONT_HAT")
			end
		end
	end
end)

I have no idea about animations, but wouldn't it be simpler to merge HAIRFRONT_HAT with HAIR_HAT?

--

7 hours ago, ZupaleX said:

local OriginalFn = v.fn()

local inst = OriginalFn()

That will result in an error, won't it? ( attempt to call local 'OriginalFn' (a table value) ).

Edited by alainmcd
missed an "end"
Link to comment
Share on other sites

AddPrefabPostInitAny is good to know about.

Honestly if I were interested purely in performance I'd stick with doing the "manual list of prefabs" for it (in fact that's what I was doing before this thread got answered), but checking all the prefabs allows me to account for new hats or modded hats that I don't know about and can't write in manually.

Course, some of the hats don't need this (open top hats such as the garland) so I'd have to write a blacklist for those.

Quote

I have no idea about animations, but wouldn't it be simpler to merge HAIRFRONT_HAT with HAIR_HAT?

I'm not really sure what you mean by this. hairfront goes in front of the headbase, hair goes behind it. I need the hairfront in order for my character to look correct from the side, so I can't use the regular hair symbol for it either hatted or hatless. It's just that unlike hair, hairfront does not have a hat version.

Disclaimer: I'm pretty clueless about how the graphics side works, this is the first time I've ever modified a build at all. I'm not even hiding/showing the hair; I'm using symbol override because I'm not even sure how to make the hairfront_hat use the same animations as hairfront by default. All I really did was open up the .scml in notepad++ and duplicate all the entries with hairfront and changing the name to hairfront_hat (and the ids of course).

Dealing with animations is something I want to learn but I haven't gotten around to it yet.

Link to comment
Share on other sites

11 minutes ago, code4240 said:

I'm not really sure what you mean by this.

I mean that I really don't know what I'm talking about. If there's some way you can merge your symbols, you wouldn't need to check all the hats and change their functions. I am completely clueless when it comes to animations, so you're probably right in doing it this way.

Link to comment
Share on other sites

5 hours ago, alainmcd said:

You can use AddPrefabPostInitAny:


AddPrefabPostInitAny(function(inst)
	if inst and inst.components and inst.components.equippable and inst.components.equippable.equipslot = GLOBAL.EQUIPSLOT.HEAD then
		local OldOnequipfn = inst.components.equippable.onequipfn
		local OldOnunequipfn = inst.components.equippable.onunequipfn
		
		inst.components.equippable.onequipfn = function(inst, owner, symbol_override)
			OldOnequipfn(inst, owner, symbol_override)
			if owner.prefab == "YOURCHARACTER" then
				owner.AnimState:Show("HAIRFRONT_HAT")
			end
		end
		
		inst.components.equippable.onunequipfn = function(inst, owner)
			OldOnunequipfn(inst, owner)
			if owner.prefab == "YOURCHARACTER" then
				owner.AnimState:Hide("HAIRFRONT_HAT")
			end
		end
	end
end)

I have no idea about animations, but wouldn't it be simpler to merge HAIRFRONT_HAT with HAIR_HAT?

--

That will result in an error, won't it? ( attempt to call local 'OriginalFn' (a table value) ).

 

There is indeed a typo in my post it should be

local OriginalFn = v.fn

I forgot about the AddPrefabPostInitAny, which is what my proposed function is doing but with less lines :p

 

EDIT: actually there is still an advantage to my method over the AddPrefabPostInitAny

You could add this function in a post sim function and a delay so no matter when your mod is loaded, you will end up modifying all the hats, even the ones which are added by other mods later during the mod loading process, while the AddPrefabPostInitAny will only affect the registered prefab when YOUR mod is loaded :)

Even though after writing that I am wondering if the AddPrefabPostInit function could be called in a post sim function as well.

 

To be fair I answered the question from the topic title but I am not sure what code4240 is trying to do. Yo want to display the standard hairfront no matter what, even with a hat equipped?

Edited by ZupaleX
Link to comment
Share on other sites

Quote

Yo want to display the standard hairfront no matter what, even with a hat equipped?

Nope. It already does that, I'm trying to make it not do that.

Though it just occurred to me to try and see if I could just move the regular hair symbol's Z order up and use that instead. That would probably be better so I'm gonna go try that.

Link to comment
Share on other sites

20 minutes ago, ZupaleX said:

Could'nt you just put a transparent sprite then?

That would just remove the hair entirely lol.

Anyway, when I looked into changing the z-order of sprites I found it would require basically remaking all the player animations in the game so that's a huge can of nope. I'll just stick with the hairfront_hat symbol.

Link to comment
Share on other sites

BTW this is what she looks like
u42IRcc.png

That hair only works if I either:
A) Put it in hairfront (which causes it to clip through hats)
B) Put it on the head sprite

hair and hairfront aren't actually synced up in the animations so trying to just stick the bits that go in front of her face looks pretty stupid as well, and putting the whole thing on the face sprite removes the bounciness the hair normally has, so adding a hairfront_hat symbol so I can prevent clipping through hats produces the best result.

pBwE90b.png
 

Basically, this allows me to have my cake and eat it too.

Link to comment
Share on other sites

Ok I understand better now. I thought you wanted to remove it actually.

Is the hairfront_hat symbol a thing? I did not see it in the build but maybe the one I have is outdated or ncomplete (I did not mess up with animations for more than a year now).

Link to comment
Share on other sites

1 minute ago, ZupaleX said:

Ok I understand better now. I thought you wanted to remove it actually.

Is the hairfront_hat symbol a thing? I did not see it in the build but maybe the one I have is outdated or ncomplete (I did not mess up with animations for more than a year now).

It's not. I added it myself.

 

Link to comment
Share on other sites

8 hours ago, ZupaleX said:

But this symbol won't be present in all the base animations then. And if it's not there you cannot override it.

Or maybe I just missed how you implement it.

The hairfront_hat is not visible, but it can still be used to override the hairfront symbol that is there.

It's intentionally not visible when the player isn't wearing a hat just like hair_hat isn't visible when the player isn't wearing a hat. I just use override instead of hide/show because it doesn't have its own animations to match hairfront the way hair_hat does to hair.

Link to comment
Share on other sites

20 hours ago, ZupaleX said:

You could add this function in a post sim function and a delay so no matter when your mod is loaded, you will end up modifying all the hats, even the ones which are added by other mods later during the mod loading process, while the AddPrefabPostInitAny will only affect the registered prefab when YOUR mod is loaded

AddPrefabPostInitAny defines a function that will be applied to any prefab that is spawned in.

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