Arestless Posted October 25, 2019 Share Posted October 25, 2019 I'm extremely new to making mods, and I'm trying to figure out how to give my character the ability to sleep at night while being unable to sleep during the day. I just can't seem to figure out how, so... how? Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/ Share on other sites More sharing options...
Ultroman Posted October 26, 2019 Share Posted October 26, 2019 (edited) This is no small feat, since the player doesn't control which time of day they can sleep. The bedrolls, tent and siestahut and the character's stategraph controls those things. I made a mod called Sleepy Time which allows you to set at which times of day bedrolls, tents and/or siestahuts can be used, and I ended up having to edit the "bedroll" and "tent" states to do it. This seems like a lot of work to have to go through, to do something you'd think many people want to mess with; their character's sleep cycle. But there you go. Go subscribe to Sleepy Time on the Steam Workshop and check out the code. It should be well commented, and if not, I apologize Edited October 26, 2019 by Ultroman Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/#findComment-1276689 Share on other sites More sharing options...
Arestless Posted October 27, 2019 Author Share Posted October 27, 2019 (edited) On 10/25/2019 at 8:39 PM, Ultroman said: This is no small feat, since the player doesn't control which time of day they can sleep. The bedrolls, tent and siestahut and the character's stategraph controls those things. I made a mod called Sleepy Time which allows you to set at which times of day bedrolls, tents and/or siestahuts can be used, and I ended up having to edit the "bedroll" and "tent" states to do it. This seems like a lot of work to have to go through, to do something you'd think many people want to mess with; their character's sleep cycle. But there you go. Go subscribe to Sleepy Time on the Steam Workshop and check out the code. It should be well commented, and if not, I apologize Thanks a bunch for this! I took a look, but like I said I'm extremely new to this. Any specific code I should be looking at? Edited October 27, 2019 by Arestless Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/#findComment-1277155 Share on other sites More sharing options...
Ultroman Posted October 27, 2019 Share Posted October 27, 2019 This would be the simplified version, which shows how to change just one state. All of this in modmain. Understand, though, that this overwrites the state, so if any other mod also does this, one or the other mod won't work. local function addState(SGname, state) print("addState") for k,v in pairs(_G.SGManager.instances) do if(k.sg.name == SGname) then k.sg.states[state.name] = state break end end end local function ChangeBedrollAndTentStateDST(inst) -- Override host bedroll-state addState("wilson", _G.State{ name = "bedroll", tags = { "bedroll", "busy", "nomorph" }, onenter = function(inst) inst.components.locomotor:Stop() -- If the player has the "furry" tag, then he is currently using a furry bedroll, and not a -- straw bedroll. The tag is added in an overridden onuse. local furry = false if inst:HasTag("furry") then furry = inst:HasTag("furry") inst:RemoveTag("furry") end local canSleepAtDay = false if bedrollCanSleepAtDay and not furry then canSleepAtDay = true elseif furryBedrollCanSleepAtDay and furry then canSleepAtDay = true end inst.canSleepAtDay = canSleepAtDay local failreason = (_G.TheWorld.state.isday and (_G.TheWorld:HasTag("cave") and "ANNOUNCE_NODAYSLEEP_CAVE" or "ANNOUNCE_NODAYSLEEP") ) or (IsNearDanger(inst) and "ANNOUNCE_NODANGERSLEEP") or nil -- Custom code to override the ability to sleep/siesta at day/night if siestahutCanSiestaAtNight and (failreason == "ANNOUNCE_NONIGHTSIESTA" or failreason == "ANNOUNCE_NONIGHTSIESTA_CAVE") then failreason = nil elseif canSleepAtDay and (failreason == "ANNOUNCE_NODAYSLEEP_CAVE" or failreason == "ANNOUNCE_NODAYSLEEP") then failreason = nil end -- you can't sleep if you will die from it if inst.components.health and ((not furry and bedrollHealthChange < 0 and inst.components.health.currenthealth <= -bedrollHealthChange) or (furry and furryBedrollHealthChange < 0 and inst.components.health.currenthealth <= -furryBedrollHealthChange)) then failreason = "health" end -- you can still sleep if you're hungry, but only if you have the required hunger if not canSleepThroughStarvation and inst.components.hunger and ((not furry and bedrollHungerChange < 0 and inst.components.hunger.current < -bedrollHungerChange) or (furry and furryBedrollHungerChange < 0 and inst.components.hunger.current < -furryBedrollHungerChange)) then failreason = "ANNOUNCE_NOHUNGERSLEEP" end if failreason ~= nil then inst:PushEvent("performaction", { action = inst.bufferedaction }) inst:ClearBufferedAction() inst.sg:GoToState("idle") if inst.components.talker ~= nil then if failreason == "health" then inst.components.talker:Say("No way! I'll die in my sleep!") else inst.components.talker:Say(_G.GetString(inst, failreason)) end end return end inst.AnimState:PlayAnimation("action_uniqueitem_pre") inst.AnimState:PushAnimation("bedroll", false) SetSleeperSleepState(inst) end, timeline = { _G.TimeEvent(20 * _G.FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/use_bedroll") end), }, events = { _G.EventHandler("firedamage", function(inst) if inst.sg:HasStateTag("sleeping") then inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") end end), _G.EventHandler("animqueueover", function(inst) if inst.AnimState:AnimDone() then if _G.TheWorld.state.isday and not inst.canSleepAtDay or (inst.components.health ~= nil and inst.components.health.takingfiredamage) or (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then inst:PushEvent("performaction", { action = inst.bufferedaction }) inst:ClearBufferedAction() inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") elseif inst:GetBufferedAction() then inst:PerformBufferedAction() if inst.components.playercontroller ~= nil then inst.components.playercontroller:Enable(true) end inst.sg:AddStateTag("sleeping") inst.sg:AddStateTag("silentmorph") inst.sg:RemoveStateTag("nomorph") inst.sg:RemoveStateTag("busy") inst.AnimState:PlayAnimation("bedroll_sleep_loop", true) else inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") end end end), }, onexit = function(inst) inst.canSleepAtDay = false if inst.sleepingbag ~= nil then --Interrupted while we are "sleeping" inst.sleepingbag.components.sleepingbag:DoWakeUp(true) inst.sleepingbag = nil SetSleeperAwakeState(inst) elseif not inst.sg.statemem.iswaking then --Interrupted before we are "sleeping" SetSleeperAwakeState(inst) end end, }) return inst end if _G.TheNet and _G.TheNet:GetIsServer() then AddPlayerPostInit(ChangeBedrollAndTentStateDST) end Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/#findComment-1277225 Share on other sites More sharing options...
Arestless Posted October 27, 2019 Author Share Posted October 27, 2019 1 hour ago, Ultroman said: This would be the simplified version, which shows how to change just one state. All of this in modmain. Understand, though, that this overwrites the state, so if any other mod also does this, one or the other mod won't work. local function addState(SGname, state) print("addState") for k,v in pairs(_G.SGManager.instances) do if(k.sg.name == SGname) then k.sg.states[state.name] = state break end end end local function ChangeBedrollAndTentStateDST(inst) -- Override host bedroll-state addState("wilson", _G.State{ name = "bedroll", tags = { "bedroll", "busy", "nomorph" }, onenter = function(inst) inst.components.locomotor:Stop() -- If the player has the "furry" tag, then he is currently using a furry bedroll, and not a -- straw bedroll. The tag is added in an overridden onuse. local furry = false if inst:HasTag("furry") then furry = inst:HasTag("furry") inst:RemoveTag("furry") end local canSleepAtDay = false if bedrollCanSleepAtDay and not furry then canSleepAtDay = true elseif furryBedrollCanSleepAtDay and furry then canSleepAtDay = true end inst.canSleepAtDay = canSleepAtDay local failreason = (_G.TheWorld.state.isday and (_G.TheWorld:HasTag("cave") and "ANNOUNCE_NODAYSLEEP_CAVE" or "ANNOUNCE_NODAYSLEEP") ) or (IsNearDanger(inst) and "ANNOUNCE_NODANGERSLEEP") or nil -- Custom code to override the ability to sleep/siesta at day/night if siestahutCanSiestaAtNight and (failreason == "ANNOUNCE_NONIGHTSIESTA" or failreason == "ANNOUNCE_NONIGHTSIESTA_CAVE") then failreason = nil elseif canSleepAtDay and (failreason == "ANNOUNCE_NODAYSLEEP_CAVE" or failreason == "ANNOUNCE_NODAYSLEEP") then failreason = nil end -- you can't sleep if you will die from it if inst.components.health and ((not furry and bedrollHealthChange < 0 and inst.components.health.currenthealth <= -bedrollHealthChange) or (furry and furryBedrollHealthChange < 0 and inst.components.health.currenthealth <= -furryBedrollHealthChange)) then failreason = "health" end -- you can still sleep if you're hungry, but only if you have the required hunger if not canSleepThroughStarvation and inst.components.hunger and ((not furry and bedrollHungerChange < 0 and inst.components.hunger.current < -bedrollHungerChange) or (furry and furryBedrollHungerChange < 0 and inst.components.hunger.current < -furryBedrollHungerChange)) then failreason = "ANNOUNCE_NOHUNGERSLEEP" end if failreason ~= nil then inst:PushEvent("performaction", { action = inst.bufferedaction }) inst:ClearBufferedAction() inst.sg:GoToState("idle") if inst.components.talker ~= nil then if failreason == "health" then inst.components.talker:Say("No way! I'll die in my sleep!") else inst.components.talker:Say(_G.GetString(inst, failreason)) end end return end inst.AnimState:PlayAnimation("action_uniqueitem_pre") inst.AnimState:PushAnimation("bedroll", false) SetSleeperSleepState(inst) end, timeline = { _G.TimeEvent(20 * _G.FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/use_bedroll") end), }, events = { _G.EventHandler("firedamage", function(inst) if inst.sg:HasStateTag("sleeping") then inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") end end), _G.EventHandler("animqueueover", function(inst) if inst.AnimState:AnimDone() then if _G.TheWorld.state.isday and not inst.canSleepAtDay or (inst.components.health ~= nil and inst.components.health.takingfiredamage) or (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then inst:PushEvent("performaction", { action = inst.bufferedaction }) inst:ClearBufferedAction() inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") elseif inst:GetBufferedAction() then inst:PerformBufferedAction() if inst.components.playercontroller ~= nil then inst.components.playercontroller:Enable(true) end inst.sg:AddStateTag("sleeping") inst.sg:AddStateTag("silentmorph") inst.sg:RemoveStateTag("nomorph") inst.sg:RemoveStateTag("busy") inst.AnimState:PlayAnimation("bedroll_sleep_loop", true) else inst.sg.statemem.iswaking = true inst.sg:GoToState("wakeup") end end end), }, onexit = function(inst) inst.canSleepAtDay = false if inst.sleepingbag ~= nil then --Interrupted while we are "sleeping" inst.sleepingbag.components.sleepingbag:DoWakeUp(true) inst.sleepingbag = nil SetSleeperAwakeState(inst) elseif not inst.sg.statemem.iswaking then --Interrupted before we are "sleeping" SetSleeperAwakeState(inst) end end, }) return inst end if _G.TheNet and _G.TheNet:GetIsServer() then AddPlayerPostInit(ChangeBedrollAndTentStateDST) end I wouldn't still put this in modmain though to make only one specific character nocturnal, right? I'm sorry if that's a dumb question, very new. Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/#findComment-1277440 Share on other sites More sharing options...
Ultroman Posted October 28, 2019 Share Posted October 28, 2019 Yes, you would, because you just need to copy the original state, and add some check to make specifically your character prefab be able to sleep. I also believe that there are other wakeup functions for your character which will need to have their checks altered, but you'll figure out which and when they are fired once you've made the state work. Note, though, that my example code is for changing an entirely different state than you are trying to change. You'll have to study the state you are trying to change. Link to comment https://forums.kleientertainment.com/forums/topic/113015-how-to-make-a-character-nocturnal/#findComment-1278034 Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now