calendar system

Morodin
28 Oct 2016, 05:58

So hello community, I just found this program and am very new to it, and not 5 minutes into learning I realized that I'd need a time based system for my game to run season and time based events. At this point this is very much beyond my understanding in the editor; I've done mods for Skyrim, Legends of Grimrock, and Fallout 4, but this is my first foray into the world of text based games. I'm sure this is technically possible to script but I'm not sure how to go about it.

What I'm looking for is a way to display a calendar in game. The closest thing to what I want is The Pixie's clock, and I took a serious look at it; but it the limit of 99 days really hurts with what I want to do. Here's the vision of what I'm looking for. A clock that displays the current in-game Month, day, hour and minute to the player. I fully expect the players to go through several 'years' in game to catch all the events. Could also have the year, though the year itself could be a simple +1 counter from the start date set if even there at all. I have no plans on doing anything with the actual year differences. Time would progress just like in The Pixie's clock library; the player moving from room to room and doing events would move time along manually. Certain events could take months, (being in a coma for 6 months as an example).

Logically speaking I know how this should technically work. It would be tracked in seconds, so a 5 minute walk would be 360 second advancement internally with two 'counters'; one for seconds and other for minutes. Then so on for hours, days, and months; even years. Technically once the base two are done the rest is a simple extension. This brings me to my question. Is there a way of extending The Pixie's clock library to be 365 days instead of 99? From there it would be a simple matter of setting the 'months' so that day 1 - 31 is displayed as January and 32 - 59 is February, etc. If I understand anything of how this system works that is.


hegemonkhan
28 Oct 2016, 07:20

I've tried to dabble into 'time and date' stuff, but it's really complicated (unless you create/use a very simple system) to try to have a 'real-world' 'time and date' system, as for me, just trying to understand the actual formula for the actual days in a year, change of days in a month every leap year and etc involved stuff, just kept getting more and more complex (though, I do suck-at/hate math), laughs. But, if you want to tackle this messy stuff, best of luck to you. It really gave me an appreciation of people who uphold/maintain/understand the technology that gives us our 'time and date' system in the real world, and of clocks/calenders on computers, and etc, lol.

However, I'd recommend not using 'real time' (Timers), but instead using the internal turns (any typed-in input or click of the mouse button on a hyperlink or the completion of a scripting, etc) (Turnscripts). Timers (using real time) are just really messy (ever done networking? or played multiplayer games online/offline, trying to synchronize the timing is really difficult to do so, whether it's between offline computers connected by a cable or online computers across the internet; ever experienced "lag" or "OOS: out of sync, errors/crashes" before? lol lol lol lol)

if you need help with coding individual parts, let me know and I can help with that stuff, but depending on how accurate you want your system to be to real 'time and date', I can't help with that, it's too complicated/complex for me.

generally, the design is this:

Time:

you have Integer Attribute(s) (which can be increased/decreased normally per internal turn and/or specified for actions/events: ie, traveling to this location increases the time by an hour whereas traveling to this location increases the time by a day / 24 hours, compared of to lets say the normal time between internal turns, being a second) for keeping track of whatever units of time you want to work with (seconds, minutes, hours, days, weeks, years, etc); the easiest is to just use a single base/smallest unit of time, and base (sorry, not good location for a pun) the other units of time off of that base/smallest unit of time.

to then deal with displaying 'clock time', you use the modulus (division but it finds/gets/returns the REMAINDER) operator: %

(the modulus operation is great for 'cyclic' stuff --- see below in the code box, and also for determining numbers' factors/if odd/if even: if VALUE%2=0, it is even, if not VALUE%2=0, it is odd, if VALUE%3=0, it has a factor of 3, if VALUE%7=0, it has a factor of 7, etc)

time_data_object.hour_integer_attribute = SOME_CURRENT_VALUE
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = A_VALUE_INCLUSIVELY_WITHIN_ZERO_TO_TWENTY_THREE_RANGE_:_0_-_23

time_data_object.hour_integer_attribute = 0
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 0

time_data_object.hour_integer_attribute = 1
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 1

time_data_object.hour_integer_attribute = 23
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 23

time_data_object.hour_integer_attribute = 24
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 0

time_data_object.hour_integer_attribute = 25
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 1

time_data_object.hour_integer_attribute = 47
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 23

time_data_object.hour_integer_attribute = 48
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 0

time_data_object.hour_integer_attribute = 49
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 1

time_data_object.hour_integer_attribute = 71
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 23

time_data_object.hour_integer_attribute = 72
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 0

time_data_object.hour_integer_attribute = 73
time_data_object.military_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 24
// time_data_object.military_hour_clock_time_integer_attribute = 1

you get the idea... lol

time_data_object.hour_integer_attribute = 18
time_data_object.civilian_hour_clock_time_integer_attribute = time_data_object.hour_integer_attribute % 12
// time_data_object.civilian_hour_clock_time_integer_attribute = 6 // this could be 6 am or 6 pm, you have to handle this too

I'm getting tired... but hopefully these links go into more of this stuff, including handling the 'date' aspect that I didn't cover in this post (day: sunday-saturday, seasons: winter-spring, months: january-december, etc etc etc):

http://textadventures.co.uk/forum/samples/topic/4317/time-and-date-coding
http://textadventures.co.uk/forum/quest/topic/5068/time-and-date-coding-a-syntaxformat-question
http://textadventures.co.uk/forum/samples/topic/4162/countdown-timer-code (just for amusement - my brain's "methods of madness", lol)

(I can't find any other links, in my quick-brief searching)


as for the 'date' stuff, that involves using List/Dictionary Attributes... I'll try to find links for them at a later time...

http://textadventures.co.uk/forum/samples/topic/5137/list-and-dictionary-extensive-guide-by-hk

I briefly give an example of handling 'days/months/etc' at roughly halfway through, but if you don't understand how dictionary and list Attributes work, you're going to need to learn if you want to handle calender/day/month/season/astrology-horoscope-zodiac-constellation/etc type stuff.

I'll still provide more links at a later time... if I can find them or if they even exist (lol) ... on more specifically the month/day/etc coding with lists and dictionaries. Or, I'll just write up a post on this stuff... if I got the time and am not lazy, lol.


if you're able to understand this 'time and date / calender' stuff, I'd just look up online on how 'time and date / calenders' ARE coded... there should be stuff online for how a calender software does the coding for it, for how it determines the month, the day, etc etc etc stuff.

otherwise, use Pixie's code, as it's the most well-done thus far publically available for coding noobs (and/or those who're not smart enough to understand time/date/coding/math stuff) like me, and if you want and/or can, you can expand upon it, but I'd use it as a starting base, or just use it as it is, if you can't create your own time/date/calender system.


Morodin
29 Oct 2016, 03:30

That last bit is exactly what I'm looking at doing. Pixie's Clock system is a great start at what I'm looking at doing. It just needs to be modified to fit the parameters that I need for this. So the question becomes how do I modify ?her? library to fit this?

Edit:
I sat down and did some thinking on how to accomplish a yearly calendar utilizing the system. Instead of trying to extend her 99 days to 365 then figure out how to parse that out into months. Instead I think resetting the 'day' Pixies system and then add months would be best here. Here's the 'code' I've worked out so far and this probably won't work if put into Quest. It's more of a placeholder until I can figure out how to actually make it work in code.

monthsend[1] = 31
if ((year mod 4 = 0) : 
	Leapyear = 1 & monthsend[2] = 29
else
	Leapyear = 0 & monthsend[2] = 28
end
monthsend[3] = 31
monthsend[4] = 30
monthsend[5] = 31
monthsend[6] = 30
monthsend[7] = 31
monthsend[8] = 31
monthsend[9] = 30
monthsend[10] = 31
monthsend[11] = 30
monthsend[12] = 31

$monthName[1] = 'January'
$monthName[2] = 'February'
$monthName[3] = 'March'
$monthName[4] = 'April'
$monthName[5] = 'May'
$monthName[6] = 'June'
$monthName[7] = 'July'
$monthName[8] = 'August'
$monthName[9] = 'September'
$monthName[10] = 'October' 
$monthName[11] = 'November'
$monthName[12] = 'December'

$month = $monthName[month]

if day > monthsEnd[month]:
	day -= monthsEnd[month]
	month += 1

	if month > 12: month = 1 & year += 1

	if month < 1: month = 1

	$month = $monthName[month]
end 

This basically checks the day number. If the day number is greater than the months end day it advances to the next month. I also included a check for year to include leap year but the functionality isn't completely implemented at this point. This would also allow a creation of events based on simply a day; so the event could happen on that day every month.


Morodin
01 Nov 2016, 16:38

I've ran into a small problem with Pixie's code. When I put in her snippet:

  player.parent = this.to
  SetInc(6)

In a room as an exit script then run the game. I get this error:

Error running script: Error evaluating expression '(not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "beforefirstenter")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression '(not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "beforefirstenter")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetBoolean(game.pov.parent, "dark")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetBoolean(room, "transparent")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(newParent)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetBoolean(room, "transparent")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(newParent)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetBoolean(room, "transparent")': GetBoolean function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(newParent)': GetAllChildObjects function expected object parameter but was passed 'null'

I've yet to modify anything in her library so I am kind of baffled as to what is going wrong, unless I'm simply putting the script in the wrong place or missing another library. Not that I see where else to put it. Also the 'game' is two rooms with nothing in them. Any assistance would be greatly appreciated.


hegemonkhan
01 Nov 2016, 20:58

quest docs' main page:

http://docs.textadventures.co.uk/quest/ (see the menu bar at the top for most of Quest's Scripts --- Script Attributes, Functions --- note that after clicking on 'functions' there's a link to switch from its categorical ordering to an alphabetical ordering, Types --- data/Attribute types, Elements)

here's the docs on Lists (Arrays) and Dictionaries (somewhat the same as Arrays):

http://docs.textadventures.co.uk/quest/guides/using_lists.html
http://docs.textadventures.co.uk/quest/using_dictionaries.html

here's a guide of mine on Lists (Arrays)/Dictionaries (somewhat the same as Arrays):

http://textadventures.co.uk/forum/samples/topic/5137/list-and-dictionary-extensive-guide-by-hk
http://textadventures.co.uk/forum/samples/topic/5138/explore-and-travel-code-sample-by-hk (old/poor code)


OBJECTS (of OOP/OOD --- underlying quest code, if I'm somewhat understanding its design, lol):

at user-level, they're called/known as...

Elements (Objects, Exits, Attributes --- these must be contained within any Element except another Attribute of course, Verbs, Functions, Commands, Turnscripts, Timers, Object Types --- quest's user level Classes/Groups, etc etc etc)

// ---------------------

// VARIABLES (3 types --- keeping this simple):
//
// -> (1) Variable: local/temporary: NAME_OF_Variable = VALUE_OR_EXPRESSION
// -> (2) Attribute: global/permanent (so long as the container/containing Object exists or still exists, of course): NAME_OF_OBJECT.NAME_OF_ATTRIBUTE = VALUE_OR_EXPRESSION
// -> (3) Parameters/Arguments: deals with Functions/Commands/etc

// ---------------

// Quest's OPERATORS:
//
// Assignment/Comparison-Equal To: =
// Addition/Concatenation: +
// Subtraction/Negative Number: -
// Multiplication: *
// Division (normal divison: finding/getting/returning the quotient): /
// Modulus (division, but finds/gets/returns the remainder): %
// AND: and
// OR: or
// Negation (Not) A: not NAME_OF_OBJECT.NAME_OF_ATTRIBUTE = VALUE_OR_EXPRESSION
// Negation (Not) B: <> // if coding directly, you need to enclose scripting within the '<![CDATA[ your_scripting ]]>' ?xml/aslx? tags, to tell quest that your '>' and '<' symbols are to be seen as 'greater than' and 'lesser than', instead of as the xml/aslx tags, ie '<object name="toy">content/body</object>' // if using the GUI/Editor for your scripting, it handles this for you // quest's unique 'aslx' is very similiar to 'xml', and its scripting is is similiar to C++/Java, excluding quest's user-friendly operators and etc stuff.

// --------------

Lists' index number starts at: 0 // first item in list
ListCount(LIST) = returns the quantity of items in list
Lists' last index (last item in list) number is: ListCount (LIST) - 1
ListItem(LIST, ListCount(LIST)) = ERROR (out of bounds of list error)
ListItem(LIST, ListCount(LIST) - 1) = NO error: returns the last item in your list
// so, if you want to work with the more human-friendly '1', then you got to account for '+/- 1' between using the value  for your list index number (1 - 1 = 0) vs dislaying the value to your human players (0 + 1 = 1)

// ----------------------

<object name="global_data_object">
  <attr name="month_stringlist_attribute" type="simplestringlist">january;february;march;april;may;june;july;august;september;october;november;december</attr>
  <attr name="month_stringdictionary_attribute" type="simplestringdictionary">january=1;february=2;march=3;april=4;may=5;june=6;july=7;august=8;september=9;october=10;november=11;december=12;1=january;2=february;3=march;4=april;5=may;6=june;7=july;8=august;9=september;10=october;11=november;12=december</attr>
  <attr name="nonleap_month_day_string_dictionary_attribute" type="simplestringdictionary">january=31;february=28;march=31;april=30;may=31;june=30;july=31;august=31;september=30;october=31;november=30;december=31;31=january;28=february;31=march;30=april;31=may;30=june;31=july;31=august;30=september;31=october;30=november;31=december</attr>
  <attr name="leap_month_day_string_dictionary_attribute" type="simplestringdictionary">january=31;february=29;march=31;april=30;may=31;june=30;july=31;august=31;september=30;october=31;november=30;december=31;31=january;29=february;31=march;30=april;31=may;30=june;31=july;31=august;30=september;31=october;30=november;31=december</attr>
  <attr name="day_stringlist_attribute" type="simplestringlist">sunday;monday;tuesday;wednesday;thursday;friday;saturday</attr>
  <attr name="day_stringdictionary_attribute" type="simplestringdictionary">sunday=1;monday=2;tuesday=3;wednesday=4;thursday=5;friday=6;saturday=7;1=sunday;2=monday;3=tuesday;4=wednesday;5=thursday;6=friday;7=saturday</attr>
  <attr name="season_stringlist_attribute" type="simplestringlist">winter;spring;summer;autumn</attr>
  <attr name="season_stringdictionary_attribute" type="simplestringdictionary">winter=1;spring=2;summer=3;autumn=4;1=winter;2=spring;3=summer;4=autumn</attr>
</object>

// string_var = "0"
// integer_var = ToInt (string_var)
// integer_var = 0

// integer_var = 0
// string_var = ToString (integer_var)
// string_var = "0"

// ToDouble (var) // quest's floating points/floats/decimal numbers data/attribute type

// IsInt (var/val) // returns true/false
// isNumeric (var/val) // returns true/false

// Lists and Dictionaries are basically an 'input-output' Function:

String Lists: input (LIST, string index number) ---> output (string value)
String Lists: input (LIST, string index number) ---> output (object reference value)

String Dictionaries: input (DICTIONARY, "string key") ---> output (string value)
Object Dictionaries: input (DICTIONARY, "string key") ---> output (object reference value)
Script Dictionaries: input (DICTIONARY, "string key") ---> output (script value/s)

VARIABLE = ListItem (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, index_number_INPUT) // returns a string/object, quest will handle the return type for you, based upon your inputted List's items)

VARIABLE = StringListItem (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, index_number_INPUT) // returns a string, inputted List must have string items

VARIABLE = ObjectListItem (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, index_number_INPUT) // returns an object, inputted List must have object items

same/similar concepts/logic for/with the Dictionaries:

DictionaryItem(xxx)
StringDictionaryItem(xxx)
ObjectDictionaryItem(xxx)
ScriptDictionaryItem(xxx)

// var = 0
// VARIABLE = StringDictionaryItem (global_data_object.month_stringlist_attribute, var)
// VARIABLE = "january"

// var = 11
// VARIABLE = StringDictionaryItem (global_data_object.month_stringlist_attribute, var)
// VARIABLE = "december"

// var = "28"
// VARIABLE = StringDictionaryItem (global_data_object.month_day_stringdictionary_attribute, var)
// VARIABLE = "february"

// var = "29"
// VARIABLE = StringDictionaryItem (global_data_object.leap_month_day_stringdictionary_attribute, var)
// VARIABLE = "february"

// var = "february"
// VARIABLE = StringDictionaryItem (global_data_object.month_day_stringdictionary_attribute, var)
// VARIABLE = "28"

// var = "february"
// VARIABLE = StringDictionaryItem (global_data_object.leap_month_day_stringdictionary_attribute, var)
// VARIABLE = "29"

// you can also add/remove items from a list/dictionary too:

// (for example... if you only want to have one month dictionary, then you'll have to 'remove--->add' to remove the wrong/old entry/item and add in the correct/new entry/item for when changing between 'february = 28 vs february = 29' days, though you can use add/remove for many other game design implications too, of course)

list add (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, "NAME_OF_ITEM") // String Value/Item for a Stringlist Attribute
list remove (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, "NAME_OF_ITEM") // String Value/Item for a Stringlist Attribute

list add (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, NAME_OF_ITEM) // Object (reference) Value/Item for an Objectlist Attribute
list remove (NAME_OF_OBJECT.NAME_OF_LIST_ATTRIBUTE, NAME_OF_ITEM) // Object (reference) Value/Item for an Objectlist Attribute

dictionary add (NAME_OF_OBJECT.NAME_OF_DICTIONARY_ATTRIBUTE, "NAME_OF_String_KEY", "String_VALUE") // string dictionary
dictionary remove (NAME_OF_OBJECT.NAME_OF_DICTIONARY_ATTRIBUTE, "NAME_OF_String_KEY") // string dictionary

dictionary add (NAME_OF_OBJECT.NAME_OF_DICTIONARY_ATTRIBUTE, "NAME_OF_String_KEY", String_VALUE) // object dictionary
dictionary remove (NAME_OF_OBJECT.NAME_OF_DICTIONARY_ATTRIBUTE, "NAME_OF_String_KEY") // object dictionary

// I'm not sure of the syntax for a Script Dictionary's script item...

The Pixie
02 Nov 2016, 08:01

I've ran into a small problem with Pixie's code. When I put in her snippet:

player.parent = this.to
SetInc(6)

In a room as an exit script then run the game. I get this error:

It needs to go into the exit, not the room. The exit has an attribute called "to", which is the destination, so the script moves the player there. The room has no such exit, so sets the player's current location to null, and errors ensue...

His code snippet by the way.


Morodin
04 Nov 2016, 02:21

Thank you both, you've both been very helpful to me on this. At this point I'm fully well over my head; I should probably generate some initial story, get the character gen working, and then come back to this after I'm a bit more familiar with how the editor works. That way I have something to actually test with. Hegemokhan I think has pretty much written the rest of the syntax out for me it seems if I read it right.

Also thanks for the clarification Pixie. That helps out a lot! Sorry about the Gender thing. Wasn't sure decided going with the default was better than hazarding a guess.


hegemonkhan
04 Nov 2016, 09:51

yep (barring likely mistakes, lol), that's quest's syntax for the stuff (replace my CAPS stuff with what you need to put there, and you can 'name' your stuff however you want too of course --- such as with my list/dictionary Attributes' names --- you don't have to use my naming/labeling system/convention, lol)


if I can remember now that Pixie is a he/him... so I don't have to use he/she... ARGH... that extra '/she' is a pain... (trying to be respectful is almost not worth it) lol.


Morodin
11 Nov 2016, 23:55

Hey, The Pixie; I'm having trouble locating which part of your library deals with displaying the time in the interface. I thought it was this part of the code, but either I didn't do it right (entirely possible) or I miss read what it's doing.

<function name="IncTime"><![CDATA[
    on ready {
      game_clock.time = game_clock.time + 1
      //msg("game_clock.time = " + game_clock.time)
      //msg("game_clock.event = " + game_clock.event)
      game_clock.minutes = game_clock.time % 60
      game_clock.hours24 = (game_clock.time / 60) % 24
      game_clock.days = game_clock.time / (60 * 24)
      name = "event_" + DD(game_clock.days) + "_" + DD(game_clock.hours24) + "_" + DD(game_clock.minutes)
      game_clock.countdown = game_clock.countdown - 1
      //msg("Looking for: " + name)
      o = GetObject(name)
      if (not o = null and HasScript(o, "look")) {
        if (game_clock.testing) msg("Found: " + o + " (" + o.alias + ")")
        // this is used by wait
        game_clock.event = true
        do(o, "look")
      }
      else if (game_clock.countdown < 0 and HasAttribute(game_clock, "nextstep")) {
        if (game_clock.testing) msg("Step found: " + game_clock.nextstep + " (" + game_clock.nextstep.alias + ")")
        // this is used by wait
        game_clock.event = true
        step = game_clock.nextstep
        game_clock.nextstep = null
        do(step, "look")
      }
      game.clock = TimeAsString()
    }
  ]]></function>

The Pixie
12 Nov 2016, 16:21

To get something to display in the interface, you need to set it as a status attribute, either on the game object or the player object, on the Attributes tab. In this case, you would add "clock" to the game object.

The relevant line from the above function is then the last one:

game.clock = TimeAsString()

The Pixie
12 Nov 2016, 17:09

The clock library is limited to 99 days for the events aspect, which expects the day to be a two digit string. If you are not using that, it should work fine (though it would be a good idea to put the start time to day 365 and check everything is okay).

Integers in Quest seem to have a limit of a little over 2 billion (2^31 = 2147483648 I guess), after which they become negative with no warning. If you store the date and time as a single integer you are then limited to 68 years (2147483647/365/24/60/60).

Here is some code for a function that will take a parameter called days and calculate a date as a string, counting from the year 2000 up to 2067, returning it as a string.

months = Split("January;February;March;April;May;June;July;August;September;October;November;December", ";")
year = 2000
flag = true
while (flag) {
  if (year % 4 = 0) {
    days_this_year = 366
  }
  else {
    days_this_year = 365
  }
  if (day > days_this_year) {
    year = year + 1
    day = day - days_this_year
  }
  else {
    flag = false
  }
}
if (year % 4 = 0) {
  days_in_months = Split("31;29;31;30;31;30;31;31;30;31;30;31", ";")
}
else {
  days_in_months = Split("31;28;31;30;31;30;31;31;30;31;30;31", ";")
}
month = 0
for (i, 0, 11) {
  days_in_month = ToInt(StringListItem(days_in_months, i))
  if (day > days_in_month) {
    month = month + 1
    day = day - days_in_month
  }
  else {
    return ("" + day + "th of " + StringListItem(months, month) + ", " + year)
  }
}

Morodin
14 Nov 2016, 04:56

Wow thanks Pixie! I was actually wanting to use the event calculator as well for this; but I didn't see it expecting 2 digits for the time and day as too much of a problem though. Here were my thoughts on this:

A: If the days were limited to the days in the month; then the days would never go over 2 digits or even close to 99.
1. This would probably ruin the "Time since started" function.
B: With the months portion added in, I could expand the event tracker and look up to include month in it's search.
C: Year would just be a visual for the player and not have any real affect on the events at all.
D: Rolling over to a new year; would mean missed events could and would be able to be done again.
E: Was looking at possibly having a completed flag so specific events didn't get repeated once done.

I wrote out some code in LUA which is what I'm most familiar with really quickly to illustrate what I'm looking at here. Maybe that will help. Also thanks so much for being patient with me and answering my questions so far. You've all been amazing help to me and I'm learning so much!

function clocktime

-- minutes = m
-- 24 Hour = h
-- 12 Hour = t
-- Days = d
-- Weekday = w
-- Month = n
-- Monthday = x
-- counter = i

weekday = {{"Monday", 1},{"Tuesday", 2},{"Wednesday", 3},{"Thursday", 4},{"Friday", 5},{"Saturday", 6},{"Sunday", 7}}
month = {{"January", 1},{"february", 2},{"March", 3},{"April", 4},{"May", 5},{"June", 6},{"July", 7},{"August", 8},{"September", 9},{"October", 10},{"November", 11},{"December", 12}}
endmonth = {{"January", 31},{"february", 28},{"March", 31},{"April", 30},{"May", 31},{"June", 30},{"July", 31},{"August", 31},{"September", 30},{"October", 31},{"November", 30},{"December", 31}}

"w, n d t:m"

for i = 1, do
   m = m + i
      if m > 60 then
         m - 60
         h + 1
      andif h > 24 then
         h - 24
         d + 1
      else
         return nil
      end
   end
   if h > 12 then
      t = h - 12
   else
      t = h
   end
   n = month
   if d > endmonth then
      n + 1
   andif n > 12
      n - 12
   else
      return nil
   end
end

Morodin
14 Nov 2016, 23:04

I guess a second question I have here, is that are we limited to putting the entire date into a single string? Couldn't we use multiple strings or make it so the 'day' keeps going back to 0 when a month is advanced?


hegemonkhan
15 Nov 2016, 02:53

resetting a value to zero, example:

(also, look into Dictionary Attributes: String Dictionaries, Object Dictionaries, and/or Script Dictionaries)

(and/or use a Function and/or a Turnscript)

(and there's also the modulus operator: %)

// the special 'changedXXX' Script Attribute:
<object name="global_data_object">
  <attr name="day_integer_attribute" type="int">0</attr>
  <attr name="month_string_attribute" type="string">unknown</attr>
  <attr name="changedmonth_string_attribute" type="script">
    this.day_integer_attribute = 1
  </attr>
</object>

Morodin
23 Nov 2016, 23:06

Hmmm... I've been looking at some things here with Java. I now know why the integer rolls over to a negative number when it hits that number, and I have some ideas about how to extend it so that value doesn't 'creep' like it does currently and allow people to use essentially an 'endless' system for their events. Don't have anything to present right now, as I'm still plowing through lessons in Java, but I'll get there. On a side note I'm liking the option of using a switch for the month and weekday. That would limit some of the string 'bloat' right there. The biggest roadblock so far is the printing as a string thing. I'm making progress in baby steps but I see a way of doing this the way I want it done. So huge progress at the same time. Your guys help so far has been invaluable as well both in understanding what the code here is doing and what we can do with it.


hegemonkhan
24 Nov 2016, 05:56

What's the problem with printing as a string, you're having?

(You seem to know programming, so you should be familiar with string concatenation, and the syntax isn't too difficult, along with an output/string being made up of text or VARIABLE or both)


Morodin
25 Nov 2016, 00:38

The problem is the string cap. +- 2147483648 is the max Java allows before it rolls over, and with the system in place would allow for ~67 years. While this is more than sufficient for what I want to do right now. (I'm well on my way to creation) I am looking at ways of extending this and to keep the integer as low as possible.

I was looking at doing this by moving the more 'static' information like Weekday and Month away from the print as string function or having separate strings for the various parts. Looking for efficiency and completion in case at some point in the future wants something that could be considered 'limitless' like a game with DND elves that a player could potentially play for 1800 years. Could even include custom number of months per year, or days per week.

Besides it's far better than reaching X turn and being confronted with "You have a heart attack from old age, you are dead". Because the code will literally fail if the string goes past that.


hegemonkhan
25 Nov 2016, 05:32

ah... the issue is the data type size limitation with java/css stuff or whatever it is you're doing... there's various designs/methods/ways of handling/dealing-with it... which you'are probably more familiar/creative with, then I am.


Morodin
08 Dec 2016, 22:50

Sooo... I may have been dumb here and miss read something wasting two weeks of time. Quest uses Java or JavaScript for the coding it does? I'm having a blonde moment and cannot find the info on the website.


hegemonkhan
08 Dec 2016, 23:39

Quest uses it's own coding language, 'aslx', it has two types of coding: (1) the 'xml/html'-like*** (ie web languages) 'creation tag block/line' code it uses, it also can use JS (JavaScript, a scripting only language I think - I don't know/not-learned 'JS' yet, 'JS' is NOT the same as the 'Java' programming language), but-and (2) quest's scripting code syntax is similiar to 'C++/Java', and quest also has similiar features (Lists/Dictionaries) to those found in the 'Python' programming language.

Python is more popular in Europe, C++ and Java is more popular in the U.S., though Python is gaining some popularity here now.


if you're interested, I highly recommend downloading notepad++, and if you do download it, once you got it installed and opened up, select 'xml' as the coding language (there's a 'language' option/drop-down in its menu bar at the top), and it will color-code for you, and I haven't noticed any issues with choosing 'xml', as it seems to work fine for quest's language. Notepad++ is also really nice as it has most/many programming language choices for color coding

https://notepad-plus-plus.org/

it's just an text-code editor software, it's not a full blown SDK/IDE software like VS (Visual Studio), NetBeans, Eclipse, etc


.***

<xxx>xxx</xxx>

or

<xxx>
  xxx
</xxx>

Morodin
10 Dec 2016, 19:13

Okay that was what was confusing me. The coding format I'm seeing is XML based. While I've been working in Java to do this as it felt the best to work with. I just want to know if Quest will accept Java or Javascript at this point?


The Pixie
10 Dec 2016, 19:24

No. It uses its own language (as well as XML), which is somewhat Java-like, but not Java. You can use JavaScript in the interface, but not to do this kind of stuff.


Morodin
14 Dec 2016, 23:13

I want to share the progress I've made on this. It's all based off of Pixie's Clock function. I'm basically taking that and expanding it to fulfill what I need. Also I'm only including the parts that have been edited from her original, there's a lot of code here as it is.

  <object name="game_clock">
    <inherit name="editor_object" />
    <time type="int">0</time>
    <minutes type="int">0</minutes>
    <hours24 type="int">0</hours24>
    <days type="int">1</days>
	<week type="int">1</week>
	<month type="int">1</month>
	<year type="int">2000</year>
	<attr name="monthofYear" type="simplestringdictionary"> 1=January;2=February;3=March;4=April;5=May;6=June;7=July;8=August;9=September;10=October;11=November;12=December;</attr>
	<attr name="dayofWeek" type="simplestringdictionary">1=Sunday;2=Monday;3=Tuesday;4=Wednesday;5=Thursday;6=Friday;7=Saturday;</attr>
    <countdown type="int">0</countdown>
    <increment type="int">0</increment>
    <waittime type="int">15</waittime>
    <testing type="boolean">false</testing>
    <clockmsg>You take your fob watch from your pocket, and look at it. It's ###.</clockmsg>
    <changedtime type="script">
      JS.eval("$('#clock').html('" + TimeAsString() + "');")
    </changedtime>
  </object>

  <function name="TimeAsString" type="string"><![CDATA[
    hours = game_clock.hours24 % 12
    if (hours = 0) {
      hours = 12
    }
    s = dayofWeek + ", " + monthofYear + " " + dayofMonth + " " + 12hourDay + ":" + minuteofHour
    if (game_clock.hours24 < 12) {
      return (s + " am")
    }
    else {
      return (s + " pm")
    }
  ]]></function>

  <function name="IncTime"><![CDATA[
    on ready {
    game_clock.minutes = game_clock.minutes + 1
      //msg("game_clock.time = " + game_clock.time)
      //msg("game_clock.event = " + game_clock.event)
    if (game_clock.minutes > 60) {
		game_clock.minutes = 0
		game_clock.hours = game_clock.hours24 + 1	  
		}
	else {
		game_clock.minutes = game_clock.minutes
		}
	if (game_clock.hours24 > 24) {
		game_clock.hours24 = 0
		game_clock.days = game_clock.days + 1
		game_clock.weeks = game_clock.weeks + 1
		}
	else {
		game_clock.hours24 = game_clock.hours24
		}
	if (game_clock.weeks > 7) {
		game_clock.weeks = 1
		}
	else {
		game_clock.weeks = game_clock.weeks
		}
	if (year % 4 = 0) {
		days_in_months = Split("31;29;31;30;31;30;31;31;30;31;30;31", ";")
		}
	else {
		days_in_months = Split("31;28;31;30;31;30;31;31;30;31;30;31", ";")
		}
	month = 0
	for (p, 0, 11) {
		days_in_month = ToInt(StringListItem(days_in_months, p))
		if (day > days_in_month) {
			month = month + 1
			day = day - days_in_month
			}
		else {
//intentionally left blank
			}
		}

      name = "event_" + DD(game_clock.days) + "_" + DD(game_clock.hours24) + "_" + DD(game_clock.minutes)
      game_clock.countdown = game_clock.countdown - 1
      //msg("Looking for: " + name)
      o = GetObject(name)
      if (not o = null and HasScript(o, "look")) {
        if (game_clock.testing) msg("Found: " + o + " (" + o.alias + ")")
        // this is used by wait
        game_clock.event = true
        do(o, "look")
      }
      else if (game_clock.countdown < 0 and HasAttribute(game_clock, "nextstep")) {
        if (game_clock.testing) msg("Step found: " + game_clock.nextstep + " (" + game_clock.nextstep.alias + ")")
        // this is used by wait
        game_clock.event = true
        step = game_clock.nextstep
        game_clock.nextstep = null
        do(step, "look")
      }
      game.clock = TimeAsString()
    }
  ]]></function>

No I'm not an experienced coder; more of a beginner if I was to rate myself in code at all. My understanding is purely from my understanding of logic systems. So if there are errors in what you see please let me know so I can squash the bugs now instead of later.

Also I was looking at the Functions List and didn't see a command to 'return nil'? What I'd like to do is use a Boolean function to check all these if/else statements and just run the conditions because they don't need an else. I'm not at that point yet in learning how to write that yet though. The way I have it works, but the other way is a lot cleaner.


hegemonkhan
15 Dec 2016, 07:38

quest does have the 'null' Value/Data~Atttribute type, Functions have to have a return type specified, but for whatever the data type for the return type you specify, you should be able to return the 'null' value for it.

http://docs.textadventures.co.uk/quest/types/null.html
^^^^^^^
http://docs.textadventures.co.uk/quest/types/


Morodin
15 Dec 2016, 14:42

Thanks! That solves one issue, now I can essentially put all the else parts to 'return null' to close them. Still would rather not use the if/else statements here but my brain can't seem to figure out a better method; but knows there should be one.


hegemonkhan
16 Dec 2016, 04:13

you can actually just not have the 'else' line/block too:

if (orc.dead) {
  msg ("The orc is dead")
}
// (implied else: obviously without an else, nothing / no action occurs when the 'if' condition fails, it just moves on to it's next script/action/game-play/whatever)

or you can leave the else's action/script blank:

if (orc.dead) {
  msg ("The orc is dead")
}
else {}

------

examples of more/different styles for the brackets/braces (you can do this for all bracing/brackets, so all of the styles below can be done for the 'if' line as well as any line of code using/needing braces/brackets. I'm not sure if quest requires new-lines or if it can all be done on one line, but this is never done, regardless, as it's unreadable by humans):

if (orc.dead) {
  msg ("The orc is dead")
}
else {
}

or

if (orc.dead)
{
  msg ("The orc is dead")
}
else
{
}

or

if (orc.dead)
{
  msg ("The orc is dead")
}
else
{}

------ VS -----------

if (orc.dead) {
  msg ("The orc is dead")
} else {
  msg ("The orc is alive")
}

Morodin
16 Dec 2016, 14:39

So you're saying I can do just

    if (game_clock.minutes > 60) {
		game_clock.minutes = 0
		game_clock.hours = game_clock.hours24 + 1	  
		}

... and just omit the else statement completely? That would be really nice for what I am doing here. I know some languages have problems with that though.


hegemonkhan
17 Dec 2016, 07:34

yep, exactly. the 'else' (and 'else if/s') condition(s) is(are) completely OPTIONAL:

either don't even code in the 'else' (if doing in code) or you jsut leave the 'else' condition's script-action, blank (don't add any script to/for it)


here's the 4 combinations of the 'if block' :

(negation/not can be applied of course, but I'm not including the negations/nots here as combinations)

1. an 'if' if block:

if (CONDITION) {
  // script/action
}

or, for example if doing strickly via the GUI/Editor (not technically an 'if' if block, but has the same effect as an 'if' if block):

if (CONDITION) {
  // script/action
} else {
  // (leave this blank --- don't add in any script/action here)
}

2. an 'if-else' if block:

if (CONDITION) {
  // script/action
} else {
  // script/action
}

3. an 'if-else if' if block:

if (CONDITION) {
  // script/action
} else if (CONDITION) {
  // script/action
}
// optionally: etc/more 'else ifs' as you want/need

4. an 'if-else if-else' if block:

if (CONDITION) {
  // script/action
} else if (CONDITION) {
  // script/action
}
// optionally: etc/more 'else ifs' as you want/need
else {
  // script/action
}

Morodin
20 Dec 2016, 21:03

Okay so I've gotten to a point where I wanted to test my work in quest and naturally I have errors. I'm kind of expecting this to have a lot of errors right now. This just was not the error I was expecting. This is what I'm getting and I have no idea as to why since this has been built within Pixie's clock framework. Any hints as to what's going on?

Failed to load game due to the following errors:
Error: Error adding type 'editor_object' to element 'game_clock': No element 'editor_object' of type 'ObjectType'

My guess is it's not liking this section of code:

  <object name="game_clock">
    <inherit name="editor_object" />
    <time type="int">0</time>
    <minutes type="int">0</minutes>
    <hours24 type="int">0</hours24>
    <days type="int">1</days>
	<week type="int">1</week>
	<month type="int">1</month>
	<year type="int">2000</year>
	<attr name="monthofYear" type="simplestringdictionary"> 1=January;2=February;3=March;4=April;5=May;6=June;7=July;8=August;9=September;10=October;11=November;12=December;</attr>
	<attr name="dayofWeek" type="simplestringdictionary">1=Sunday;2=Monday;3=Tuesday;4=Wednesday;5=Thursday;6=Friday;7=Saturday;</attr>
    <countdown type="int">0</countdown>
    <increment type="int">0</increment>
    <waittime type="int">15</waittime>
    <testing type="boolean">false</testing>
    <clockmsg>You take your fob watch from your pocket, and look at it. It's ###.</clockmsg>
    <changedtime type="script">
      JS.eval("$('#clock').html('" + TimeAsString() + "');")
    </changedtime>
  </object>

Specifically the <inherit name="editor_object" /> section of the code; but after looking at it and going through the website and Pixies original code. I can't see the reason why for the life of me this is popping up. When his original works just fine.


The Pixie
20 Dec 2016, 21:44

Sounds like you are missing the core library. In full code, the top four lines should look like this:

<!--Saved by Quest 5.6.6108.15891-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />

What do you see? Are you editing this outside of Quest?


Morodin
20 Dec 2016, 22:17

That was it! Thanks Pixie! I seriously have no idea how that happened. While I'm using notepad++ to edit the clocklib with it formatted to display XML as it's language. I've not touched the game I'm using to test it in. So somewhere between saves in the quest editor I must have accidentally deleted the core library and not noticed.

Now onto the actual getting this working part. I can write code for months, but it doesn't do me any good if I can't test it and make sure it works! .... - and it means probably another million and a half questions from me as I run into things I don't understand.


Morodin
08 Jan 2017, 22:54

Okay, I am being dumb again, must be the holiday eggnog. Either that or losing my 1 TB drive over the holidays addled me more than I thought. I'm going with the former; my eggnog hangovers aren't that bad. :-P This is what I'm getting:

Error running script: Error compiling expression 'currentWeekday + ", " + curentMonth + " " + dayofMonth + " " + 12hourDay + ":" + minuteofHour': Unknown object or variable 'currentWeekday'

Error running script: Error compiling expression 'toInt(StringListItem(dayofWeek, w))': Unknown object or variable 'dayofWeek'

The first comes up when I run the game the second appears when switching rooms. Is this because I've not fully converted Pixie's code over yet. Or did I actually code this wrong and miss something?


hegemonkhan
09 Jan 2017, 02:05

both are just coding errors (this is the majority of coding/programming: you're not coding... you're fixing up your mistakes, spelling mistakes or typos or accidental spaces from highlighting and copying or forgotten symbol/parenthesis/brace/bracket/etc, etc etc etc, lol), you just need to fix your code up.

from the looks of them, it's likely you just need to create those Attributes for whatever the Object (or they're Variables if done locally):

Unknown object or variable 'currentWeekday' --- you need to create a 'currentWeekday' (check spelling too - as you can have this in your code but it's got a different spelling/typo in it and/or also look for any accidental spaces from highlighting and copying too far... as these are the worst.. hardest to spot/find --- you must be a spelling nazi when coding! coding must have ZERO spelling/typo mistakes!) Attribute (or Variable if just doing locally in the script, but it's more likely it's to be an Attribute contained within some Object)

and the same with this:

Unknown object or variable 'dayofWeek'