. . . Posted September 29, 2016 Share Posted September 29, 2016 (edited) Hello, can someone tell me how to make stategraphpostinit because I heard it's not good to edit SGwilson for your character because it causes incompatibilities with other mods that do that.. So, for example can someone make this into statehraphpostinit then I can see & learn then I convert all my custom state to stategrapghpostinit? Thanks so much !! State{ name = "adam_whistle", tags = { "whistling", "pausepredict", "nomorph", "busy" }, onenter = function(inst) inst.Physics:Stop() inst.components.locomotor:Stop() inst.AnimState:Hide("ARM_carry") inst.AnimState:Show("ARM_normal") inst.AnimState:PlayAnimation("horn") inst.AnimState:PushAnimation("horn") inst.components.inventory:ReturnActiveActionItem(inst.bufferedaction ~= nil and inst.bufferedaction.invobject or nil) if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end if inst.whistle_cooldown == nil then if TheWorld:HasTag("cave") then return end inst.whistle_cooldown = true local birdspawner = TheWorld.components.birdspawner birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX_FEATHERHAT) birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY_FEATHERHAT) inst:DoTaskInTime(90, function() inst.whistle_cooldown = nil end) -- Cooldown = 1.30.0. inst:DoTaskInTime(30, function(inst) local birdspawner = TheWorld.components.birdspawner birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY) birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX) end) end end, timeline = { TimeEvent(21*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/smallbird/chirp", "whistle") inst:PerformBufferedAction() end), TimeEvent(41*FRAMES, function(inst) inst.SoundEmitter:KillSound("whistle") end), TimeEvent(61*FRAMES, function(inst) inst.sg:GoToState("idle") end), }, events = { EventHandler("animqueueover", function(inst) if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, onexit = function(inst) inst.SoundEmitter:KillSound("whistle") if inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) then inst.AnimState:Show("ARM_carry") inst.AnimState:Hide("ARM_normal") end end, }, Edited October 1, 2016 by SuperDavid Link to comment Share on other sites More sharing options...
. . . Posted September 30, 2016 Author Share Posted September 30, 2016 (edited) Help Edited October 1, 2016 by SuperDavid Link to comment Share on other sites More sharing options...
. . . Posted October 1, 2016 Author Share Posted October 1, 2016 Sorry but i'm gonna bump this again since I really would love to know how to make stategraphpostinit, because the way my mod is now it crashes with lots of other character mods because I use a edited SGwilson & that's a big problem . I would appreciate any help so much ! Have a lovely day/night !!! Link to comment Share on other sites More sharing options...
DarkXero Posted October 1, 2016 Share Posted October 1, 2016 (edited) There are many functions. AddStategraphActionHandler(name, actionhandler) AddStategraphState(name, state) AddStategraphEvent(name, eventhandler) local postinit = function(stategraph) end AddStategraphPostInit(name, postinit) You could say that the stategraph post init allows you to do what the others do. For example: local new_state = State { name = "hello", tags = {}, } AddStategraphState(name, new_state) is equivalent to local new_state = State { name = "hello", tags = {}, } local postinit = function(stategraph) stategraph.states["hello"] = new_state end AddStategraphPostInit(name, postinit) You can see in stategraph.lua, in the class definition of StateGraph, that all these functions are pretty much called consecutively. StateGraph = Class( function(self, name, states, events, defaultstate, actionhandlers) assert(name and type(name) == "string", "You must specify a name for this stategraph") local info = debug.getinfo(3, "Sl") self.defline = string.format("%s:%d", info.short_src, info.currentline) self.name = name self.defaultstate = defaultstate --reindex the tables self.actionhandlers = {} if actionhandlers then for k,v in pairs(actionhandlers) do assert( v:is_a(ActionHandler),"Non-action handler added in actionhandler table!") self.actionhandlers[v.action] = v end end for k,modhandlers in pairs(ModManager:GetPostInitData("StategraphActionHandler", self.name)) do for i,v in ipairs(modhandlers) do assert( v:is_a(ActionHandler),"Non-action handler added in mod actionhandler table!") self.actionhandlers[v.action] = v end end self.events = {} for k,v in pairs(events) do assert( v:is_a(EventHandler),"Non-event added in events table!") self.events[v.name] = v end for k,modhandlers in pairs(ModManager:GetPostInitData("StategraphEvent", self.name)) do for i,v in ipairs(modhandlers) do assert( v:is_a(EventHandler),"Non-event added in mod events table!") self.events[v.name] = v end end self.states = {} for k,v in pairs(states) do assert( v:is_a(State),"Non-state added in state table!") self.states[v.name] = v end for k,modhandlers in pairs(ModManager:GetPostInitData("StategraphState", self.name)) do for i,v in ipairs(modhandlers) do assert( v:is_a(State),"Non-state added in mod state table!") self.states[v.name] = v end end -- apply mods local modfns = ModManager:GetPostInitFns("StategraphPostInit", self.name) for i,modfn in ipairs(modfns) do modfn(self) end end) Another thing is that "name" corresponds to the stategraph name (which you can see at the end of the stategraph file), and NOT to the stategraph filename. So, using the function that exists specially to add new states, it would look like this: local State = GLOBAL.State local EQUIPSLOTS = GLOBAL.EQUIPSLOTS local EventHandler = GLOBAL.EventHandler local TimeEvent = GLOBAL.TimeEvent local FRAMES = GLOBAL.FRAMES local TUNING = GLOBAL.TUNING local adam_whistle_state = State { name = "adam_whistle", tags = { "whistling", "pausepredict", "nomorph", "busy" }, onenter = function(inst) inst.Physics:Stop() inst.components.locomotor:Stop() inst.AnimState:Hide("ARM_carry") inst.AnimState:Show("ARM_normal") inst.AnimState:PlayAnimation("horn") inst.AnimState:PushAnimation("horn") inst.components.inventory:ReturnActiveActionItem(inst.bufferedaction ~= nil and inst.bufferedaction.invobject or nil) if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end local world = GLOBAL.TheWorld if inst.whistle_cooldown == nil then if world:HasTag("cave") then return end inst.whistle_cooldown = true local birdspawner = world.components.birdspawner birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX_FEATHERHAT) birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY_FEATHERHAT) inst:DoTaskInTime(90, function() inst.whistle_cooldown = nil end) -- Cooldown = 1.30.0. inst:DoTaskInTime(30, function(inst) local birdspawner = world.components.birdspawner birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY) birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX) end) end end, timeline = { TimeEvent(21 * FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/smallbird/chirp", "whistle") inst:PerformBufferedAction() end), TimeEvent(41 * FRAMES, function(inst) inst.SoundEmitter:KillSound("whistle") end), TimeEvent(61 * FRAMES, function(inst) inst.sg:GoToState("idle") end), }, events = { EventHandler("animqueueover", function(inst) if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, onexit = function(inst) inst.SoundEmitter:KillSound("whistle") if inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) then inst.AnimState:Show("ARM_carry") inst.AnimState:Hide("ARM_normal") end end, } AddStategraphState("wilson", adam_whistle_state) Edited October 1, 2016 by DarkXero Link to comment Share on other sites More sharing options...
. . . Posted October 1, 2016 Author Share Posted October 1, 2016 (edited) 2 hours ago, DarkXero said: local adam_whistle_state = State { @DarkXero I'm sorry to bother but game crashes saying "attempt to index global "State" a nil value" at this line of code, I added a GLOBAL. & it works but would there be a way to do like "local State = ???" then I don't need to add GLOBAL.? (I just did "local State = GLOBAL.State" & that worked, haha)... But I have a new problem @DarkXero if you can help me that would be great, so i'm trying to convert my custom states 1 by 1 & I tried to covert this state which works perfectly fine in SGwilson local adam_dodge_state = State{ name = "dodge", tags = { "busy", "pausepredict", "nomorph", "dodging" }, onenter = function(inst) inst.Physics:Stop() inst.AnimState:PlayAnimation("leap") if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end end, events = { EventHandler("animover", function(inst) if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, }, AddStategraphState("wilson", adam_dodge_state) but when I tried adding it into my modmain.lua the game crashes & says ":195: unexpected symbol near 'local'" line 195 being adam_dodge_state & that confuses me greatly because that didn't happen with the whistle state?! Edited October 1, 2016 by SuperDavid Link to comment Share on other sites More sharing options...
DarkXero Posted October 1, 2016 Share Posted October 1, 2016 I can't believe I forgot State. local State = GLOBAL.State That should do the trick. Link to comment Share on other sites More sharing options...
DarkXero Posted October 1, 2016 Share Posted October 1, 2016 36 minutes ago, SuperDavid said: but when I tried adding it into my modmain.lua the game crashes & says ":195: unexpected symbol near 'local'" line 195 being adam_dodge_state & that confuses me greatly?! Remove the comma at the end of -State { etc },- Link to comment Share on other sites More sharing options...
. . . Posted October 1, 2016 Author Share Posted October 1, 2016 (edited) @DarkXero This's so embarrassing but can you please show me exactly what's wrong? I keep staring hard & don't see any comma anywhere weird... I put all the stuff I did but the code that causes the crash is all the way at the bottom "local adam_dodge_state = State {" and I don't see any comma or I must be blind ... Thanks so much for helping me DarkXero !!!! local EQUIPSLOTS = GLOBAL.EQUIPSLOTS local EventHandler = GLOBAL.EventHandler local TimeEvent = GLOBAL.TimeEvent local FRAMES = GLOBAL.FRAMES local TUNING = GLOBAL.TUNING local State = GLOBAL.State local ShakeAllCameras = GLOBAL.ShakeAllCameras local CAMERASHAKE = GLOBAL.CAMERASHAKE local adam_whistle_state = State { name = "adam_whistle", tags = { "whistling", "pausepredict", "nomorph", "busy" }, onenter = function(inst) inst.Physics:Stop() inst.components.locomotor:Stop() inst.AnimState:Hide("ARM_carry") inst.AnimState:Show("ARM_normal") inst.AnimState:PlayAnimation("horn") inst.AnimState:PushAnimation("horn") inst.components.inventory:ReturnActiveActionItem(inst.bufferedaction ~= nil and inst.bufferedaction.invobject or nil) if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end local world = GLOBAL.TheWorld if inst.whistle_cooldown == nil then if world:HasTag("cave") then return end inst.whistle_cooldown = true local birdspawner = world.components.birdspawner birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX_FEATHERHAT) birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY_FEATHERHAT) inst:DoTaskInTime(90, function() inst.whistle_cooldown = nil end) -- Cooldown = 1.30.0. inst:DoTaskInTime(30, function(inst) local birdspawner = world.components.birdspawner birdspawner:SetSpawnTimes(TUNING.BIRD_SPAWN_DELAY) birdspawner:SetMaxBirds(TUNING.BIRD_SPAWN_MAX) end) end end, timeline = { TimeEvent(21 * FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/smallbird/chirp", "whistle") inst:PerformBufferedAction() end), TimeEvent(41 * FRAMES, function(inst) inst.SoundEmitter:KillSound("whistle") end), TimeEvent(61 * FRAMES, function(inst) inst.sg:GoToState("idle") end), }, events = { EventHandler("animqueueover", function(inst) if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, onexit = function(inst) inst.SoundEmitter:KillSound("whistle") if inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) then inst.AnimState:Show("ARM_carry") inst.AnimState:Hide("ARM_normal") end end, } local adam_roar_state = State { name = "adam_roar", tags = { "busy", "roaring", "pausepredict" }, onenter = function(inst, data) inst:ClearBufferedAction() inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("yawn") if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end end, timeline = { TimeEvent(18*FRAMES, function(inst) ShakeAllCameras(CAMERASHAKE.FULL, 1.38, 0.02, 10, inst, 60) inst.SoundEmitter:PlaySound("dontstarve/creatures/worm/death", "death") inst.SoundEmitter:PlaySound("dontstarve/creatures/werepig/howl", "howl") inst.SoundEmitter:PlaySound("dontstarve/creatures/werepig/grunt", "grunt") inst.SoundEmitter:PlaySound("dontstarve/creatures/worm/distant", "distant") inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/vargr/howl", "vargr") inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/bearger/grrrr", "grrrr") end), TimeEvent(68*FRAMES, function(inst) inst.sg:RemoveStateTag("roaring") inst.SoundEmitter:KillSound("howl") inst.SoundEmitter:KillSound("death") inst.SoundEmitter:KillSound("grunt") inst.SoundEmitter:KillSound("vargr") end), TimeEvent(128*FRAMES, function(inst) inst.SoundEmitter:KillSound("grrrr") inst.SoundEmitter:KillSound("distant") end), }, events = { EventHandler("animover", function(inst) if inst.AnimState:AnimDone() then inst.sg:RemoveStateTag("roaring") inst.SoundEmitter:KillSound("howl") inst.SoundEmitter:KillSound("death") inst.SoundEmitter:KillSound("grunt") inst.SoundEmitter:KillSound("vargr") inst.SoundEmitter:KillSound("grrrr") inst.SoundEmitter:KillSound("distant") inst.sg:GoToState("idle") end end), }, onexit = function(inst) inst.sg:RemoveStateTag("roaring") inst.SoundEmitter:KillSound("howl") inst.SoundEmitter:KillSound("death") inst.SoundEmitter:KillSound("grunt") inst.SoundEmitter:KillSound("vargr") inst.SoundEmitter:KillSound("grrrr") inst.SoundEmitter:KillSound("distant") end, }, local adam_dodge_state = State { name = "dodge", tags = { "busy", "pausepredict", "nomorph", "dodging" }, onenter = function(inst) inst.Physics:Stop() inst.AnimState:PlayAnimation("leap") if inst.components.playercontroller ~= nil then inst.components.playercontroller:RemotePausePrediction() end end, events = { EventHandler("animover", function(inst) if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, }, AddStategraphState("wilson", adam_roar_state) AddStategraphState("wilson", adam_dodge_state) AddStategraphState("wilson", adam_whistle_state) @DarkXero I have another stupid question, i'm sorry... I noticed that my character has multiple for example "local State = GLOBAL.State" since he has some actions that require that & I have multiple actions which do that but do those actions all need to have a "local ??? = GLOBAL.???" right next to them or can I just put all the locals local require = GLOBAL.require local STRINGS = GLOBAL.STRINGS local Ingredient = GLOBAL.Ingredient local RECIPETABS = GLOBAL.RECIPETABS local TECH = GLOBAL.TECH local resolvefilepath = GLOBAL.resolvefilepath local ACTIONS = GLOBAL.ACTIONS local ActionHandler = GLOBAL.ActionHandler local DEGREES = GLOBAL.DEGREES local COLLISION = GLOBAL.COLLISION local TheSim = GLOBAL.TheSim local Vector3 = GLOBAL.Vector3 local PlayFootstep = GLOBAL.PlayFootstep local SpawnPrefab = GLOBAL.SpawnPrefab local EQUIPSLOTS = GLOBAL.EQUIPSLOTS local EventHandler = GLOBAL.EventHandler local TimeEvent = GLOBAL.TimeEvent local FRAMES = GLOBAL.FRAMES local TUNING = GLOBAL.TUNING local State = GLOBAL.State local ShakeAllCameras = GLOBAL.ShakeAllCameras local CAMERASHAKE = GLOBAL.CAMERASHAKE all the way at the top of my 2,000 line code modmain.lua & those actions would still work, right? The actions for say require "local TUNING = GLOBAL.TUNING" & "local TUNING = GLOBAL.TUNING" is all the way at the top of modmain.lua & the action is 2,000 lines of code down from the "local TUNING = GLOBAL.TUNING" would that make the action preform slower? Would it be better to have multiple "local TUNING = GLOBAL.TUNING" near everything that needs it or would it be fine to just put 1 all the way at the top? Sorry for this stupid question . Edited October 1, 2016 by SuperDavid Link to comment Share on other sites More sharing options...
DarkXero Posted October 1, 2016 Share Posted October 1, 2016 41 minutes ago, SuperDavid said: and I don't see any comma or I must be blind Roar state and dodge state have commas at the end of the -State { }- 42 minutes ago, SuperDavid said: all the way at the top of my 2,000 line code modmain.lua & those actions would still work, right? The actions for say require "local TUNING = GLOBAL.TUNING" & "local TUNING = GLOBAL.TUNING" is all the way at the top of modmain.lua & the action is 2,000 lines of code down from the "local TUNING = GLOBAL.TUNING" would that make the action preform slower? Would it be better to have multiple "local TUNING = GLOBAL.TUNING" near everything that needs it or would it be fine to just put 1 all the way at the top? Having one or multiple doesn't practically make a difference. Just put the locals once at the beginning and then use them as you see fit. The point of having them as locals is so you don't write GLOBAL everywhere. Link to comment Share on other sites More sharing options...
. . . Posted October 8, 2016 Author Share Posted October 8, 2016 (edited) @DarkXero Thank you so, so, so much !!!!!!!!!!!!! Sorry for bringing this old post up but I need to ask a question! @DarkXero If I can ask you a question is that can stategraph post init be used to edit states in SGwilson that aren't custom? Say for example I want to edit "run" state & make it that characters with "inst.stealth == true" don't play footstep sounds like this would that be fine or would that be bad? State{ name = "run", tags = { "moving", "running", "canrotate", "autopredict" }, onenter = function(inst) inst.components.locomotor:RunForward() local anim = inst:HasTag("groggy") and "idle_walk" or "run_loop" if not inst.AnimState:IsCurrentAnimation(anim) then inst.AnimState:PlayAnimation(anim, true) end inst.sg:SetTimeout(inst.AnimState:GetCurrentAnimationLength()) inst.sg.statemem.riding = inst.components.rider ~= nil and inst.components.rider:IsRiding() end, onupdate = function(inst) inst.components.locomotor:RunForward() end, timeline = { if inst.stealth == true then return end --unmounted TimeEvent(7 * FRAMES, function(inst) if not inst.sg.statemem.riding then if inst.sg.mem.footsteps > 3 then PlayFootstep(inst, .6, true) else inst.sg.mem.footsteps = inst.sg.mem.footsteps + 1 PlayFootstep(inst, 1, true) end DoFoleySounds(inst) end end), TimeEvent(15 * FRAMES, function(inst) if not inst.sg.statemem.riding then if inst.sg.mem.footsteps > 3 then PlayFootstep(inst, .6, true) else inst.sg.mem.footsteps = inst.sg.mem.footsteps + 1 PlayFootstep(inst, 1, true) end DoFoleySounds(inst) end end), --mounted TimeEvent(0 * FRAMES, function(inst) if inst.sg.statemem.riding then DoMountedFoleySounds(inst) end end), TimeEvent(5 * FRAMES, function(inst) if inst.sg.statemem.riding then if inst.sg.mem.footsteps > 3 then PlayFootstep(inst, .6, true) else inst.sg.mem.footsteps = inst.sg.mem.footsteps + 1 PlayFootstep(inst, 1, true) end end end), }, ontimeout = function(inst) inst.sg:GoToState("run") end, }, Edited October 9, 2016 by SuperDavid Link to comment Share on other sites More sharing options...
DarkXero Posted October 9, 2016 Share Posted October 9, 2016 On 8/10/2016 at 5:57 PM, SuperDavid said: would that be fine or would that be bad? This is bad for many reasons: 1) Making your own state and passing it to the stategraph means that if somebody else does it, you lose your state. 2) You slapped code right in the middle of a table. timeline is a table with TimeEvent values. This is a crash. 3) "inst.stealth == true" is redundant, and will also be only available on the host/server. People with movement prediction enabled will still hear the sounds because you didn't override it on the client stategraph. So a correct solution overriding the wilson stategraph would be 50% useful. So, what is to be done here? To override the function responsible for footstep noises, which luckily for us is a global function defined in worldtiledefs.lua. -- modmain.lua local _PlayFootstep = GLOBAL.PlayFootstep GLOBAL.PlayFootstep = function(inst, ...) -- networked variable that cancels footstep noise if inst.stealthsteps and inst.stealthsteps:value() then return end return _PlayFootstep(inst, ...) end -- character.lua -- in common_postinit function inst.stealthsteps = net_bool(inst.GUID, "player.stealthsteps") inst.stealthsteps:set(false) First, put this code in the respective places. Second, whenever you do inst.stealth = true you also do inst.stealthsteps:set(true) and when you do inst.stealth = false you also do inst.stealthsteps:set(false) to activate and deactivate the variable responsible for regulating the noises. Link to comment 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