Jump to content

[Question] Adding beefalo behaviour tweak to character mod


Recommended Posts

Hi!

I've just completed a character mod (Nicole & Nando) and I'd like to implement interactions between her and Beefalo. Basic friendliness will do the job as a starting point but after doing some research and finding a few threads (found info for similar functionality for bees and frogs) I'm realizing that beefalo are one of the more complex mobs due to their already-complex interactions with players. 

I've learned that the combat components (IsValidTarget) and modmain.lua (tags) are likely to see changes but this is my first custom behaviour tweak that will require new tags, functions, and component changes in general. I imagine this might involve or conflict with some of the domestication functions in beefalometrics.lua, but those aren't restricted/required on my end. I'll add that I'm a decent coder but new to lua, so bear with me. I haven't posted code but will work at it and update as pointers come in!

Any tips or info on how to proceed with this would be so appreciated. For now I really just want her to be able to be around them and shear them without any issue. 

Thank you for reading! This is a great community. I'm working on a mod tool for character development/testing that I'm excited to share one day soon.

hearteyed-beefalo.png

Link to comment
Share on other sites

I don't know much about Beefalo, especially after all the riding was added, but their combat component is identical to all other entities, so yes, extend their current CanTarget and just check if the target is your prefab, and if so, return false, otherwise, return whatever the original CanTarget function would return.

  • Like 1
Link to comment
Share on other sites

On 2020-01-09 at 10:52 AM, Ultroman said:

I don't know much about Beefalo, especially after all the riding was added, but their combat component is identical to all other entities, so yes, extend their current CanTarget and just check if the target is your prefab, and if so, return false, otherwise, return whatever the original CanTarget function would return.

Thanks! Will go that route. Would you mind giving a really basic example for extending existing functions? I know enough to know that supplying a modified beefalo prefab isn’t ideal but I’m just not sure on syntax for extending. Thanks again 

On 2020-01-30 at 3:59 PM, Skoith said:

There's a custom character mod called 'Wully' on the steam workshop that basically behaves like a beefalo and is not attacked by them, maybe you can find some help there? 

I’ll definitely be taking a peek, appreciate the tip

Link to comment
Share on other sites

For functions which do NOT return anything:

local oldOnDestack = comp.inst.components.stackable.ondestack
comp.inst.components.stackable.ondestack = function(inst)
	-- Do some code stuff
	
	-- Call the existing function, if there was any.
	if oldOnDestack ~= nil then
		oldOnDestack(inst)
	end

	-- Do some code stuff
end


For functions which DO return something:
Pretend that ondestack returns something (which it doesn't!!!). Then what?

local oldOnDestack = comp.inst.components.stackable.ondestack
comp.inst.components.stackable.ondestack = function(inst)
	-- MAYBE do some code stuff, perhaps changing the given parameters or
	-- changing how the existing function is used.
	
	-- Call the existing function, if there was any, and store the result in a variable.
	var result = nil
	if oldOnDestack ~= nil then
		result = oldOnDestack(inst)
	end
	
	-- MAYBE do some code stuff, perhaps changing the result in certain instances.
	-- Or you might just want to trigger a custom event here. Who knows?
	
	return result
end


Another example, where the function returns two variables! Pretend that ondestack returns 2 variables (which it doesn't!!!).

local oldOnDestack = comp.inst.components.stackable.ondestack
comp.inst.components.stackable.ondestack = function(inst)
	-- MAYBE do some code stuff, perhaps changing the given parameters or
	-- changing how the existing function is used.
	
	-- Call the existing function, if there was any, and store the result in a variable.
	var result1 = nil
	var result2 = nil
	if oldOnDestack ~= nil then
		result, result2 = oldOnDestack(inst)
	end
	
	-- MAYBE do some code stuff, perhaps changing the results in certain instances.
	-- Or you might just want to trigger a custom event here. Who knows?
	
	return result, result2
end

An actual example, where I wanted to change the properties of the children spawned by a childspawner.

local oldOnspawned = inst.components.childspawner.onspawned
inst.components.childspawner.onspawned = function(childspawner, child)
    child.components.pollinator.collectcount = 3
    child.components.locomotor.walkspeed = 5.5
    child.components.health:SetMaxHealth(70)
    child.components.combat:SetDefaultDamage(7)
    child.AnimState:SetBuild("honeybee_build")
	
	if oldOnspawned ~= nil then
		oldOnspawned(inst)
	end
end

 

Edited by Ultroman
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

3 hours ago, Ultroman said:

For functions which do NOT return anything:


local oldOnDestack = comp.inst.components.stackable.ondestack
comp.inst.components.stackable.ondestack = function(inst)
	-- Do some code stuff
	
	-- Call the existing function, if there was any.
	if oldOnDestack ~= nil then
		oldOnDestack(inst)
	end
end


For functions which DO return something:
Pretend that ondestack returns something. Then what?


local oldOnDestack = comp.inst.components.stackable.ondestack
comp.inst.components.stackable.ondestack = function(inst)
	-- MAYBE do some code stuff, perhaps changing the given parameters or
	-- changing how the existing function is used.
	
	-- Call the existing function, if there was any, and store the result in a variable.
	var result = nil
	if oldOnDestack ~= nil then
		result = oldOnDestack(inst)
	end
	
	-- MAYBE do some code stuff, perhaps changing the result in certain instances.
	-- Or you might just want to trigger a custom event here. Who knows?
	
	return result
end

 

An actual example, where I wanted to change the properties of the children spawned by a childspawner.


local oldOnspawned = inst.components.childspawner.onspawned
inst.components.childspawner.onspawned = function(childspawner, child)
    child.components.pollinator.collectcount = 3
    child.components.locomotor.walkspeed = 5.5
    child.components.health:SetMaxHealth(70)
    child.components.combat:SetDefaultDamage(7)
    child.AnimState:SetBuild("honeybee_build")
	
	if oldOnspawned ~= nil then
		oldOnspawned(inst)
	end
end

 

Thanks for this. Really appreciate you taking the time.

  • Like 1
Link to comment
Share on other sites

 

44 minutes ago, Ultroman said:

You're welcome! :) This post goes into my "Tutorial links.txt" file :D

So at the moment I've solved the friendliness issue by giving Nicole the 'beefalo' tag. That takes care of a lot of things, but not the shaving while awake problem. I was able to get that working by changing prefabs/beefalo.lua, specifically the CanShaveTest function from:

local function CanShaveTest(inst)
    if inst.components.sleeper:IsAsleep() then
        return true
    else
        return false, "AWAKEBEEFALO"
    end
end

...to:

local function CanShaveTest(inst)
    local player = GetClosestInstWithTag("player", inst, 2)
    if inst.components.sleeper:IsAsleep() or player ~= nil and player:HasTag("Nicole") then 
        return true
    else
        return false, "AWAKEBEEFALO"
    end
end

 

But, I'd rather extend it instead of including a modified prefabs/beefalo.lua file like you've been helping me with. So it looks like you're extending component functions in your (awesome) examples, what about if the target function is in a prefab? Is that something we can do? Also which file should the extension be in? nicole.lua or modmain.lua?

Edited by ry3bread
Additional question
Link to comment
Share on other sites

On 9.3.2020 at 11:25 PM, ry3bread said:

But, I'd rather extend it instead of including a modified prefabs/beefalo.lua file like you've been helping me with. So it looks like you're extending component functions in your (awesome) examples, what about if the target function is in a prefab? Is that something we can do?

Good boy...or girl...or whatever :)

Bad news is you cannot extend a local function. They are not accessible from outside their scope.
Good news is, if you see where CanShaveTest is used, it's like this:

inst.components.beard.canshavetest = CanShaveTest

This is the only place it's used. This means that the non-local "canshavetest" variable/reference on the beard component is set to refer to the local CanShaveTest function. What you can do, is extend inst.components.beard.canshavetest in an AddPrefabPostInit call on the beefalo prefabs (I believe there are more beefalo prefabs than just "beefalo", at least "babybeefalo"). This code goes in your modmain.lua. Make one for each prefab:

AddPrefabPostInit("beefalo", function(inst)
	-- Code here
end)

 

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