Jump to content

Give Specific Character bonus from eating Modded Food


Recommended Posts

Hello! I'm creating my first modded character for Don't Starve Together, and he has the ability to craft a food item. Its prefab is called saltpop. My plan for the Salt Pop is to have every character except for my modded character lose sanity when they eat it. I've also made my character gain 5 more hunger than usual when they eat it.

This is what I'm doing (saltpop.lua) to try and get this working:

if eater:HasTag("saltpopbuilder") then --If the Character eats it
    	eater.components.hunger:DoDelta(5) -- 5 (extra?) hunger (does this stack on top of predefined values?)
	
	else --if literally anyone else eats it
		eater.components.sanity:DoDelta(-3) -- they lose sanity, sad day for them
	end

My character has the tag saltpopbuilder (Which allows them to craft the prefab in the first place), but I get an error:

[00:00:24]: error calling LoadPrefabFile in mod Richdude (itsMiatch's Character): 
[string "../mods/Richdude/scripts/prefabs/saltpop"]:3: variable 'eater' is not declared

I've looked around a tiny bit and notice that other users have occasionally had similar errors (e.g. with GetRecipe and OnTurnOn), and have been advised to switch do a DST-friendly variable (AllRecipes), or make their variable local, respectively. I personally have no clue how to make a variable local. I have tried the following configuration:

if local eater:HasTag("saltpopbuilder") then --If the Character eats it
    	eater.components.hunger:DoDelta(5) -- 5 (extra?) hunger (does this stack on top of predefined values?)
	
	else --if literally anyone else eats it
		eater.components.sanity:DoDelta(-3)
	end

which yielded the following error:

[00:00:37]: error calling LoadPrefabFile in mod Richdude (Miatch's Character): 
[string "scripts/mainfunctions.lua"]:150: Error loading file prefabs/saltpop
[string "../mods/Richdude/scripts/prefabs/saltpop.lua"]:3: unexpected symbol near 'local'

And I have also tried setting up a new local variable based off a global variable:

local eater = GLOBAL.eater

which yielded the following error:

[00:00:26]: error calling LoadPrefabFile in mod Richdude (Miatch's Character): 
[string "../mods/Richdide/scripts/prefabs/saltpop"]:1: variable 'GLOBAL' is not defined

Regarding finding a DST-Friendly alternative to 'eater', I wouldn't know where to begin. :I

I'd like to know if there's anything I could do to get my own code to work. Failing that, I'd appreciate code sent my way that does work.

Thanks in advance for any solutions, workarounds, let-downs, or other instances of help!

Link to comment
Share on other sites

The first code snippet you have is fine, but since it's telling you that there is no eater, you must have put it in the wrong place. You need to add an oneatenfn (a function automatically called when the food is eaten) to your food-prefab's edible component. This function is called by the edible component of the food-prefab when the food is eaten, before the predefined values are applied.

In your food prefab's fn() or postinit() function AFTER the edible component has been added, put this in:

inst.components.edible:SetOnEatenFn(function(food, eater)
	-- Do something special when the food is eaten.
	--If the Character eats it...
	if eater:HasTag("saltpopbuilder") then
		-- Give 5 extra hunger, on top of what the food already gives.
		-- We put in a safe-guard, since some characters may not have a hunger component.
		if eater.components.hunger then
    		eater.components.hunger:DoDelta(5)
		end
	-- If anyone else eats it...
	else
		-- Remove 3 sanity from them
		-- We put in a safe-guard, since some characters may not have a sanity component.
		if eater.components.sanity then
			eater.components.sanity:DoDelta(-3) -- they lose sanity, sad day for them
		end
	end
end)

 

If you're getting into modding, I would really recommend you check out my newcomer post. It WILL save you LOADS of time, and get you across the most annoying hurdles, and teach you a way to debug your code easily. I hope you don't mind me saying this, but some of your suggestions led me to think that you don't know much LUA syntax, and I just gotta tell you...throwing things at the wall to see what sticks gets old really fast, and you're gonna have a bad time :) You can really ease your life and save precious hours and days slaving over mistakes of ignorance, if you take a day or two of tutorials and just reading code from the game or other mods, to see how things work. You don't have to understand every single line, but trust me, things start to sink in along the way, and suddenly you have this halleluja moment where "it all fits together", and after a few of those, and maybe a few weeks more, you'll start getting to feel like a programmer, which means you'll be thinking things like "why the f... is it built like this" a lot ;)

Good luck, m8! We'll be here waiting for your questions.

Edited by Ultroman
Link to comment
Share on other sites

Thanks so much for the help! I can now enjoy my Salt Pops in peace.

You're correct, I'm not well-versed in lua, but I hope to learn as much as I can -- I'm interested in quite a few points mentioned in the post you linked to.

IOiDhlk.png

Edited by itsMiatch
I HIT CONTROL ENTER INSTEAD OF ENTER
Link to comment
Share on other sites

Hahah, glad to hear it works :D You're very welcome! If you've got animations and all that working, you've aready covered some pretty shifty grounds, so I have a lot of hope for you ;) That's some nice-looking sprites, there. Really fitting the style of the game. Great job!

Link to comment
Share on other sites

Aw, thanks for the compliment! ^-^ I like to think I'm putting in effort for the mod's art.

...Ooh, ooh! -- Sorry to demand your time again...

Similarly to having a food item only benefit my character, I'm helping someone with another character who brings a sword.

This person wants their character to deal extra damage (and have a larger attack range) when using the sword compared to other characters. I've only recently learnt about tags and really like them, and I figured one way to start off would be to convert the script you suggested into something for this character.

I've gone right back to basics --

if holder:HasTag("swordsman") then
		-- Make the weapon super cool
		inst.components.weapon:SetRange(1.5)
		inst.components.weapon:SetDamage(TUNING.SPEAR_DAMAGE + TUNING.SPEAR_DAMAGE / 6)
	else
		-- Bland and boring weapon
		inst.components.weapon:SetRange(1)
		inst.components.weapon:SetDamage(TUNING.SPEAR_DAMAGE - TUNING.SPEAR_DAMAGE / 6)
	end

There are very likely a lot of invalid things about this section of code, currently placed in the sword's prefab file (customsword.lua). I have confirmed this by checking out the crash log that generated when trying to run the mod -- variable 'holder' is not defined.

What variable/component?/code should I use here to result in the sword:

- Doing more damage if the specific modded character holds it
- Doing less damage if another character holds it
- Updating the damage it deals when changing hands, instead of, say, getting stuck at the modded character's bonus

(also, possibly but not at all required if you don't have unlimited leisure time, have the character do slightly more with pre-existing sword items such as the Nightmare Sword)

I'm so sorry for being dependent and taking up time and all that, especially on the same post as before. Please inform me if, next time, I should create a new post and conduct further reading before asking for help.

Thanks in advance for any solutions, workarounds, let-downs, or other instances of help! I can't say with enough meaning that you're doing the modders, confused-newbie and furious-veterans alike, a great service; we all appreciate it very much.

Link to comment
Share on other sites

It's always best to create a new thread for new topics.

That said, I think what you're looking for is a way to alter all sword weapons by whether the user has that specific tag. That's not hard at all.

Put this in your friend's modmain, and fill out the prefab_list with all the weapons you want to affect. You can even include weapons from other mods. You COULD make this code affect all weapons with the "sharp" tag instead, but that would also include blowdarts. It's not really likely that tags will be consistently applied, so I always prefer to just rely on a manually filled list. This approach applies the same augmentation to all weapons. I've added an example below where you can make different settings to the individual weapons.

-- List of weapons we want to affect.
local prefab_list = {
	"nightsword",
	"spear",
}

local augmentWeapon = function(inst, owner)
	if owner:HasTag("swordsman") then
		inst.components.weapon:SetRange(inst.components.weapon.origattackrange * 1.5)
		inst.components.weapon:SetDamage(inst.components.weapon.origdamage + (inst.components.weapon.origdamage / 6))
	else
		inst.components.weapon:SetRange(inst.components.weapon.origattackrange)
		inst.components.weapon:SetDamage(inst.components.weapon.origdamage)
	end
end

-- Loop/iterate through the contents of prefab_list. I am using ipairs since we have a list
-- and not a dictionary. ipairs gives you two variables per list entry; the first is the index,
-- which I have named "i", and the second is the value, which I have named "v".
-- As such, "v" is one of the strings in the list. So, for each of the strings in the list...
for i,v in ipairs(prefab_list) do
	-- ...call AddPrefabPostInit, using the string (v) to denote the prefab we want to change.
	-- AddPrefabPostInit will ensure that ALL instances of the prefab with this name, will have
	-- the given function run for it, where the inst parameter is the instance of the prefab.
	AddPrefabPostInit(v, function(inst)
		-- Save the original settings to new variables on the weapon component.
		inst.components.weapon.origdamage = inst.components.weapon.damage
		inst.components.weapon.origattackrange = inst.components.weapon.attackrange
		
		-- Extend the existing, or set a new, onequipfn.
		-- That is a function called in the equippable component whenever
		-- someone (also e.g. pigmen) equip the weapon.
		local old_onequipfn = inst.components.equippable.onequipfn
		if old_onequipfn ~= nil then
			inst.components.equippable.onequipfn = function(inst, owner)
				old_onequip(inst, owner)
				augmentWeapon(inst, owner)
			end
		else
			inst.components.equippable.onequipfn = augmentWeapon
		end
	end)
end

 

Here's another approach, using a dictionary instead, so you can set different values for each weapon.
DISCLAIMER: I'm not entirely sure that it's possible for me to pass the value of "v" as a parameter for augmentweapon the way I do right now. If it doesn't work, we'll just have to look up the weapon in the prefab_dict, and get the data from there.

-- Dictionary of weapons we want to affect, and their settings.
-- Nightsword gets 50% more attack range and +35% damage, while
-- Spear gets 30% more attack range and +20% damage.
-- You can make the values negative to make him worse at using the weapon.
local prefab_dict = {
	["nightsword"] = {50, 35},
	["spear"] = {30, 20},
}

local augmentWeapon = function(inst, owner, data)
	if owner:HasTag("swordsman") then
		inst.components.weapon:SetRange(inst.components.weapon.origattackrange + (inst.components.weapon.origdamage * data[1]))
		inst.components.weapon:SetDamage(inst.components.weapon.origdamage + (inst.components.weapon.origdamage * data[2]))
	else
		inst.components.weapon:SetRange(inst.components.weapon.origattackrange)
		inst.components.weapon:SetDamage(inst.components.weapon.origdamage)
	end
end

-- Loop/iterate through the contents of prefab_dict. I am using pairs since we have a dictionary
-- pairs gives you two variables per dictionary entry; the first is the key, which I have named "k",
-- and the second is the value, which I have named "v".
-- As such, "k" is one of the strings in the list, and "v" is the data-list.
-- So, for each of the entries in the list...
for k,v in ipairs(prefab_dict) do
	-- ...call AddPrefabPostInit, using the string (v) to denote the prefab we want to change.
	-- AddPrefabPostInit will ensure that ALL instances of the prefab with this name, will have
	-- the given function run for it, where the inst parameter is the instance of the prefab.
	AddPrefabPostInit(k, function(inst)
		-- Save the original settings to new variables on the weapon component.
		inst.components.weapon.origdamage = inst.components.weapon.damage
		inst.components.weapon.origattackrange = inst.components.weapon.attackrange
		
		-- Extend the existing, or set a new, onequipfn.
		-- That is a function called in the equippable component whenever
		-- someone (also e.g. pigmen) equip the weapon.
		local old_onequipfn = inst.components.equippable.onequipfn
		if old_onequipfn ~= nil then
			inst.components.equippable.onequipfn = function(inst, owner)
				old_onequip(inst, owner)
				augmentWeapon(inst, owner, v)
			end
		else
			inst.components.equippable.onequipfn = augmentWeapon
		end
	end)
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...