Jump to content

Recommended Posts

This is a big task I understand but I am trying to make bots or NPCs for the game. First I am trying to use Wilson's prefab as a start. I want to make the character wander around on it's own as step one. I am semi-new to coding don't starve together stuff. I can give more information but I just started this project there isn't much to say.

I slightly edited Wilson's files renamed as a new prefab and gave it a custom brain with only the action to wander around. Any helping tips or what I should worry about? Maybe tips or tricks on making a brain or stategraph?

So by NPCs, do you mean like pigmen but with the ability to gather resources and live on their own?

Brains can be tricky to comprehend at first, but there is a method to all those nodes and behaviors. The tree of priority nodes starts with the behavior at the top and works its way down until it's told to stop. That's why "panic" is always at the very top of every brain, so spiders won't stop to take a nap while they're on fire.

There used to be a neat site that talked about Don't Starve brains and behavior coding, but last I checked a year or two ago, it was kinda gone.

But I'd say definitely look into combining functions of existing mobs. Pigmen brains are a good place to start because they can function very much like a player on their own, when certain conditions are met. They can even work and gather materials. Maybe merge this with the penguin's ability to choose and maintain a "home" of sorts. 

 

and teach them some manners

so they don't wander into people's bases and raid their farms and livestock (unless that's what you want them to do)

Can you explain to me a bit how stategraphs work? The api seems really weird.using the stategraph of a lure plant I see

Quote

ActionHandler(ACTIONS.HARVEST, "eat_enter")

I don't really know what action handler parameters are. But of course I should be looking at something that can actually move.

Quote

ActionHandler(ACTIONS.CHOP, "chop"),

It seems pretty simple to me but what exactly are these parameters made from? The ACTIONS.CHOP I don't understand and I am pretty sure "chop" is just a quick name of the instance  which is used further in the stategraph.

Also came across this really weird error that I don't really know what caused it

Quote

[string "scripts/entityscript.lua"]:889: attempt to index field 'sg' (a boolean value)
LUA ERROR stack traceback:

the attempt was not part of my code but the error was caused by

Quote

inst:SetStateGraph("SGwilsonbot")

I can provide as much information you need but I really have no idea how to fix this error.

ok that problem might be resolved. I think it is because my spawn action goes into an idle animation I haven't set up.

 

NOPE. Still have the same problem

 

I can tell you all about stategraphs. A whole lot of my modding is done with stategraphs. But action handlers are literally the only part of stategraphs I don't know how to use, because I never use them.

I think action handlers are more for stuff with controls, for players, since there are multiple ways to initiate the same thing (pressing space, clicking, controller button) it makes it easier to lead to the same thing.

but I've made creatures and other AI and none of them use action handlers so you "probably" don't need to worry about those.  inst.sg:GoToState("asdf") should do the job just fine

 

oh, but none of those stategraphs I made were for playing the actual game... Eh, it's probably not that different

What is there not to understand?

ActionHandler(ACTIONS.CHOP, "chop")

when the entity starts the action ACTIONS.CHOP, it goes to the state "chop"

First parameter is action, second parameter is state to go to when action is met. Action gets handled

Now I am more or less having trouble with finding the names of certain animations. I made wilson use his idle animation after spawning, and the idle animation I just want him to stand there but for some reason it still stays invisible. I may be reading other creature's codes wrong and trying to implement an idle animation that which wilson might have the name for something else like "funnyidle" or something ridiculous

Quote

require("stategraphs/commonstates")

 local actionhandlers = {}

 local events = {}

local states=
{
    State{
        name = "spawn",
        tags = {"busy"},

        onenter = function(inst, playanim)
            inst.Physics:Stop()           
            inst.AnimState:PlayAnimation("spawn")
            inst.AnimState:PushAnimation("idle", true)   
            inst.SoundEmitter:PlaySound("dontstarve/creatures/wilson/1manband_accord_1")        
        end,
        
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },

    },
    
    State{
        name = "idle",
        tags = {"idle", true},
        onenter = function(inst)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("idle", true)
        end,
        
        
    },
}
return StateGraph("wilsonbot", states, events, "idle", actionhandlers)

yes it's bad I know but I simply need to know how to literally just idle XD

stategraphs give me the absolute most trouble. I want to learn how to use this but not many tutorials exists on stategraphs. This mod is not dead but I have been testing quite a bit. Do you know any useful resources to understand stategraphs more?

18 hours ago, Spidergamer1248 said:

stategraphs give me the absolute most trouble. I want to learn how to use this but not many tutorials exists on stategraphs. This mod is not dead but I have been testing quite a bit. Do you know any useful resources to understand stategraphs more?

I know there was an existing sample mod for the original Don't Starve about creating a custom creature that included an example of a very basic stategraph with details on what all the small parts do. If i can remember where it was;

Here we go!  http://steamcommunity.com/sharedfiles/filedetails/?id=177285368

This stategraph is VERY basic, but it gets the point across. 

Whats giving you the most trouble with the stategraphs? the contents of the individual states? The layout of how everything is set up? Figuring out how to actually use the states in the stategraph? All of the above? I can give you some more explanation if you're confused about certain features or functions that don't involve actions since I use stategraphs a ton. but not actions.

18 hours ago, Spidergamer1248 said:

Yes. States are giving me the most trouble and without a knowledge of where to put certain parameters without crashing is a problem. Should I put an even in Idle to go back to the state idle to repeat?

 

I've been meaning to make a guide about stategraph contents so I might as well give it a go.

 

There are a handful of components that make up each individual state: name, tags, onenter, onexit, onupdate, ontimeout, timeline, and events.

Almost all of these are completely optional, and can just be left out of the state if they aren't needed. (except name)  You might even have a state as small as this:

State
    {
        name = "example_channeling",
        tags = {},

        onenter = function(inst)
            inst.AnimState:PlayAnimation("channel_pst")
        end,
    },

But you wont find many states without onenter or timeline.

 

Let's start with the main meat of states, the timeline. Timelines are composed of TimeEvents, which are kind of like DoTaskInTime() fns, but they cancel themselves if the player leaves the state to enter a different one.

You assign the TimeEvent a number to designate what frame it should run on. And when the player enters that state, at ? frames into the state, all code inside that TimeEvent will run.

--In this timeline example, the player plays the "give" animation on frame 5, and on frame 13 it plays a sound and sets the nearest player on fire, sure, why not. and then the player is trapped in this state forever or until someone attacks them because we haven't properly set it to go back to idle and it has the "busy" tag

name = "example",
tags = { "busy" },

timeline =
        {
            TimeEvent(5 * FRAMES, function(inst) --ON THE 5TH FRAME OF THIS STATE
                inst.AnimState:PlayAnimation("give") --PLAY THIS ANIMATION
            end),
  	TimeEvent(13 * FRAMES, function(inst) --ON THE 13TH FRAME
                inst.SoundEmitter:PlaySound("dontstarve/wilson/use_gemstaff") --DO THIS
      		--AND OTHER STUFF TOO, YOU CAN RUN WHATEVER YOU WANT IN HERE.
      		TheSim:FindFirstEntityWithTag("player").components.burnable:Ignite() --SET THE NEAREST PLAYER ON FIRE
            end),
        },

A player can only be in one state at a time, but they also must always be in a state. There must always be some way of returning the player to their idle state when the state is done, or else they would be stuck in that state forever! This is normally done by using either sg:GoToState("idle") or sg:RemoveStateTag("busy") (I'll get into statetags later though) and those can be done with just a regular old timeevent, or an event listener for animover (when the player's animation finishes. and I'll also get into event listeners later)

 

ONENTER; you can think of this as a TimeEvent that happens on frame 0. It just runs whatever is inside of it the moment the player enters this state. easy as that. This is the best place to start your players animations, since why would you have a state that doesn't play a custom animation? Our example state would have beniffited from having an onenter fn to play our animation instead of using a TimeEvent on frame 5, because those first 4 frames will be just whatever animation was playing out before that.

ONEXIT: Whatever is in your "onexit" will run as the player exits that state to enter a new one. More specifically, it runs right before the new state runs it's "onenter" fn. This is often used to turn off state specific parameters, like if the onenter fn turned off the players controls, you would certainly want to turn those back on as the player exits the state. So why put it in an onexit fn as opposed to an "animover" event listener or TimeEvent? Well, if the player gets attacked or struck by lightning or something mid-state, they might be sent to the "hit" state before their previous TimeEvent or animover eventlistener runs, and you'd be outta luck! With onexit, you don't have to worry about the state being interrupted and skipping important code.

ONUPDATE: Anything inside onpudate will run  every  single  frame  as long as the player remains in that state. It's like copy/pasting a TimeEvent for every frame. It's not used often, and I can't think of any of it's common uses off the top of my head, other than that "run" uses it to locomote the player forward every frame. But you can do some logic checking or something with it. maybe the fishing state uses onupdate to check if it's caught a fish, which it then runs sg:GoToState("catch") or something like that. I dunno, I didn't check.

ONTIMEOUT: This is a TimeEvent with a variable timer. You cant set which frame it will run directly, you have to use "inst.sg:SetTimeout(? * FRAMES)"  --and replace "?" with a number, of course. I don't use it that often, so I'm not as familiar with it, but it seems most states set the timeout number in onenter, but you may be able to change that number later. the "?" doesn't have to be a straight up number, you could replace it with a function that calls your players health, maybe, and have ontimeout run sooner if your player's health is lower, or something like that.

 

EVENTS:  This is where things can get a bit tricky, simply because there are so many different kinds of events. The Events component is full of EventHandlers, which are identical to using "inst:ListenForEvent("aneventname", function() (stuff happens here) end)"   except (stuff happens here) only happens if the player is in that specific state. (sidenote, this portion of the guide is about the EventHandlers inside of individual states. not that huge long list of generic EventHandlers near the top of each stategraph file. I'll get to those later)

Events are pushed to an entity with  inst:PushEvent("aneventname") from anywhere in the code. It doesn't normally happen from within the stategraph file.

You'll notice the most common one is  EventHandler("animover", function(inst) ...) which is an event that is pushed when, you guessed it, the player's current animation has ended. Which is often just to send the player back to idle at the end of their state, because otherwise, their animation will freeze when it's over, and it looks weird. You can actually use the animover event listener outside of stategraphs too probably. Just like you can use non-stategraph specific events in a state's EventListeners. 

Does your character die during this state? if they do, play fireworks on their death!

events =
        {
            EventHandler("killed", function(inst)
                inst.fx = SpawnPrefab("shock_fx")
		--(or something like that, I didn't look up the actual code)
            end),
        },

(well, this might not even work, since the player might enter the "death" state before the killed event is pushed, but I hope this gets the idea)

EventHandlers are called by pushing events from somewhere else in the code. And there are LOTS of them. I have no idea where "killed" comes from, all I know is that SOMEWHERE in the code;  ThePlayer:PushEvent("killed")  is run when they die. I could probably open up the game files and do a ctrl-f and search for that to figure out where it gets run from, if I felt like it. (also, a state's event handlers only listen for events pushed on their owners. you can't use an EventHandler to listen for another players death. (or, not easily, at least))

There are plenty of existing events that the game runs, but theres nothing stopping you from making your own custom events to push too! Lets say you made a custom character that has a special ability that, every time you press Q, they breath fire. you could set up a keyhandler that every time it is pressed, it does  ThePlayer:PushEvent("breathfire")  or something. (ThePlayer wouldn't be good to use here but it's just an example) Maybe you wanted to do something goofy, so you edited the existing "bedroll" state and added this event handler to it:

EventHandler("breathfire", function(inst)
 	inst.components.burnable:Ignite()
end),

This would make it so that if we press Q while we are in the bedroll state, we set ourselves on fire.

Although, bedroll also already has an eventhandler for burning...

EventHandler("firedamage", function(inst)
                if inst.sg:HasStateTag("sleeping") then
                    inst.sg.statemem.iswaking = true
                    inst.sg:GoToState("wakeup")
                end
end),

Which would put us into the "wakeup" state if it detects that we are on fire during the "sleeping" portion of the state.

I can hear you thinking; "So what is this 'sleeping' tag? and iswaking statemem?"

statemem is kinda weird. But in stategraph states, its hard to declare local variables that you can access between different TimeEvents and onenter fns and etc. and by "its hard" I mean "you cant." If you set "local myvariable = 12" in your onenter and then try to do "print("just an example", myvariable)" in a TimeEvent for frame 12, it will crash, because it can't access myvariable. 

Instead, you do "inst.statemem.myvariable = 12" in onenter, and THEN you can do "print("just an example", inst.statemem.myvariable)" anywhere else.

It's basically just a way of setting variables that can be accessed between the different components of a state, like TimeEvents and onenter etc. but ONLY for that state. Once the player leaves that state, whatever was stored in statemem is wiped out.

 

"So what is this 'sleeping' tag? And that list of tags beneath each state name?"

And this is a good transition into my next topic, which I will continue in another reply because this one is getting real long.

  • Thanks 1

TAGS:  (or, statetags)

Most noticeable as that list of "tags" underneath the name of the state. But don't mistake those as "tags." Theyre actually STATEtags.  inst:HasTag:("nodangle") will return false for the state below.  inst.sg:HasStateTag("nodangle") is what you're really looking for, that will return true if you're in the "changeoutsidewardrobe" state

State{
        name = "changeoutsidewardrobe",
        tags = { "busy", "pausepredict", "nomorph", "nodangle" },

statetags are much like normals tags, except that (just like everything else in stategraphs) a state's statetags only exist when the player is in that specific state. In our example state from earlier in the guide, we only gave it one tag; "busy." Probably one of the most common statetags, this is the statetag that tells the game if we're allowed to do anything or not. When we eat a plate of meatballs and we're in the eat state, we can't move or interact with anything until we're done stuffing our face. That means the "eat" state has a "busy" tag. So if we take a look at the first three lines of the state...

State{
        name = "eat",
        tags = { "busy", "nodangle" }, --IT SURE DOES
		--(dont ask me what "nodangle" is for I have no idea)

You'll notice that a lot of states use  inst.sg:RemoveStateTag("busy")  when they are finished instead of just using  inst.sg:GoToState("idle") 

It just looks a little prettier. A lot of states have animations that slowly transition to the idle animation, but don't want to force the player to sit through that whole animation, so let them cancel the state early by simply moving in any direction. That's why removing the "busy" tag is often used in a TimeEvent, and GoToState("idle") is used in an EventHandler("animover"). Pairing the two together gives you a state with the option to let the player cancel the animation early if they're impatient, but give the animation a smooth transition into "idle" if they have nothing else to do.

"wait, you can just take statetags off that "tags" list at the top at any time?" Yep! You can also ADD statetags too!  inst.sg:AddStateTag("busy")  And it can be used anywhere at any time. In TimeEvents, EventHandlers, inside or outside of stategraphs, on other players stategraphs. Heck, that tags list is just a shortcut. You could basically accomplish the same thing by adding the statetags in an onenter fn.

State{
        name = "eat",
        tags = {},

	onenter = function(inst)
		inst.sg:AddStateTag("busy")
		inst.sg:AddStateTag("nodangle")
    	...

Same thing! Probably.

 

It may seem a little complicated seeing all the different statetags, but statetags themselves aren't really very complex. Not all of them "do" things like busy does. In fact, all you can really can do with statetags is  inst.sg:AddStateTag, RemoveStateTag, and HasStateTag. That's it. The only reason "busy" does what it does is because locomotor and playercontroller check for inst.sg:HasStateTag("busy") and just turn it off if it returns as true.

Just like the "notalking" tag is used by talker.lua to decide if the player should run their yap or not by checking for inst.sg:HasStateTag("notalking"). Much like events, we can also make our own custom statetags and call them whatever we want, and use them wherever we want!

Some statetags aren't even used outside of their own state. You might decide to add the statetag "sleeping" at TimeEvent 15 since the player's animation doesn't show them asleep until frame 15, and then use an EventHandler to listen for the "firedamage" event, and in that EventHandler, check  if inst.sg:HasStateTag("sleeping")  and make them wait through a longer animation if they were already asleep when they got set on fire.

Heres a simplified of what that state might look like if we did it like that. The real bedroll state is much bigger (and doesn't work the same way) but I'm cutting out most of the confusing logic that doesn't relate to stategraph structure. I'm putting it in a dropdown because it's a big boy. 

Spoiler

 


State{
        name = "bedroll",
        tags = {"busy"},

        onenter = function(inst)
            inst.AnimState:PlayAnimation("action_uniqueitem_pre")
            inst.AnimState:PushAnimation("bedroll", false)

            SetSleeperSleepState(inst) --(PROBABLY SOMETHING TO DO WITH ACTUAL SLEEPING MECHANICS //SHRUG)
        end,

        timeline =
        {
            TimeEvent(15 * FRAMES, function(inst) --AT THIS POINT IN THE ANIMATION, THEY ARE IN THE SLEEPING BAG
                inst.sg:AddStateTag("sleeping")
            end),
        },

        events =
        {
            EventHandler("firedamage", function(inst)
                if inst.sg:HasStateTag("sleeping") then --IF THEYVE GOTTEN TO THE POINT WHERE THEY ARE IN THE SLEEPING BAG, THEN-
                    inst.sg:GoToState("wakeup") --FORCE THEM INTO ANOTHER STATE WITH A WAKEUP ANIMATION
		else 		--OTHERWISE, SINCE THEY MUST NOT HAVE GOTTEN INTO THE SLEEPING BAG YET-
			inst.sg:RemoveStateTag("busy") --LET THEM TAKE ACTION IMMEDIATELY
            	end
            end),
        },

        onexit = function(inst)
            SetSleeperAwakeState(inst) --(WE WANT THIS ON AN ONEXIT SO THAT THE GAME KNOWS WE "AWOKE" EVEN IF WE WERE INTERUPTED)
        end,
    },

 

And there you have it! The "sleeping" state tag in this case is mostly for the state to decide if the player should go to the "wakeup" state and go through another animation with the busy tag and such, or if they should be able to just press any direction and start running. But there are actually other eventhandlers OUTSIDE of the state that listen for the "sleeping" statetag, which I will start getting into.

 

I hope these are starting to make a little sense at this point! The custom version of the "bedroll" state in the dropdown above should have hopefully been easy enough to understand.

So far, this covers most of the components of an individual state. All that other clutter you see inside of TimeEvents and EventListeners is just normal game code that does non-stategraph things in various other components and other parts of the game that you'll need to study up on for them to make any sense. Of course, if it doesn't relate to anything you're working on, it doesn't really matter! Taking a look at the real "bedroll" state, I had absolutely no idea what most of it meant, but I'm not doing anything related to sleeping or setting things on fire, so who cares!

But now that we've covered the contents of a state, lets talk about how we enter states...

Edited by pickleplayer

By now you might have noticed that EventHandlers can be found in both the "events" table of states that include them, and also in a huge list of "events" found near the top of the player's stategraph. 

Unlike the individual state's list of events, the list of eventhandlers at the top of the stategraph are ALWAYS active, no matter what state the player is on. Always listening... 

THIS is how you enter states. The game Pushes events to the player from anywhere within the code. The eventlisteners hear that event being called, and run whatever code is inside them, which is mostly comparing tags and statetags to decide what state to send the player to, or whether they should send them to any state at all.

Well, I guess actionhandlers can also be invovled in sending players to states. But we don't talk about actionhandlers in my household because I don't know how to use them I've never needed to use them, and I've gotten by just fine by using only eventhandlers. They actually look real simple, I've just never bothered to look into them. I'm pretty sure the single player version of stategraphs don't even have action handlers. Don't quote me on that. Most of my modding experience is on the single player version of the game, and my larger scale DST mod projects aren't exactly... "typical" kinds of mods.

 

To start, lets look at a very simply example. In that long list of generic eventhandlers at the top of stategraph, here's an eventhandler for fishingcancel.

EventHandler("fishingcancel",
        function(inst)
            if inst.sg:HasStateTag("fishing") then
                inst.sg:GoToState("fishing_pst")
            end
	end),

So somewhere in the game's code,  inst:PushEvent("fishingcancel")  happens, in at least one location. ("inst" might be replaced with whatever the code uses to reference the stategraph's owner, depending on the circumstance) 

If we decide we want to know where and how this event is called, we can open up the game files and do a ctrl-f to search for  PushEvent("fishingcancel  and find that it's in the component fishingrod.lua on line 135 in the function StopFishing(),  "self.inst:PushEvent("fishingcancel").

So what calls StopFishing()? ctrl-f again, there we go, it's in actions.lua on 574, act.invobject.components.fishingrod:StopFishing(), in the function ACTIONS.REEL.fn-  oh... it's an action handler... You know what let's keep going. it's a learning experience for us both now. When you hover your mouse over the pond and it says "REEL" and you click the pond. Boom, action handler sent. Maybe. We'll pretend that's true. The chain reaction starts now. The actionhandler runs StopFishing(), which runs  PushEvent("fishingcancel"), which is heard by the EventHandler("fishingcancel"), which then asks "does the player have the statetag "fishing"?" and if the player is in a state that has the "fishing" statetag, it runs  inst.sg:GoToState("fishing_pst")   which puts the player in the "fishing_pst" state. And we're done.

Okay that example was a little confusing, I should really work on that one later.

But the short version is: Use PushEvent to activate an EventHandler to put the player into a state.

And the even shorter version is: PushEvent  -  EventHandler  -  State

 

I'm not sure if that got the point across very well. It's a bit hard to pick up, because there are a lot of different ways to push events, whether it be keypresses, action handlers, stat changes, another event listener, etc. 

I also have yet to get into the data fields that can be sent into eventlisteners, but that gets a little more complicated, and it's better to understand the basics before getting into that.

 

If you want, you can pick a state from a stategraph and I can walk you through the process of how it gets to that state in more detail.

Ok I have been working on this for a while. Stopped the crashing and figure out exactly I need to do. How do I push idle on as soon as it is created?

Sorry it has been a while. Been dealing with stuff irl but I am back.

Edited by Spidergamer1248

I could be wrong, but I believe its in the line at the very bottom of all stategraphs as part of the return statement

return StateGraph("wilson_client", states, events, "idle", actionhandlers)

this one is set to "idle" as well

wow I think I have spent over a week working on useless things that won't even work unless I do this right. Ok can you walk me through prefabs, because I think I have everything I need but it seems like that is the problem.

I think I messed up around,
 

Quote

    inst.AnimState:SetBank("wilson")
    inst.AnimState:SetBuild("build")
    inst.AnimState:PlayAnimation("idle")

, but I am not sure

That seems about right to me. the "wilson" bank is the bank that all player characters use. As long as "build" is the actual name of the build of your character, this should be correct. Where is that build name coming from? is there a "build.zip" file in your mod's "anim" folder?

I'm assuming the problem here is that they aren't showing up? Just invisible? If they're showing up and just not doing the correct actions, then it might not be related to the animation files (though some states do rely on the "animover" event, which means that if the animations don't play, they'd never end, and the state would never be over)

Make sure the animation files are being imported, like "Asset( "ANIM", "anim/yourbuildname.zip" )," and all that jazz

and that your character has the right stategraph, if it's not already set, with  inst:SetStateGraph("yourstategraphname")

What problem are you having right now? Is this being created as some sort of mod character with extra code added on? Or adding code onto existing components without adding any new characters?

Edited by pickleplayer

Yeah it is invisible. It has health and everything. I can poke it to death but animations just don't work. It Is a mod using the base wilson's animation added in during the beginning of  the prefab code.

Quote

require "brains/botbrain"
local brain = require "brains/botbrain"
require "stategraphs/SGwilsonbot"

local assets =
{
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
    Asset("ANIM", "anim/beard.zip"),
    Asset("ANIM", "anim/wilson.zip"),
    Asset("SOUND", "sound/wilson.fsb"),
}

local prefabs =
{
    "beardhair",
}

local start_inv =
{
    default =
    {
    },

    lavaarena = TUNING.LAVAARENA_STARTING_ITEMS.WILSON,
}

prefabs = FlattenTree({ prefabs, start_inv }, true)

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddMiniMapEntity()
    inst.entity:AddNetwork()

    
    MakeCharacterPhysics(inst, 30, .5)
    
    inst.AnimState:SetBank("wilson")
    inst.AnimState:SetBuild("build")
    inst.AnimState:PlayAnimation("idle")
    
    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end
    
    --Health Component
    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(TUNING.WILSON_HEALTH)

    --Combat Component
    inst:AddComponent("combat")
    inst.components.combat:SetDefaultDamage(TUNING.WILSON_DAMAGE)
    inst.components.combat:SetAttackPeriod(TUNING.WILSON_ATTACK_PERIOD)
    -- inst.components.combat:SetRetargetFunction(1, NormalRetarget)

    --Movement Component
    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = TUNING.WILSON_WALK_SPEED
    inst.components.locomotor.runspeed = TUNING.WILSON_RUN_SPEED
    
    
    inst:SetStateGraph("SGwilsonbot")
    inst:SetBrain(brain)

    return inst
end

local function common_postinit(inst)
    --bearded (from beard component) added to pristine state for optimization
    inst:AddTag("bearded")
end

local function OnResetBeard(inst)
    inst.AnimState:ClearOverrideSymbol("beard")
end

--tune the beard economy...
local BEARD_DAYS = { 4, 8, 16 }
local BEARD_BITS = { 1, 3,  9 }

local function OnGrowShortBeard(inst)
    inst.AnimState:OverrideSymbol("beard", "beard", "beard_short")
    inst.components.beard.bits = BEARD_BITS[1]
end

local function OnGrowMediumBeard(inst)
    inst.AnimState:OverrideSymbol("beard", "beard", "beard_medium")
    inst.components.beard.bits = BEARD_BITS[2]
end

local function OnGrowLongBeard(inst)
    inst.AnimState:OverrideSymbol("beard", "beard", "beard_long")
    inst.components.beard.bits = BEARD_BITS[3]
end

local function master_postinit(inst)
    inst.starting_inventory = start_inv[TheNet:GetServerGameMode()] or start_inv.default

    inst:AddComponent("beard")
    inst.components.beard.onreset = OnResetBeard
    inst.components.beard.prize = "beardhair"
    inst.components.beard:AddCallback(BEARD_DAYS[1], OnGrowShortBeard)
    inst.components.beard:AddCallback(BEARD_DAYS[2], OnGrowMediumBeard)
    inst.components.beard:AddCallback(BEARD_DAYS[3], OnGrowLongBeard)

    if TheNet:GetServerGameMode() == "lavaarena" then
        event_server_data("lavaarena", "prefabs/wilson").master_postinit(inst)
    end
end

-- return MakePlayerCharacter("wilson", prefabs, assets, common_postinit, master_postinit)
return Prefab("wilsonbot", fn, assets, prefabs)

 

If you want to read through this

My main question still remains, does "build.zip" exist in your mods "anim" folder? (and does it have an anim folder at all?)

And is it being imported? It could have been imported in your modmain, but if not, you can also do it in here in that "local assets" list at the top. just throw in  Asset("ANIM", "anim/build.zip"),   underneath those other 4 assets. That might do the trick.

As a test, you can try and replace your  SetBuild("build")   with  SetBuild("wilson")  To see if it will at least show up with Wilson's skin. and if its STILL invisible, then the problem is probably coming from somewhere else

It's also probably good that you replaced MakePlayerCharacter with just a regular prefab, since player characters have all sorts of extra stuff thrown onto them.

oh, no you shouldn't need to mess around with any of that.

Oh, I probably should have asked this first, is this a custom character, or are you just using wilson? If there's no custom character models or animations or anything, and we're just using Wilson, then we're probably going in the wrong direction entirely.

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
×
  • Create New...