Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Check if a day have past, and make a calcul.

edited February 2017 in Help! with 2.0
Hi,

Here is the calendar I use : Here

My Question is :

Is it possible with the widget above, that at the end of a day a calcul is done? something like :
set $GMoney+=((random(1, 3)*$Population)/2)

And don't do that on Sunday. (I'm sure it will be to simple if I don't put a condition ;))

Thanks.

Comments

  • The general idea is that each time you change the time, you want to check if you have ticked over to a new day. I'm at work at the moment, so apologies if there are any errors in the below. My intention is just to give you an idea of how you could approach this problem.

    There are many ways to do that sort of thing, with the simplest (and perhaps least reliable) method being something like this:
    <<widget "addhours">>\
    <<if ($gameDate.getUTCHours() + $args[0]) > 23>>\
    /* This will take us past midnight, so run end of day calculations in here.*/
    <</if>>\
    <<run $gameDate.setUTCHours($gameDate.getUTCHours() + $args[0])>>\
    <</widget>>
    

    This approach is problematic though, because if you put <<addhours 72>> somewhere in your story to pass 3 days, the end of day code will only run once, even though you would want it to run 3 times in a row. You would also need to come up separate solutions for <<addmins>> and <<adddays>>.


    A more robust approach might be something like:
    <<widget "addhours">>\
    /* save the old date value before we modify it*/
    <<set _oldGameDate = new Date($gameDate.getTime())>>\
    <<run $gameDate.setUTCHours($gameDate.getUTCHours() + $args[0])>>\
    /* pass the old and new date values to the end of day function*/
    <<eod _oldGameDate $gameDate>>
    <</widget>>
    
    /* make a whole new widget that gets called by addhours, addmins, etc */
    <<widget eod>>
    /* work out a total number of days in the old and new dates, rounded down to make sure we're only ever dealing with whole days */
    <<set _firstDay to Math.floor($args[0].getTime() / 86400000)>>
    <<set _lastDay to Math.floor($args[1].getTime() / 86400000)>>
    <<set _numDays to _lastDay - _firstDay>>
    <<for _i to 0; _i < _numDays ; _i++>>
    /* Any code in here will run once per day that has passed.*/
    <</for>>
    <</widget>>
    

    It takes a bit more work to do it this way, but it's much harder to accidentally break it once it is up and running.
  • Hi,

    Thanks for the answer, I'll check that when I'll be back from work.

    Have a good day.
  • Hi,

    That's working.
    I extend it to month if some people is interrested in :
    /* Adds the specified number of hours. */
    <<widget "addhours">>\
    /* save the old date value before we modify it*/
    <<set _yesterday = new Date($gameDate.getTime())>>\
    <<set _month = new Date($gameDate.getMonth())>>\
    <<run $gameDate.setHours($gameDate.getHours() + $args[0])>>\
    /* pass the old and new date values to the end of day function*/
    <<earn _yesterday $gameDate>>
    <<pay $gameDate>>
    <</widget>>
    
    <<widget earn>>
    /* work out a total number of days in the old and new dates, rounded down to make sure we're only ever dealing with whole days */
    <<set _firstDay to Math.floor($args[0].getTime() / 86400000)>>
    <<set _lastDay to Math.floor($args[1].getTime() / 86400000)>>
    <<set _numDays to _lastDay - _firstDay>>
    <<for _d to 0; _d < _numDays ; _d++>>
    /* Any code in here will run once per day that has passed.*/
    <</for>>
    <</widget>>
    
    <<widget pay>>
    <<set _nextmonth to $args[0].getMonth()>>
    <<set _numMonth to _nextmonth - _month>>
    <<for _m to 0; _m < _numMonth ; _m++>>
    /* Any code in here will run once per month that has passed.*/
    <</for>>
    <</widget>>
    

    Thanks a lot.
  • Oh, I just realised I forgot to put a \ at the end of each line. You'll need to do that or you'll get lots of blank lines in your passage each time you use these widgets.
  • One slight modification to the earn and pay widget you may want to think about is, instead of hard-wiring the "Any code in here will run once per X" code into the widget itself place that code within two passages with Known Names and change the widgets to silently display those passages instead, which will cause the markup within then to be executed. This separates the WHEN should the special event code be run from the actual special code, the same way special passages like StoryInit work.

    eg. Somthing like the following:
    <<for _d to 0; _d < _numDays ; _d++>>
    <<display "EOD">>
    <</for>>
    
    and
    
    <<for _m to 0; _m < _numMonth ; _m++>>
    <<display "EOM">>
    <</for>>
    
    warning: The above was written without any testing, you may need wrap the <<display>> macro calls within <<silently>> macros.
  • edited March 2017
    @Alianna, I just realised you are setting _month inside <<addhours>> and then using _month inside <<pay>>.

    @greyelf, do you know if this is valid usage? Can temporary variables persist across widgets like this? I'm not exactly sure which scope they reside in.
  • Rokiyo wrote: »
    Can temporary variables persist across widgets like this? I'm not exactly sure which scope they reside in.

    We should also page @TheMadExile to this question as well.

    I also would like to know the answer to this question.
  • edited March 2017
    As noted within the documentation, temporary variables exist for the lifetime of the moment/turn that they're created in. As long as the call to <<pay>> happens within the same moment/turn as the call to <<addhours>>, everything should be fine.

    SEE: TwineScript > Variables.
  • edited March 2017
    greyelf wrote: »
    One slight modification to the earn and pay widget you may want to think about is, instead of hard-wiring the "Any code in here will run once per X" code into the widget itself place that code within two passages with Known Names and change the widgets to silently display those passages instead, which will cause the markup within then to be executed. This separates the WHEN should the special event code be run from the actual special code, the same way special passages like StoryInit work.

    eg. Somthing like the following:
    <<for _d to 0; _d < _numDays ; _d++>>
    <<display "EOD">>
    <</for>>
    
    and
    
    <<for _m to 0; _m < _numMonth ; _m++>>
    <<display "EOM">>
    <</for>>
    
    warning: The above was written without any testing, you may need wrap the <<display>> macro calls within <<silently>> macros.

    Hi,

    So if I understand, I create two passages named "earn" and "pay".
    I write the the "Any code in here will run once per X" code in them.

    I call them in the widget.

    And in the passage I want it to run, I put the code you write (or something like that and maybe in a <<silently>> macro).

    Sorry, my english and twine experience are not so advanced ^^.

    Thx.
  • Alianna wrote: »
    So if I understand, I create two passages named "earn" and "pay".
    I write the the "Any code in here will run once per X" code in them.

    I call them in the widget.

    And in the passage I want it to run, I put the code you write (or something like that and maybe in a <<silently>> macro).

    Basically yes, although I personally would not name the special passages earn and pay because that would make their names too similar to the widget names and could cause same confusion.

    note:
    I (automatically and maybe wrongly) used the passage names EOD and EOD, which stand for End-of-Day and End-of-Month respectively, because in the past I have worked on accounting/financial systems and those three letter acronyms describe the (well known in those sectors) events that are occurring.
  • As long as the call to <<pay>> happens within the same moment/turn as the call to <<addhours>>, everything should be fine.

    One more thing, TME, a moment/turn changes with Passage traversal, right? Or in fact anything that changes the history? So, merely displaying passages doesn't change a turn?
  • As noted within the documentation, temporary variables exist for the lifetime of the moment/turn that they're created in. As long as the call to <<pay>> happens within the same moment/turn as the call to <<addhours>>, everything should be fine.

    SEE: TwineScript > Variables.
    I had seen that, but I'm still not completely clear on what you mean by moment/turn.

    Are you referring to the full batch of tasks that occurs during passage rendering? I.e. A temporary variable created in PassageHeader will still exist while PassageFooter is rendering, but won't exist when the user clicks on a setter link within the rendered passage?


  • Only passage navigation creates new moments/turns and only at the start of said navigation is the temporary variable store reset.

    A temporary variable set within any of the on navigation recurring special passages will exist until the start of a new navigation—e.g. a temporary variable created in PassageHeader will be available within PassageFooter.
  • Only passage navigation creates new moments/turns and only at the start of said navigation is the temporary variable store reset.
    That is helpful, thank you. I had been treating temporary variables as if they were JavaScript variables declared within a function, ie assuming they weren't available outside of the scope they were declared in.
Sign In or Register to comment.