Jump to content

Giving a character a Crock Pot at start?


Recommended Posts

Hello you wonderful community! I've been modding a character for DST the past week now. I've so far done custom speech, stats, etc. However, there has been one small problem....

As soon as the player starts, I wanted to give them a Crock Pot to start with. (You can probably guess who this mod is for). I do know the possibilties and the know-how to give a character a starting item, just not one for an item that can't be kept in the inventory in the first place. Or maybe my scripting isn't as good as I thought!


local MakePlayerCharacter = require "prefabs/player_common"

local assets = {
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
}
local prefabs = {}

-- Custom starting items
local start_inv = {
"spear"
}

-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when reviving from ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "gordonramsay_speed_mod", 1)
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
   inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "gordonramsay_speed_mod")
end

-- When loading or spawning the character
local function onload(inst)
    inst:ListenForEvent("ms_respawnedfromghost", onbecamehuman)
    inst:ListenForEvent("ms_becameghost", onbecameghost)

    if inst:HasTag("playerghost") then
        onbecameghost(inst)
    else
        onbecamehuman(inst)
    end
end


-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "gordonramsay.tex" )
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- choose which sounds this character will play
	inst.soundsname = "wilson"
	
	-- Uncomment if "wathgrithr"(Wigfrid) or "webber" voice is used
    --inst.talker_path_override = "dontstarve_DLC001/characters/"
	
	-- Stats	
	inst.components.health:SetMaxHealth(225)
	inst.components.hunger:SetMax(200)
	inst.components.sanity:SetMax(150)
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE
	
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	
end

return MakePlayerCharacter("gordonramsay", prefabs, assets, common_postinit, master_postinit, start_inv)

Any kind soul out there willing to help? :) 

Thank you in advance!

Edited by ITSRAW
Link to comment
Share on other sites

As far as i know, crockpot can't be given this way because it's not an item, it's a structure.

I know it's possible to start with a structure "unlocked" and maybe ready to be deployed... I'll try to see if i find a topic about it because i don't remember how to do it.

But if i don't find it and if you don't have any answer, i have an ugly way to do it : give the crockpot blueprint and the crockpot material as starting item. I hope someone will give a better solution.

 

Edit

 

You should find some answer about how to have a recipe unlocked (so crockpot here), but it will not "give" the crockpot, just the ability to build it. I think the code still work. I don't find the other code...

Edited by Lumina
Link to comment
Share on other sites

28 minutes ago, Lumina said:

As far as i know, crockpot can't be given this way because it's not an item, it's a structure.

I know it's possible to start with a structure "unlocked" and maybe ready to be deployed... I'll try to see if i find a topic about it because i don't remember how to do it.

But if i don't find it and if you don't have any answer, i have an ugly way to do it : give the crockpot blueprint and the crockpot material as starting item. I hope someone will give a better solution.

Yeah, that is what I thought as well. Never really could hold a structure in my inventory before either. (Except for the walls) I appreciate your help and willing to give me a hand! I'll keep look along side you. :D 

If nothing can be done about it, I think that suggestion you gave about the blueprint will work just as nicely as well. Once again, thank you, as I appreciate it very much. :]

Edit for your edit: Appreciate it! That could work, I'll take a look into it. :) Hopefully someone can come along as think of a script for this kind of thing though. Otherwise, will just need to use that workaround!

Edited by ITSRAW
Link to comment
Share on other sites

This thing here took me 3 hours to get it right, enjoy:

local ACTIONS = GLOBAL.ACTIONS
local ActionHandler = GLOBAL.ActionHandler
local SpawnPrefab = GLOBAL.SpawnPrefab

function MovableCrockpotPostInit(inst)
    if GLOBAL.TheWorld.ismastersim then
		local function ondeploy(inst, pt)
			local cookpot = SpawnPrefab("cookpot")
			if cookpot ~= nil then
				cookpot.Transform:SetPosition(pt:Get())
				cookpot.SoundEmitter:PlaySound("dontstarve/common/cook_pot_craft")
				inst:Remove()
			end
		end
	
		if not inst.components.deployable then
			inst:AddComponent("deployable")
		end
		inst.components.deployable.ondeploy = ondeploy
		
		if not inst.components.inventoryitem then
			inst:AddComponent("inventoryitem")
		end
		inst.components.inventoryitem.canbepickedup = false
		
		inst:AddTag("crockpot_regular")
		
		inst:ListenForEvent("onputininventory", function() 
			if inst.components.container then
				if inst.components.container:IsOpen() then
					inst.components.container:Close()
				end
				inst.components.container.canbeopened = false
			end
		end)
		
		inst:ListenForEvent("gotnewitem", function() 
			if inst.components.container and inst.components.container.canbeopened == true then
				inst.components.container:Open()
			end
		end)
		
    end
end 
AddPrefabPostInit("cookpot", MovableCrockpotPostInit)

-- Make a special action to pick up Crockpot only by a special character with rmb
local CROCKPOTPICKUP = GLOBAL.Action({ priority=10 })	
CROCKPOTPICKUP.str = "Pick up"
CROCKPOTPICKUP.id = "CROCKPOTPICKUP"
CROCKPOTPICKUP.fn = function(act)
	if act.doer.components.inventory ~= nil and
        act.target ~= nil and
        act.target.components.inventoryitem ~= nil and
		act.target.prefab == "cookpot" and
		not act.target:HasTag("burnt") and
		(act.target.components.container and not act.target.components.container:IsOpen() and act.target.components.container:IsEmpty()) and
		act.target.components.stewer and act.target.components.stewer.product == nil and not act.target.components.stewer:IsCooking() then

        act.doer:PushEvent("onpickupitem", { item = act.target })
		act.doer.components.inventory:GiveItem(act.target, nil, act.target:GetPosition())
        return true
	
	elseif act.target:HasTag("burnt") then
		return false, "ISBURNT"
		
	elseif not act.target:HasTag("burnt") and 
		   act.target.components.container and not act.target.components.container:IsEmpty() and
		   act.target.components.stewer and not act.target.components.stewer:IsCooking() then
		return false, "ISFULL"
		
	elseif not act.target:HasTag("burnt") and 
		   (act.target.components.container and not act.target.components.container:IsEmpty() or
		   act.target.components.stewer and act.target.components.stewer.product ~= nil or
		   act.target.components.container and act.target.components.container:IsOpen()) then
		return false, "ISCOOKING"
	
    end
end
AddAction(CROCKPOTPICKUP)

AddComponentAction("SCENE", "inventoryitem", function(inst, doer, actions, right)
    if right and doer.replica.inventory ~= nil and doer:HasTag("crockpot_pickuper") and inst:HasTag("crockpot_regular") and not inst:HasTag("fire") then
        table.insert(actions, ACTIONS.CROCKPOTPICKUP)
    end
end)
AddStategraphActionHandler("wilson_client", crockpotpickup_handler)

local placecrockpot_handler = ActionHandler(ACTIONS.CROCKPOTPICKUP, function(inst)
	return "doshortaction"
end)
AddStategraphActionHandler("wilson", placecrockpot_handler)

local  placecrockpot_handler_client = ActionHandler(ACTIONS.CROCKPOTPICKUP, "doshortaction")
AddStategraphActionHandler("wilson_client", placecrockpot_handler_client)

GLOBAL.STRINGS.CHARACTERS.GENERIC.ACTIONFAIL.CROCKPOTPICKUP = {
	ISBURNT = "I can't pick it up, it's all burnt up.",
	ISCOOKING = "I can't pick it up, it's being used!",
	ISFULL = "I should empty it before picking it up!",
}

-- Regular "dropping" the item from inventory causes really troublesome bugs, so here we go with a custom action:

local PLACECROCKPOT = GLOBAL.Action({ priority= 10, distance= 1.1})	
PLACECROCKPOT.str = "Plant"
PLACECROCKPOT.id = "PLACECROCKPOT"
PLACECROCKPOT.fn = function(act)
	if act.invobject and act.invobject.components.deployable and act.invobject.components.deployable:CanDeploy(act.pos) then
        if act.invobject then
            if act.invobject.components.deployable:Deploy(act.pos, act.doer, act.rotation) then
                return true
            else
                act.doer.components.inventory:GiveItem(act.invobject)
            end
        end
    end
end
AddAction(PLACECROCKPOT)

AddComponentAction("POINT", "deployable", function(inst, doer, pos, actions, right)
    if not right and doer and inst and inst:HasTag("crockpot_regular") and inst.replica and inst.replica.inventoryitem and inst.replica.inventoryitem:IsHeldBy(doer) then
        table.insert(actions, ACTIONS.PLACECROCKPOT)
    end
end)
AddStategraphActionHandler("wilson_client", placecrockpot_handler)

local placecrockpot_handler = ActionHandler(ACTIONS.PLACECROCKPOT, function(inst)
	return "doshortaction"
end)
AddStategraphActionHandler("wilson", placecrockpot_handler)

local  placecrockpot_handler_client = ActionHandler(ACTIONS.PLACECROCKPOT, "doshortaction")
AddStategraphActionHandler("wilson_client", placecrockpot_handler_client)

Put this in your modmain.

And add a "crockpot_pickuper" tag to your character.

Edited by PanAzej
there may still be some bugs here though, but I'll leave fixing them to you
Link to comment
Share on other sites

@PanAzej

Oh. my. god. You're a HERO and lifesaver! You taking that much time out of your day for a random use like me. :o I am truly grateful and will not disappoint you! From the bottom of my heart, THANK YOU!

If only there were an option to like a post more than once.... :) 

Only question is this. How exactly would I add a 'tag' to my character? Sorry to be more of a problem, but not really a pro at this modding yet. x) 

Edited by ITSRAW
Link to comment
Share on other sites

2 hours ago, ITSRAW said:

I am truly grateful and will not disappoint you! From the bottom of my heart, THANK YOU!

No problem!

2 hours ago, ITSRAW said:

Only question is this. How exactly would I add a 'tag' to my character? Sorry to be more of a problem, but not really a pro at this modding yet. x) 

Add this in your common_postinit function:

inst:AddTag("crockpot_pickuper")

The "picking up crockpot" action is exclusive to characters with this tag.

Link to comment
Share on other sites

1 hour ago, Lumina said:

I'm so happy when i see people like you providing amazing code like this !

Thank you!

"gotnewitem" eventlistener is broken, though. I mean, it doesn't do anything.

The major bug with this code is that the Crockpot won't automatically open when you put items in it anymore. It could be fixed with yet another action, I think.

Also, mobs like frogs can drop the Crockpot from the inventory, causing it to collide with character and in the end 'hover' in the air. That could also be fixed with workarounds. Probably removing colliders while putting it in inventory would work.

But yeah, it's mostly working.

Edited by PanAzej
yes
Link to comment
Share on other sites

@PanAzej

Found it! Thank you! How I know I found it, is that it sadly gave an error to me when I booted up the server. :/

Error message I get is: :39: ')' expected near 'inst'

I've even tried adding that, but I get the same error message, but instead says ')' expected near ':'

I attached an image to make it easier. :) 

Here is my character lua:

 


local MakePlayerCharacter = require "prefabs/player_common"

local assets = {
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
}
local prefabs = {}

-- Custom starting items
local start_inv = {
"spear"
}

-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when reviving from ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "gordonramsay_speed_mod", 1)
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
   inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "gordonramsay_speed_mod")
end

-- When loading or spawning the character
local function onload(inst)
    inst:ListenForEvent("ms_respawnedfromghost", onbecamehuman)
    inst:ListenForEvent("ms_becameghost", onbecameghost)

    if inst:HasTag("playerghost") then
        onbecameghost(inst)
    else
        onbecamehuman(inst)
    end
end


-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function inst:AddTag("crockpot_pickuper") 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "gordonramsay.tex" )
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- choose which sounds this character will play
	inst.soundsname = "wilson"
	
	-- Uncomment if "wathgrithr"(Wigfrid) or "webber" voice is used
    --inst.talker_path_override = "dontstarve_DLC001/characters/"
	
	-- Stats	
	inst.components.health:SetMaxHealth(225)
	inst.components.hunger:SetMax(200)
	inst.components.sanity:SetMax(150)
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE
	
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	
end

return MakePlayerCharacter("gordonramsay", prefabs, assets, common_postinit, master_postinit, start_inv)

And my modmain lua:

PrefabFiles = {
	"gordonramsay",
	"gordonramsay_none",
}
local ACTIONS = GLOBAL.ACTIONS
local ActionHandler = GLOBAL.ActionHandler
local SpawnPrefab = GLOBAL.SpawnPrefab

function MovableCrockpotPostInit(inst)
    if GLOBAL.TheWorld.ismastersim then
		local function ondeploy(inst, pt)
			local cookpot = SpawnPrefab("cookpot")
			if cookpot ~= nil then
				cookpot.Transform:SetPosition(pt:Get())
				cookpot.SoundEmitter:PlaySound("dontstarve/common/cook_pot_craft")
				inst:Remove()
			end
		end
	
		if not inst.components.deployable then
			inst:AddComponent("deployable")
		end
		inst.components.deployable.ondeploy = ondeploy
		
		if not inst.components.inventoryitem then
			inst:AddComponent("inventoryitem")
		end
		inst.components.inventoryitem.canbepickedup = false
		
		inst:AddTag("crockpot_regular")
		
		inst:ListenForEvent("onputininventory", function() 
			if inst.components.container then
				if inst.components.container:IsOpen() then
					inst.components.container:Close()
				end
				inst.components.container.canbeopened = false
			end
		end)
		
		inst:ListenForEvent("gotnewitem", function() 
			if inst.components.container and inst.components.container.canbeopened == true then
				inst.components.container:Open()
			end
		end)
		
    end
end 
AddPrefabPostInit("cookpot", MovableCrockpotPostInit)

-- Make a special action to pick up Crockpot only by a special character with rmb
local CROCKPOTPICKUP = GLOBAL.Action({ priority=10 })	
CROCKPOTPICKUP.str = "Pick up"
CROCKPOTPICKUP.id = "CROCKPOTPICKUP"
CROCKPOTPICKUP.fn = function(act)
	if act.doer.components.inventory ~= nil and
        act.target ~= nil and
        act.target.components.inventoryitem ~= nil and
		act.target.prefab == "cookpot" and
		not act.target:HasTag("burnt") and
		(act.target.components.container and not act.target.components.container:IsOpen() and act.target.components.container:IsEmpty()) and
		act.target.components.stewer and act.target.components.stewer.product == nil and not act.target.components.stewer:IsCooking() then

        act.doer:PushEvent("onpickupitem", { item = act.target })
		act.doer.components.inventory:GiveItem(act.target, nil, act.target:GetPosition())
        return true
	
	elseif act.target:HasTag("burnt") then
		return false, "ISBURNT"
		
	elseif not act.target:HasTag("burnt") and 
		   act.target.components.container and not act.target.components.container:IsEmpty() and
		   act.target.components.stewer and not act.target.components.stewer:IsCooking() then
		return false, "ISFULL"
		
	elseif not act.target:HasTag("burnt") and 
		   (act.target.components.container and not act.target.components.container:IsEmpty() or
		   act.target.components.stewer and act.target.components.stewer.product ~= nil or
		   act.target.components.container and act.target.components.container:IsOpen()) then
		return false, "ISCOOKING"
	
    end
end
AddAction(CROCKPOTPICKUP)

AddComponentAction("SCENE", "inventoryitem", function(inst, doer, actions, right)
    if right and doer.replica.inventory ~= nil and doer:HasTag("crockpot_pickuper") and inst:HasTag("crockpot_regular") and not inst:HasTag("fire") then
        table.insert(actions, ACTIONS.CROCKPOTPICKUP)
    end
end)
AddStategraphActionHandler("wilson_client", crockpotpickup_handler)

local placecrockpot_handler = ActionHandler(ACTIONS.CROCKPOTPICKUP, function(inst)
	return "doshortaction"
end)
AddStategraphActionHandler("wilson", placecrockpot_handler)

local  placecrockpot_handler_client = ActionHandler(ACTIONS.CROCKPOTPICKUP, "doshortaction")
AddStategraphActionHandler("wilson_client", placecrockpot_handler_client)

GLOBAL.STRINGS.CHARACTERS.GENERIC.ACTIONFAIL.CROCKPOTPICKUP = {
	ISBURNT = "I can't pick it up, it's all burnt up.",
	ISCOOKING = "I can't pick it up, it's being used!",
	ISFULL = "I should empty it before picking it up!",
}

-- Regular "dropping" the item from inventory causes really troublesome bugs, so here we go with a custom action:

local PLACECROCKPOT = GLOBAL.Action({ priority= 10, distance= 1.1})	
PLACECROCKPOT.str = "Plant"
PLACECROCKPOT.id = "PLACECROCKPOT"
PLACECROCKPOT.fn = function(act)
	if act.invobject and act.invobject.components.deployable and act.invobject.components.deployable:CanDeploy(act.pos) then
        if act.invobject then
            if act.invobject.components.deployable:Deploy(act.pos, act.doer, act.rotation) then
                return true
            else
                act.doer.components.inventory:GiveItem(act.invobject)
            end
        end
    end
end
AddAction(PLACECROCKPOT)

AddComponentAction("POINT", "deployable", function(inst, doer, pos, actions, right)
    if not right and doer and inst and inst:HasTag("crockpot_regular") and inst.replica and inst.replica.inventoryitem and inst.replica.inventoryitem:IsHeldBy(doer) then
        table.insert(actions, ACTIONS.PLACECROCKPOT)
    end
end)
AddStategraphActionHandler("wilson_client", placecrockpot_handler)

local placecrockpot_handler = ActionHandler(ACTIONS.PLACECROCKPOT, function(inst)
	return "doshortaction"
end)
AddStategraphActionHandler("wilson", placecrockpot_handler)

local  placecrockpot_handler_client = ActionHandler(ACTIONS.PLACECROCKPOT, "doshortaction")
AddStategraphActionHandler("wilson_client", placecrockpot_handler_client)
local starting_inv =
{
    "spear",
}

Assets = {
    Asset( "IMAGE", "images/saveslot_portraits/gordonramsay.tex" ),
    Asset( "ATLAS", "images/saveslot_portraits/gordonramsay.xml" ),

    Asset( "IMAGE", "images/selectscreen_portraits/gordonramsay.tex" ),
    Asset( "ATLAS", "images/selectscreen_portraits/gordonramsay.xml" ),
	
    Asset( "IMAGE", "images/selectscreen_portraits/gordonramsay_silho.tex" ),
    Asset( "ATLAS", "images/selectscreen_portraits/gordonramsay_silho.xml" ),

    Asset( "IMAGE", "bigportraits/gordonramsay.tex" ),
    Asset( "ATLAS", "bigportraits/gordonramsay.xml" ),
	
	Asset( "IMAGE", "images/map_icons/gordonramsay.tex" ),
	Asset( "ATLAS", "images/map_icons/gordonramsay.xml" ),
	
	Asset( "IMAGE", "images/avatars/avatar_gordonramsay.tex" ),
    Asset( "ATLAS", "images/avatars/avatar_gordonramsay.xml" ),
	
	Asset( "IMAGE", "images/avatars/avatar_ghost_gordonramsay.tex" ),
    Asset( "ATLAS", "images/avatars/avatar_ghost_gordonramsay.xml" ),
	
	Asset( "IMAGE", "images/avatars/self_inspect_gordonramsay.tex" ),
    Asset( "ATLAS", "images/avatars/self_inspect_gordonramsay.xml" ),
	
	Asset( "IMAGE", "images/names_gordonramsay.tex" ),
    Asset( "ATLAS", "images/names_gordonramsay.xml" ),
	
    Asset( "IMAGE", "bigportraits/gordonramsay_none.tex" ),
    Asset( "ATLAS", "bigportraits/gordonramsay_none.xml" ),

}

local require = GLOBAL.require
local STRINGS = GLOBAL.STRINGS

-- The character select screen lines
STRINGS.CHARACTER_TITLES.gordonramsay = "The Chef"
STRINGS.CHARACTER_NAMES.gordonramsay = "Esc"
STRINGS.CHARACTER_DESCRIPTIONS.gordonramsay = "*Is an extremely picky eater\n*Starts with crock pot and gains extra effects\n*Is very tough"
STRINGS.CHARACTER_QUOTES.gordonramsay = "\"IT'S RAWWWWW\""

-- Custom speech strings
STRINGS.CHARACTERS.GORDONRAMSAY = require "speech_gordonramsay"

-- The character's name as appears in-game 
STRINGS.NAMES.gordonramsay = "Esc"

AddMinimapAtlas("images/map_icons/gordonramsay.xml")

-- Add mod character to mod character list. Also specify a gender. Possible genders are MALE, FEMALE, ROBOT, NEUTRAL, and PLURAL.
AddModCharacter("gordonramsay", "MALE")

 

I appreciate the help! :D Error.png

Edited by ITSRAW
Link to comment
Share on other sites

-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "gordonramsay.tex" )
	-- Tags
	inst:AddTag("crockpot_pickuper")
end

 

Link to comment
Share on other sites

Awesome, thank you! No error messages here. :) Atm no crock pot is spawning when I spawn in the world, but that can be just something in the script possibly not working. So far it seems I've done everything right(thanks to you) but do you have any ideas for a fix? Not rushing or anything, just don't want this marvelous script to got to waste. :) 

Link to comment
Share on other sites

Tested it. Cooked with it. Played with it. WORKS PERFECT! Words can not describe how appreciative I am right now... Thank you so much my friend, it would be a great honor if I could add you as a contributor when the character goes live on Steam. :D

If there is anything I can ever do for you, just let me know. ;)

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