+3 votes
by (390 points)
Hello all, i'm completely new here, and twine in general.

The last two weeks i've been watching lots of tutorials on YT, and a whole bunch of threads explaining how to do certain things.

I have an idea to create a relatively big, open world management game, i already know how to use some macros, but right now i can't continue without having a decent, simple, easy to use date and calendar system that counts time (only hours and minutes).

The story format i'm using is Sugarcube 2.21.0, on Twine 2.2.1.

I never dabbled in JS before, or any kind of coding in general, hence my ignorance.

My other problem is that most of the threads i find about how to make a clock system, are either for twine 1 or earlier versions of sugarcube, and not applicable to my case.

What i'm looking for essentially is a timer that counts time as a normal clock would, but only counts time through entering passages, for example, a sleep passage makes time go by 8hours, another makes time pass by 1minute, and so forth. And if it could count days and months as well, that'd be perfect.

I know this question gets asked a lot, and i don't want to add to the pile, but i'm tired of banging my head against the wall.

Can someone help me, please?

3 Answers

+2 votes
by (8.6k points)
selected by
 
Best answer

In the simplest case, for Earth dates in the Gregorian calendar, just use the standard JavaScript Date object. Set some value to it at the beginning of your game (in StoryInit or your starting passage) and you can always refer to it later to add or change the "current" time.

<<set $now = new Date("2238-07-05T10:30:00Z")>>

The Date object, for all its faults, has the neat ability that its numbers "overflow". For example, if you'd add 20 hours to this particular date and print it, it would be the morning of the 6th July, not the 30th hour of the 5th July.

<<run $now.setHours($now.getHours() + 20)>>
<<= $now.toGMTString()>>
/* prints "Fri, 06 Jul 2238 06:30:00 GMT" */

You can add some macros around this, in particular for the display, and you can also look at the moment.js module if you want even better control over dates and times. But to know what exactly to suggest here we'd need way more specifics about your requirements for manipulating and displaying the date and time.

For an example of a bit of possible "chrome" to polish your game with, take a look at the dyClockJS module.

by (390 points)
Thanks a lot for the detailed explanation.

You cleared things a bit more for me, but now i see my greatest obstacle will be JavaScript, as everytime i see javascripts i get a small seizure, how big and complex they are, specially for me, one who never programed anything in my life.

This is all very new, and very different from anything i've done, but i'll get there in time.

Thanks a lot again.

Any kind of help is appreciated and welcome! =)
+2 votes
by (44.7k points)
by (390 points)
Thank you for your reply, but seeing as i'm still watching tutorials and learning to control Sugarcube, all of these leave me with more answers than questions. I'll learn eventually though, at least i have three links to some examples i can apply in the future.

 

Thank you again. =)
+3 votes
by (8.9k points)
  • Create a new passage called "Game Clock".
  • Add a widget tag to this passage.
  • Paste Mad Exile's Gregorian Date & Time Widgets into this passage:
/*
	Date & Time Widget Setup
*/
<<set
	window.GameDays to [
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
	];
	window.GameMonths to [
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	];

	/*
		Below we have to use the multi-parameter version of the Date
		constructor, rather than the date string version, because the
		date string version treats a missing timezone offset as UTC.
		While there are ways to determine players' timezone offsets,
		so they could be added to a date string, it's more convenient
		simply to use the multi-parameter constructor.

		The point of this is so that you can simply initialize the game
		world clock to whatever date and time you wish without having to
		worry about the players' timezone offsets, while still ensuring
		that they all see the same game world dates and times.
	*/
	/* params: year , month(0-based) , day , hour(24H) , minute [, second ] */
	$gameDate to new Date(2015, 2, 17, 3, 24); /* e.g. Mar 17, 2015 03:24 */
>>


/*
	Date & Time Advancement Widget Definitions
*/
/* Adds the specified number of minutes. */
<<widget "addmins">>\
<<run $gameDate.setMinutes($gameDate.getMinutes() + $args[0])>>\
<</widget>>

/* Adds the specified number of hours. */
<<widget "addhours">>\
<<run $gameDate.setHours($gameDate.getHours() + $args[0])>>\
<</widget>>

/* Adds the specified number of days. */
<<widget "adddays">>\
<<run $gameDate.setHours($gameDate.getHours() + $args[0] * 24)>>\
<</widget>>


/*
	Date & Time Printing Widget Definitions
*/
/* Prints the current date ("{weekday} {month} {day}, {year}"). */
<<widget "date">>\
<<print String.format("{0} {1} {2}, {3}",
	GameDays[$gameDate.getDay()],
	GameMonths[$gameDate.getMonth()],
	$gameDate.getDate(),
	$gameDate.getFullYear()
)>>\
<</widget>>

/* Prints the current time (12H). */
<<widget "time12hr">>\
<<if $gameDate.getHours() eq 0>>\
12\
<<elseif $gameDate.getHours() gt 12>>\
<<print $gameDate.getHours() - 12>>\
<<else>>\
<<print $gameDate.getHours()>>\
<</if>>:\
<<if $gameDate.getMinutes() lt 10>>0<</if>><<print $gameDate.getMinutes()>> \
<<if $gameDate.getHours() gte 12>>PM<<else>>AM<</if>>\
<</widget>>

/* Prints the current time (24H). */
<<widget "time24hr">>\
<<if $gameDate.getHours() lt 10>>0<</if>><<print $gameDate.getHours()>>:\
<<if $gameDate.getMinutes() lt 10>>0<</if>><<print $gameDate.getMinutes()>>\
<</widget>>

/* Prints the current date and time (12H). */
<<widget "datetime">><<date>> <<time12hr>> (<<time24hr>>)<</widget>>
  • To advance the time 5 minutes in a passage, type <<addmins 5>> somewhere into the passage.
  • To advance 7 hours, <<addhours 7>>
  • To advance 30 days, <<adddays 30>>
by (390 points)

Thank you for your help.

I eventually got this code to work, the only things i'm missing right now are hou to make if statements regarding specific days and months!

I can set up shop hours no problem, but setting up certain events that take place only on certain days and months, now that i can't do. I tried looking into the written code, to see if what i'm seeking is there, and either it isn't or i'm just blind.

I tried lots of ways to refer to specific days, these are some of my attempts:

   \<<if $gameDate.getUTCDay() gte "mon">>
  It's closed.
   \<</if>>

   \<<if $gameDate.getUTCDay() is "Mon">>
  It's closed.
   \<</if>>

   \<<if $gameDate.getUTCDay() is "Monday">>
  It's closed.
   \<</if>>

   \<<if $gameDate.getUTCDay() is "monday">>
  It's closed.
   \<</if>>

   \<<if $window.GameDays is "mon">>
  It's closed.
   \<</if>>

   \<<if $gameDate.getUTCDay("mon") gte "mon">>
  It's closed.
   \<</if>>

   \<<if $gameDate.getUTCDay() is "mon">>
  It's closed.
   \<</if>>
  
   \<<if $gameDate.getDay("mon")>>
  IT'S CLOSED!!!
   \<</if>>
   
   \<<if $gameDate.getDay("tue")>>
  TUESDAY IS CLOSED!!!
   \<</if>>

I'm sure i'm doing something wrong,..

by (8.9k points)
<<if $gameDate.getDay() == 0>>It is Sunday
  <<elseif $gameDate.getDay() == 1>>It is Monday
  <<elseif $gameDate.getDay() == 2>>It is Tuesday
  <<elseif $gameDate.getDay() == 3>>It is Wednesday
  <<elseif $gameDate.getDay() == 4>>It is Thursday
  <<elseif $gameDate.getDay() == 5>>It is Friday
  <<elseif $gameDate.getDay() == 6>>It is Saturday
<</if>>

<<if $gameDate.getMonth() == 0>>It is January
  <<elseif $gameDate.getMonth() == 1>>It is February
  <<elseif $gameDate.getMonth() == 2>>It is March
  <<elseif $gameDate.getMonth() == 3>>It is April
  <<elseif $gameDate.getMonth() == 4>>It is May
  <<elseif $gameDate.getMonth() == 5>>It is June
  <<elseif $gameDate.getMonth() == 6>>It is July
  <<elseif $gameDate.getMonth() == 7>>It is August
  <<elseif $gameDate.getMonth() == 8>>It is September
  <<elseif $gameDate.getMonth() == 9>>It is October
  <<elseif $gameDate.getMonth() == 10>>It is November
  <<elseif $gameDate.getMonth() == 11>>It is December
<</if>>

 

by (390 points)

Thanks a whole bunch, this makes everything much easier! yeslaugh

by (8.9k points)
No problem, good luck!
by (44.7k points)

You can use the .toLocaleString() function to shorten just about all of the above code.  For example:

<<-$gameDate.toLocaleString("en-US", { weekday: 'long', month: 'short', day: 'numeric', year: 'numeric' } )>>

That would output something like "Monday, Oct. 8, 2018".  It's not limited to the date either, you can have it show the time as well by adding that to the options.  See the documentation linked to above for the various option settings.

by (170 points)

Hi,

I've been trying to use a date and time tool/widget and it seems this one worked. Mainly to show it on the sidebar as so:

Time: <<time24h>>
Date: <<date>>

I've also removed the year from the widget since I did not need it and it worked perfectly:

<<print String.format("{0} {1} {2}, {3}",
	GameDays[$gameDate.getDay()],
	GameMonths[$gameDate.getMonth()],
	$gameDate.getDate(),
)>>\

I can add days, hours and so on, but I've tried to create a way to set the time so that it can be more flexible. Like so:

/* Date & Time Setting Widget Definitions */
/* Sets the specified number of minutes. */
<<widget "setmins">>\
<<run $gameDate.setUTCMinutes($gameDate.setUTCMinutes() + $args[0])>>\
<</widget>>

/* Sets the specified number of hours. */
<<widget "sethours">>\
<<run $gameDate.setUTCHours($gameDate.setUTCHours() + $args[0])>>\
<</widget>>

/* Sets the specified number of days. */
<<widget "setdays">>\
<<run $gameDate.setUTCHours($gameDate.setUTCHours() + $args[0] * 24)>>\
<</widget>>

It's, obviously, mainly a copy/paster of the advance time of Mad Exile's /* Adds ... */. I thought it could work, but it displays this:

Time: :
Date: NaN,

The character goes to sleep. So I need a day to pass and the time to always be 8:00 (24h). The code looks like this:

/* Sets hours */
<<sethours 09>>
/* Sets minutes */
<<setmins 00>>

/* Adds 1 day-Pass time */
<<adddays 1>>

Adding things works like a charm. But it seems like I'm far from knowing how to change the "add" command into a "set" one.

I hope that's clear enough and that it isn't too much to ask for. I can't figure out how to solve it, but something tells me it's simple when I look at the code I'm using for reference (not that I'd be able to create it...).

by (170 points)
I'm curious, did you ever figure out how to set it to a specific hour/minute/day?
by (8.9k points)

To set the date to midnight Jan 1, 1885

<<set $gameDate to new Date(1885, 0, 1, 0, 0)>>

 

To set the date to 9.28AM Nov 12, 1955

<<set $gameDate to new Date(1955, 10, 12, 9, 28)>>

 

To set the date to 2.42AM Oct 27, 1985

<<set $gameDate to new Date(1985, 9, 27, 2, 42)>>
by (110 points)
edited by

I believe the issue was about how to set the hour for example, without changing the day. Seeing as in some game systems it's impossible to tell on which day the player is going to sleep in their bed on. If there are other ways for days to pass, for example.

<<set $gameDate.setHours(8)>> 

 sets the time to 8 AM

<<set $gameDate.setHours(16)>>

sets the time to 4 PM

So, for instance, writing this in your 'bed time passage'...

<<adddays 1>>
<<set $gameDate.setHours(8)>>

Will take you to 8AM tomorrow morning. I've not studied making widgets, so not sure how to make a neat 'sethour' widget, but I guess I could look into that.

by (170 points)

I tried this but it sets it to the wrong hour- say if I do the 

<<set $gameDate.setHours(16)>>

it sets the time to 9 pm, not 4. I'm not sure why. 

by (110 points)

There's something wrong with your code somewhere. By default, it should work.

var event = new Date('August 19, 1975 23:15:30');
event.setHours(20);

console.log(event);
// expected output: Tue Aug 19 1975 20:15:30 GMT+0200 (CEST)
// (note: your timezone may vary)

event.setHours(20,21,22);

console.log(event);
// expected output: Tue Aug 19 1975 20:21:22 GMT+0200 (CEST)

I can't figure out what could cause it to behave in the manner you described though. Maybe someone else can help you with that.

by (170 points)
I'm not sure exactly what part of the code I had was wrong- I recopied the widget that was posted above and replaced what I had, and it's working now.
by (120 points)
Well I did want this on the sidebar and but I didn't want to ring in months into this

Plus I want to make a timer, being able to detect the passage of days when activated

But I didn't see any way to add it to the sidebar

Just how to implement it
by (170 points)

I'm not sure I'm understanding you right but- to add something to the side bar, create a passage named StoryCaption

There, you can put all the info you want that's not in a button, like so-

 

Time: <<time12hr>>


Name: $name

etc.

by (120 points)
edited by
Yeah, confuses me too now that I read it back

I wanted to add the day count and time to the sidebar, which you (kinda) clarified

But I want to add a day timer, when it is triggered to begin, after so many days something happens

This 'should' be more understandable

And with the top answer, copy pasta in a Game Clock passage, I don't know how to display it in the sidebar as "setMinutes" and "setHours" is undefined
by (170 points)

I wasn't sure myself how to work it with the widget above. I have a bit of coding where, you go to bed, and it adds a day, outside of the widget.

I have a $days variable set up in storyinit, initially set to 1.

So, a basic set up I have is- 

::Home::

<<days>>
Blah blah.


<<button "Go to bed" "Home">>
<<set $gameDate.setHours(7)>>
<<set $gameDate.setMinutes(0)>>
<<set $days += 1>>
<</button>>

<<button "Leave" "Somewhere Else">>
<</button>>

(Hope this helps with the setminutes issue. The 7 sets it to 7 am, the 0 sets it to 00, so 7:00 am, to show it, you would just have it say <<time12hr>>)

Where <<days>> is a widget I set up, as below-

::days::

<<widget "days">>
	<<if $days == 2>>
		<<set $testtext to "It's day 2">>
	<<elseif $days == 3>>
		<<set $testtext to "It's day 3">>
	<</if>>
	
<</widget>>

(The $texttext is just something to help me see that it's actually being triggered). You can play around a bit if you were more interested in it being weekday (if $days == "Sunday") or something, rather than just 1 or 2. But, whatever it is, you would just put $days in the StoryCaption to show what you want for it.

Let me know if this isn't quite what you're looking for still!

...