Jump to content

Quick code review for changing the hunger drain speed based on hunger value


Recommended Posts

Hello DST community. I was hoping for some help with this problem I've encountered. I'm new to character modding but I've come up with what I think is some code that is close to working. I've looked at other character's prefabs and referenced some other mods to try to get this working. What I am currently trying to do is change my character's hunger drain rate depending on the threshold of their hunger value.

Spoiler

local function onhungerchange(inst, data)

        if inst.components.hunger.current > 50 then

           inst.components.hunger.hungerrate = 50 * TUNING.WILSON_HUNGER_RATE

           elseif inst.components.hunger.current < 10 then

           inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE

           inst:ListenForEvent("hungerdelta", onhungerchange)

        end

end

The numbers are just for testing purposes (They're not actually going to drain their hunger at 50x the speed). But from this code, what I expect to happen is the game to check if my hunger is above 50, then set the hunger drain rate to 50x. And if the hunger value drops below 10, the hunger drain should return to normal. It doesn't do anything in game though but it also does not crash so I'm not sure where I went wrong. I would much appreciate if any kind user on here would give me some advice. Thank you.
 

Link to comment
Share on other sites

Its not doing anything because unless this function is being called by something else first, the ListenForEvent is never actually started until the function runs. You would want the ListenForEvent in your character's master_postinit instead. Also, less important, you don't need to check current hunger with inst.components.hunger in this case, data.new has the new hunger value stored from the hungerdelta event and you can use that for simplicity's sake.

  • Like 1
Link to comment
Share on other sites

3 hours ago, Merkyrrie said:

Its not doing anything because unless this function is being called by something else first, the ListenForEvent is never actually started until the function runs. You would want the ListenForEvent in your character's master_postinit instead. Also, less important, you don't need to check current hunger with inst.components.hunger in this case, data.new has the new hunger value stored from the hungerdelta event and you can use that for simplicity's sake.

Hello Merkyrrie. I appreciate the advice and have taken some advice from your other reply in a thread pertaining to health regen based on temperature/hunger. I have some new code to share and a new issue to share.

This is the function line I have created in the master_postinit
 

Spoiler
inst:ListenForEvent("hungerdelta", hungerspeed)

Following your advice from this thread and the other thread, this is the code that I have put outside of the common_postinit and the master_postinit

Spoiler

--Function for dynamically changing hunger rate

local function hungerspeed(inst, data)

    local newpercent = math.floor(data.new)

    local oldpercent = math.floor(data.last)

    if newpercent == oldpercent then

        return

    end

 

    if newpercent > 75 then

        inst.components.hunger.hungerrate = 50 * TUNING.WILSON_HUNGER_RATE

    elseif inst.components.hunger.current <= 75 then

        inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE

     end

 

end


 

So now this code definitely appears to be doing something, however there is no crash report I can find to diagnose the issue.

The order of events is: I launch world with only my character mod enabled, the server launches and generates a world. I am taken to the character select screen and am able to select my character and hit GO to spawn in. However, as soon as the character spawns in, the server hangs for several seconds and I am unable to make any input until I am notified that I have been disconnected from the server.

I think I may be missing something that is causing this function to call too many times or call data that does not exist. I would much appreciate some advice. Thank you.

Edited by Bluehero
Link to comment
Share on other sites

The server sometimes logs the error further up in the server log, not sure if that'd be the case here though.

Looking through the Hunger component, the error is most likely because the variables pushed with the "hungerdelta" event are (Unfortunately) different then with "temperaturedelta" in the temperature component. For hungerdelta, you'd want to do data.newpercent and data.oldpercent instead of new and last (It won't mess anything up to keep the local variables the same)

Also, I believe its generally better to use the component's in-built functions to set/get its stored variables. In your case you can do

inst.components.hunger:SetRate(1 * TUNING.WILSON_HUNGER_RATE)

instead of inst.components.hunger.hungerrate =

Same result but better form and shouldn't break if they ever change that variable in the code, as unlikely as that is. Probably won't matter either way, though.

  • Like 1
Link to comment
Share on other sites

I appreciate your help and your patience Merkyrrie. I feel like I am learning more each file I search and each change I make. The server no longer crashes, however the function still does not manifest in game.

This is what I am working with now:

Spoiler

local function hungerspeed(inst, data)

    local newpercent = math.floor(data.newpercent)

    local oldpercent = math.floor(data.oldpercent)

    if newpercent == oldpercent then

        return

    end

 

    if newpercent > 75 then

        inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE * 50)

    elseif newpercent <= 75 then

        inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE * 1)

     end

 

end

I have tried experimenting with moving some bits of code or renaming variables or moving variables but all of this either results in a failed server launch or nothing happening. I have looked through other character files that have differing hunger rates (such as Warly). I am wondering if I am missing something from the master_postinit that should tell the server what to set my hunger rate as. The only thing I have related to hunger in the master_postinit as of now is the ListenForEvent for hungerdelta. I appreciate your help. I think if I am able to get this working I will be motivated to take some lua lessons online, haha.

Link to comment
Share on other sites

Oh! I completely forgot, stuff like hunger and sanity are almost always given out as percents (Because the max won't always be 100) so their value is actually between .0 and 1 rather than 0 and 100. My bad honestly, that slipped my mind somehow despite the values being sent literally being named new percent.

Just change 75 to .75 and it should start working properly. That is, if your character has 100 hunger and you want it to start at 75. Otherwise just find the percent you want it to start at instead.

  • Hunger 1
Link to comment
Share on other sites

9 hours ago, Merkyrrie said:

Oh! I completely forgot, stuff like hunger and sanity are almost always given out as percents (Because the max won't always be 100) so their value is actually between .0 and 1 rather than 0 and 100

Thought about it a bit and this also means you'll wanna get rid of the math.floors as they'll only be turning the decimal into a whole 0, which means the if newpercent == oldpercent won't work either because the decimals tend to come in as stuff like .998545225 or .500125611 and will likely never be equal to oldpercent. Lua unfortunately doesn't have a clean way of shaving these decimals down without turning it into a string.

Luckily it doesn't look like hungerdelta gets called nearly as much as temperaturedelta so not returning early shouldn't be a big problem. You might want to set up a check for if you've already changed hunger rate though, as there's no need to be constantly setting it to the same value. There's unfortunately no GetRate function for hunger so you'd either need to be setting your own variable in the character prefab or you can probably get away with using inst.components.hunger.hungerrate for it in this case if needed.

Simplest way would be

if newpercent < .75 and inst.components.hunger.hungerrate ~= (TUNING.WILSON_HUNGER_RATE * 50) then

This way even if its called a lot its still only doing an if check then finishing the function rather than pointlessly changing a 1 to a 1

Without using hunger.hungerrate you could setup a local hungerrate variable outside the function that you then set to the same thing you set SetRate to and check that in the if statement

  • Health 1
Link to comment
Share on other sites

12 hours ago, Merkyrrie said:

Oh! I completely forgot, stuff like hunger and sanity are almost always given out as percents (Because the max won't always be 100) so their value is actually between .0 and 1 rather than 0 and 100. My bad honestly, that slipped my mind somehow despite the values being sent literally being named new percent.

Just change 75 to .75 and it should start working properly. That is, if your character has 100 hunger and you want it to start at 75. Otherwise just find the percent you want it to start at instead.

Whoopsies, I figured the hunger was a percent but it's been so long since I've taken a math class I was thinking the percent value would scale from 1-100 instead of being a decimal.

Quote

Thought about it a bit and this also means you'll wanna get rid of the math.floors as they'll only be turning the decimal into a whole 0, which means the if newpercent == oldpercent won't work either because the decimals tend to come in as stuff like .998545225 or .500125611 and will likely never be equal to oldpercent. Lua unfortunately doesn't have a clean way of shaving these decimals down without turning it into a string.

The function finally worked after I removed the math.floor rounding! Thank you so much.
 

Quote

Simplest way would be

if newpercent < .75 and inst.components.hunger.hungerrate ~= (TUNING.WILSON_HUNGER_RATE * 50) then

This way even if its called a lot its still only doing an if check then finishing the function rather than pointlessly changing a 1 to a 1

I tested it after adding the "and" function you suggested to optimize the code, but it seems to just break it and the hunger rate doesn't change when it goes below the threshold. I ended up just removing the check for that because it works fine without, albeit probably a bit more taxing that way.

Thanks again for all your help, I understand a lot more now than I did before. Seeing this function finally work is exciting.

Link to comment
Share on other sites

20 minutes ago, Bluehero said:

I tested it after adding the "and" function you suggested to optimize the code, but it seems to just break it and the hunger rate doesn't change when it goes below the threshold. I ended up just removing the check for that because it works fine without, albeit probably a bit more taxing that way.


Thanks again for all your help, I understand a lot more now than I did before. Seeing this function finally work is exciting.

I may have done it backwards to what you were going for, the TUNING.WILSON_HUNGER RATE * 50 part should be the same as what you're setting it to right after and the elseif will also need it. Otherwise.. not sure what would be causing that to not work.

And glad I could help, hope all your future modding endeavors go well :grin:

  • Potato Cup 1
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...