Stats lowering with real time pass [SOLVED]

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
M.T.D.G.
Regular
Posts: 112
Joined: Sun Jun 01, 2008 12:37 pm
Completed: -SacrifiXi (BxB)-Beta-Love (BxB)-Ivan Berk Dress Up Game-Kiss the Cock (BxG)
Projects: -Death on Holiday (BxG)
Tumblr: mtdg
Deviantart: M-T-D-G
itch: mtdg
Location: Italy
Contact:

Stats lowering with real time pass [SOLVED]

#1 Post by M.T.D.G. »

I'm making a Tamagotchi-like videogame and I managed to make stats raise with their relative always-on-screen bars by clicking their respective functions. Now, I'd like those stats to deplete when real time passes, even after the game is closed. For example, I'd like "hunger" stat to lower by 1 point after, say, 60 minutes.
How should I code this? This is what I have so far:

Code: Select all

init:
    $ import time
    $ year, month, day, hour, minute, second, dow, doy, dst = time.localtime()
    
label quit:
    $ persistent.last_exit = time.time()
    
    
label start:
    $ minutes = time.time()    
    
    if minutes += 60:
    $ hunger_level -=1
I know these last two lines don't make much sense (indeed I get an error when I launch the game) but I'm terrible at coding and I don't know what else to do.
Last edited by M.T.D.G. on Wed Jun 13, 2018 3:56 pm, edited 1 time in total.
mtdg.tumblr.com (nsfw)

ImageImageImageImageImage

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Stats lowering with real time pass

#2 Post by kivik »

You've got a few problems with your code.

Code: Select all

    if minutes += 60:
    $ hunger_level -=1
This contains the following errors:
- you haven't indented the line beneath the if statement - that's how python blocks work
- your if statement doesn't contain a comparison operator - you're trying adding 60 to minutes in an if statement, that doesn't work in python.
- not sure what you thought the code would do, but the most it'd ever do is subtract 1 from hunger_level. It's not in a loop (if that's what you're aiming for), so it's not doing anything interesting with the number 60 that would calculate the hunger_level for you.

Other problems include:
- you're missing a return statement in your quit label, this means your game won't actually ever quit, it'll just roll back to the start label.
- you're not actually using the persistent variable to make any sort of comparison to the current time, you're recording it, and then ignoring it.
- time.time() returns time in seconds: https://docs.python.org/2/library/time.html#time.time not minutes. So you need to divide the difference by another 60 to get 60 minutes
- you're doing the calculation on the start label - this means the code to compare the closing time and start time will only happen when player starts a new game.


So to tackle what you want:
- you should write a function that does the comparison - and call that function periodically. This allows you to have a single place that does all the calculations, and you can call it at any point in time.
- the easiest thing to do to call this function periodically is to create an invisible screen (with nothing in it) and use a timer there. https://www.renpy.org/doc/html/screens.html#timer
- storing the quit time is useful, but what you really want, is to record when the last tick was when you updated your hunger stats. This way you're not just calculating the time difference between two random points > you're calculating the last tick AND the time difference, thus accurately working out whether it's time for another tick or not.
- to clarify what I mean. If I start playing the game at 12:00pm, quit the game at 12:59pm, then resume the game at 1:01pm. 2 minutes have passed, but 61 minutes have passed since the last tick. Hunger should go down by 1.
- it's probably worth using python's datetime functions to work out the time difference between two points rather than calculating it yourself. I'm not familiar with it the python datetime functions myself but you should be able to look it up.


Now I'm not sure what your experience is in programming, so I want to leave this here and let you have a think, and see if you can come up with some ideas, but the core components should be something like this:

1 - a function that compares the current time to the old time, works out the difference, calculate changes that needs to happen. It'll also work out the last "ticking point" and record that in a persistent variable.
2 - a screen that's shown (show it on a completely different layer than other screens, using the config.layers variable) so that it never gets hidden by accident. Have a timer on this screen that calls the function above periodically

Hope this helps, I can look into mocking something up if this is beyond your programming knowledge

User avatar
M.T.D.G.
Regular
Posts: 112
Joined: Sun Jun 01, 2008 12:37 pm
Completed: -SacrifiXi (BxB)-Beta-Love (BxB)-Ivan Berk Dress Up Game-Kiss the Cock (BxG)
Projects: -Death on Holiday (BxG)
Tumblr: mtdg
Deviantart: M-T-D-G
itch: mtdg
Location: Italy
Contact:

Re: Stats lowering with real time pass

#3 Post by M.T.D.G. »

kivik wrote: Wed Jun 13, 2018 9:43 am
Thanks for taking the time to write this useful answer! Sadly my coding skills are next to zero, I just mess around with tutorials and basic stuff (I'm just an artist).
The game I'm working at is a very small project that I started for fun but I'd like to implement what I wrote in my first post.
If you could help me with this code, I'd be very grateful but if it's something too complicated or time consuming, don't worry. I don't want to waste anybody's time! I'll try to find some other solution or -more probably- I'll drop the idea all together.
mtdg.tumblr.com (nsfw)

ImageImageImageImageImage

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Stats lowering with real time pass

#4 Post by kivik »

So I had a go at making this just now and it seems to work. I've added comments in the code but I'll do more explanation further down.

Code: Select all

# check all tickers on game load
label after_load:
    $ check_all_tickers()
    return

init python:
    config.layers.append("ticker")
    from datetime import datetime, timedelta

    # ticker class
    class ticker:
        def __init__(self, start_tick, minutes_per_tick, function):
            self.last_tick = start_tick
            self.minutes_per_tick = minutes_per_tick
            self.function = function

        def check_tick(self):
            minutes_lapsed = (datetime.now() - self.last_tick).total_seconds() / 60 # calculate minutes since last tick
            loop, remainder = divmod(minutes_lapsed, self.minutes_per_tick) # work out how many ticks since last tick and remainder
            self.last_tick += timedelta(minutes=loop * self.minutes_per_tick) # update last tick
            while loop > 0:
                self.function()
                loop -= 1

    # function to check all tickers in ticker_list
    def check_all_tickers():
        global ticker_list
        for ticker in ticker_list:
            ticker.check_tick()

    # your functions to update stats
    def func_hunger():
        global hunger
        hunger -= 1
        if hunger < 0:
            hunger = 0

    def func_happiness():
        global happiness
        happiness -= 1
        if happiness < 0:
            happiness = 0

# game start time - set it as a variable to synchronise all tickers
default start_tick = datetime.now()

# your stats
default hunger = 10
default happiness = 10

# create ticker objects
default ticker_hunger = ticker(start_tick, 1, func_hunger)
default ticker_happiness = ticker(start_tick, 2, func_happiness)
# a list containing all your tickers
default ticker_list = [ticker_hunger, ticker_happiness]

# just a screen to show you the stats
screen stats:
    frame:
        xalign 0.0 yalign 0.0
        vbox:
            text "Hunger: [hunger]"
            text "Happiness: [happiness]"

# the invisible ticker screen - updates every 1 second
screen ticker_screen:
    timer 1.0 action Function(check_all_tickers) repeat True

label start:
    show screen ticker_screen(_layer="ticker")
    show screen stats
    while True:
        "Hi!"
Since you said you're not familiar with programming, I've hopefully created something that's easy enough to use, using object orientation.

Picture there being little ticker people in this code, they're ticker objects (their properties is inside the class ticker). Each one is responsible for a different stats - so in this example I've created one for hunger, one for happiness. Each ticker takes 3 variables when you create it:
- the start_tick: which is the start time of the game, just use the start_tick variable for this
- minutes_per_tick: how many minutes should pass before the ticker executes changes to your stats
- function: what function should your ticker run when it's due to trigger a tick

The first two should be self explanatory, but the third, you'll need to create a python function to be passed into the ticker. I'll explain later, but essentially whatever function you pass into your ticker when you create it, it'll run that function when it's due a tick.

Now as mentioned in the last post, I'm using an invisible screen to trigger the tickers. The way I've done this is, I've put all the tickers into a list. The invisible screen will then call a function that goes through the entire list of tickers, and ask them to check whether they're due a tick - and if they are, they'll run their tick function. The screen runs once every second, which should be more than suitable for the purpose of this.


Now, if you want to create more tickers, you first need to create the ticker's function. Follow the examples of the existing functions - copy and paste them before renaming the relevant names and variables. Let's say we'll do a new one for the stats boredom:

Code: Select all

    def func_boredom():
        global boredom
        boredom = min(boredom + 1, 100)
I'm using a shorthand here, but basically I'm adding 1 to boredom, then if it's larger than 100, boredom exceeds 100. It works by comparing boredom + 1 and 100, and choosing the smaller (minimum) value. You can use hunger = max(hunger - 1, 0) to achieve the same effect when subtracting, but I kept it with if statements above.

Now that we've got the function, we just need to create the ticker and add it to the ticker_list:

Code: Select all

default ticker_boredom = ticker(start_tick, 10, func_boredom) # note there's no bracket to the function name here

default ticker_list = [ticker_hunger, ticker_happiness, ticker_boredom]
Note that I've added ticker_boredom to the end of the ticker_list here. Also I've put in 10 as the second parameter, so the ticker will only run the func_boredom function every 10 minutes.


Test it out yourself, I've used low values here so it's easy to test it. Try saving the game and then loading it a few minutes later to see the difference.


Note that no persistent variables are needed, because your saved game will automatically keep track of the last tick for every ticker, and since each tick would update the last_tick attribute for the ticker - you don't need to do anything on quit to record anything at all. The only thing I've done is to add an after_load label to run all the tickers again on load - otherwise it'd take 1 second before the tickers are triggered and update your stats.


Let me know if it makes sense.

User avatar
M.T.D.G.
Regular
Posts: 112
Joined: Sun Jun 01, 2008 12:37 pm
Completed: -SacrifiXi (BxB)-Beta-Love (BxB)-Ivan Berk Dress Up Game-Kiss the Cock (BxG)
Projects: -Death on Holiday (BxG)
Tumblr: mtdg
Deviantart: M-T-D-G
itch: mtdg
Location: Italy
Contact:

Re: Stats lowering with real time pass

#5 Post by M.T.D.G. »

kivik wrote: Wed Jun 13, 2018 1:41 pm ...
Your code works perfectly! I was almost moved when I saw the stat values behave the way they should...I should build you a statue! Your code is simple to understand but also very complex. I would have never been able to come up with it, so thank you very much for taking the time to help me. I'll be sure to credit you in the final game, if you don't mind.
mtdg.tumblr.com (nsfw)

ImageImageImageImageImage

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Stats lowering with real time pass [SOLVED]

#6 Post by kivik »

Hey cool! I ended up learning some new stuff myself like how to pass functions around and what python datetime functions there are. It was a fun little experiment :)

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]