123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- const daysOfMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
- //https://www.timeanddate.com/sun/russia/saint-peterburg
- const dayLengthMax = 1341;// The longest day has daylight of 18:51 and civil daylight of 3:30 which adds up to 22:21, which are 1341 minutes
- const dayLengthMin = 468; // The shortest day has daylight of 6:53 and civil daylight of 1:55 which adds up to 7:48, which are 468 minutes
- const seasons = [
- 'winter',
- 'winter',
- 'winter',
- 'spring',
- 'summer',
- 'summer',
- 'summer',
- 'summer',
- 'summer',
- 'autumn',
- 'winter',
- 'winter'
- ];
- const holidays = {
- winter : {
- start: [1,1],
- end: [1,15],
- school: true,
- work: false
- },
- spring : {
- start: [3,20],
- end: [3,26],
- school: true,
- work: false
- },
- summer : {
- start: [6,1],
- end: [8,31],
- school: true,
- work: false
- },
- autumn : {
- start: [11,4],
- end: [11,11],
- school: true,
- work: false
- },
- }
- /**
- * Only ever roll time forwards by increasing minutes. This is the only way skills, stats, etc. get updated.
- * Increasing day and hour only excute some function. Avoid if possible. These fields are for internatl use only.
- * Increasing month or year won't execute events.
- */
- class GameTime{
- _now = undefined;
- get minutes(){
- return this._now.getUTCMinutes();
- }
- set minutes(v:number){
- if(typeof v !== "number"){
- console.error("Time Increase by invalid value",v);
- return;
- }
- v = Math.ceil(v);
- let minutes = this._now.getUTCMinutes();
- let timeToAdd = v - minutes;
- if(timeToAdd == 0)
- return;
- this.execute_every_timeUpdate(timeToAdd);
- let currentMinutesIn15MinutesInterval = minutes % 15;
- let minutesToCompleteCurrent15MinutesInterval = 15 - currentMinutesIn15MinutesInterval;
- if(minutesToCompleteCurrent15MinutesInterval > timeToAdd){
- this._now.setUTCMinutes(minutes + timeToAdd);
- this.execute_every_timeUpdate_post();
- return;
- }
- let currentIterationTimeToAdd = minutesToCompleteCurrent15MinutesInterval;
- while(timeToAdd > 0){
- let timeToSet = this._now.getTime() + currentIterationTimeToAdd * 60000;
- this._now = new Date(timeToSet);
- if(timeToSet % 900000 == 0)
- this.execute_every_15_minutes();
- if(this.minutes == 0){
- this.execute_every_1_hour();
- if(this.hour == 0){
- this.execute_every_1_day();
- if(this.day == 1){
- this.execute_every_1_month();
- if(this.month == 1){
- this.execute_every_1_year();
- }
- }
- }
- }
- timeToAdd -= currentIterationTimeToAdd;
- currentIterationTimeToAdd = Math.min(15,timeToAdd);
- }
- //this._now.setUTCMinutes(minutes % 60);
- this.execute_every_timeUpdate_post();
- }
- get hour(){return this._now.getUTCHours();}
- set hour(v){
- const oneDay = 86400000;
- const now = this.now;
- let targetTime = new Date(now);
- targetTime.setUTCHours(v,0);
- let millisecondDifference = targetTime.getTime() - now.getTime();
- if(millisecondDifference < 0)
- millisecondDifference += 86400000;
- const minuteDifference = Math.floor(millisecondDifference / 60000);
- this.minutes += minuteDifference;
- }
- get seconds(){
- return 0;
- }
- _startDate = null;
- get startDate():Date{return this._startDate;}
- get year(){return this._now.getUTCFullYear();}
- set year(v){this._now.setUTCFullYear(v);}
- get month(){return this._now.getUTCMonth()+1;}
- /*set month(v){
- this._now.setUTCMonth(v-1);
- }*/
- get day(){return this._now.getUTCDate();}
- /*set day(v){
- let daysToAdd = v - this.day;
- let month = this.month;
- for(let i = 0; i < daysToAdd; i++){
- this._now.setUTCDate(this._now.getUTCDate()+1);
- if(this.month != month){
- this.execute_every_1_month();
- if(this.month == 1)
- this.execute_every_1_year();
- month = this.month;
- }
- }
- /*while(v > daysOfMonth[this.month + 1]){
- this.execute_every_1_month();
- v-= daysOfMonth[this.month + 1];
- this.month += 1;
- }
- this._now.setUTCDate(v);*/
- //}
- //
-
- /**
- * From 1 (Monday) to 7 (Sunday)
- * @readonly
- * @type {number}
- */
- get weekday(){
- return this._now.getUTCDay() || 7;
- }
- //Days since the game started. 1 is the first day.
- get daystart(){
- const oneDay = 86400000;
- return Math.floor(Math.abs((this.today.getTime() - this.startDate.getTime()) / oneDay)) + 1;
- }
- daystartNextAtNthOfMonth(n){
- const now = this.now;
- let nextDate = new Date(now);
- if(n <= now.getUTCDate())
- nextDate.setUTCMonth(now.getUTCMonth() + 1);
- nextDate.setUTCDate(n);
- const timeDifference = nextDate.getTime() - now.getTime();
- const daysDifference = Math.floor(timeDifference / 86400000);
- return daysDifference + this.daystart;
- }
- daystartNextAtWeekday(weekday){
- const currentWeekday = this.weekday;
- if(weekday > currentWeekday)
- return weekday - currentWeekday + this.daystart;
- return 7 + weekday - currentWeekday + this.daystart;
- }
-
- /**
- * @param {number} daystart
- * @returns {*}
- */
- daystartToDate(daystart){
- return new Date(this._startDate.getTime() + (daystart-1)*86400000);
- }
- // Years that have passed since the game started. Starts with 1 in the first year.
- get yearstart(){
- const today = this.today;
- const startDate = this.startDate;
- let startDateInCurrentYear = clone(startDate);
- startDateInCurrentYear.setUTCFullYear(today.getUTCFullYear());
- if(startDateInCurrentYear > today)
- //It's early in the year
- return today.getUTCFullYear() - startDate.getUTCFullYear();
- return today.getUTCFullYear() - startDate.getUTCFullYear() + 1;
- }
- initTime(yearOrDate,month=undefined,day=undefined,hour=undefined,minute=undefined){
- if(yearOrDate instanceof Date){
- this._startDate = clone(yearOrDate);
- this._now = clone(yearOrDate);
- this._startDate.setUTCHours(0,0,0,0);
- }
- else if(typeof yearOrDate == "number" &&
- typeof month == "number" &&
- typeof day == "number" &&
- typeof hour == "number" &&
- typeof minute == "number"){
- this._startDate = new Date(Date.UTC(yearOrDate,month-1,day));
- this._now = new Date(Date.UTC(yearOrDate,month-1,day,hour,minute));
- }else{
- console.error('Arguments for time.initDate not supported:',yearOrDate,month,day,hour,minute);
- }
- console.log("$time.initTime (startDate,now)",this._startDate,this._now);
- }
- get isNight(){
- const dayStage = this.dayStage;
- return !(dayStage >= 1 && dayStage <= 3);
- }
- get dayDistanceToMiddleOfYear(){
- let dayOfYear = this.dayOfYear;
- let distanceToMiddleOfYear = 0;
- if(dayOfYear >= 354)
- distanceToMiddleOfYear = 536 - dayOfYear; // 183 (half a year) + 353 (winter equinox) - current day
- else if(dayOfYear >= 171)
- distanceToMiddleOfYear = dayOfYear - 171;
- else
- distanceToMiddleOfYear = 171-dayOfYear;
- return distanceToMiddleOfYear;
- }
- get dayLength(){
- return (dayLengthMax-(dayLengthMax-dayLengthMin)*this.dayDistanceToMiddleOfYear/182);
- }
- get dayOfYear(){
- let days = 0;
- for(let i=0; i < this.month-1; i++){
- days += daysOfMonth[i];
- }
- days += this.day;
- return days;
- }
- get dawnDuskLength(){
- return 120;
- }
- get dayStage(){
- /*1 - dawn
- 2 - midday
- 3 - sunset
- 4 - the beginning of the night
- 5 - night
- 6 - the end of the night*/
- let minutesSinceMidnight = this.minutesSinceMidnight;
- let dayStages = this.dayStagesStartEnd;
- for (const [key, startEnd] of Object.entries(dayStages)) {
- if(startEnd[0] < startEnd[1]){
- if(minutesSinceMidnight >= startEnd[0] && minutesSinceMidnight < startEnd[1]){
- return parseInt(key);
- }
- }else{
- if(minutesSinceMidnight >= startEnd[0] || minutesSinceMidnight < startEnd[1]){
- return parseInt(key);
- }
- }
- }
- console.warn('dayStage calculation failed, returning default value');
- return 2;
- }
- // Return the start and end times of each stage of the current day in minutes since midnight
- get dayStagesStartEnd(){
- let DayLength = this.dayLength;
- let ddl = this.dawnDuskLength;
- let half_ddl = ddl/2;
- let sunZenithMinutes = this.sunZenithMinutes;
- let dawnStart = sunZenithMinutes - DayLength / 2;
- let dawnEnd = dawnStart + half_ddl;
- let earlyDawnStart = dawnStart - half_ddl;
- let earlyDawnEnd = dawnStart;
- let duskEnd = sunZenithMinutes + DayLength / 2;
- let duskStart = duskEnd - half_ddl;
- let lateDuskStart = duskEnd;
- let lateDuskEnd = lateDuskStart + half_ddl;
- let middayStart = dawnEnd;
- let middayEnd = duskStart;
- let nightStart = lateDuskEnd;
- let nightEnd = earlyDawnStart;
- return {
- "1": [dawnStart,dawnEnd],
- "2": [middayStart,middayEnd],
- "3": [duskStart,duskEnd],
- "4": [lateDuskStart,lateDuskEnd],
- "5": [nightStart,nightEnd],
- "6": [earlyDawnStart,earlyDawnEnd],
- };
- }
- get endTime(){
- return new Date(9999,11,31);
- }
- get isWinter(){
- return (seasons[this.month - 1] == 'winter');
- }
- get minutesSinceMidnight() {
- return this.hour * 60 + this.minutes;
- }
-
- /**
- * No need to clone this value.
- * @readonly
- * @type {Date}
- */
- get now():Date{
- return clone(this._now);
- }
-
- /**
- * Description placeholder
- * @date 10/3/2023 - 1:06:21 PM
- *
- * @param {number} offset
- * @returns {Date}
- */
- nowWithMinutesOffset(offset){
- let now = this.now;
- now.setUTCMinutes(now.getUTCMinutes() + offset);
- return now;
- }
- get tomorrow(){
- var tomorrow = this.now;
- tomorrow.setUTCDate(tomorrow.getUTCDate()+1);
- tomorrow.setUTCHours(0,0,0,0);
- return tomorrow;
- }
- secondsSinceDate(date){
- if(!(date instanceof Date))
- return Infinity;
- return Math.floor((this.now.getTime() - date.getTime()) / 1000);
- }
-
- /**
- * Returns whether a given Date is in the future.
- * @date 10/3/2023 - 1:10:48 PM
- *
- * @param {Date} date
- * @returns {boolean}
- */
- isFuture(date){
- try{
- return (this.secondsSinceDate(date) < 0);
- }catch(e){
- console.error("ERROR in $time.isFuture",date);
- return false;
- }
- }
- get today():Date{
- let now = clone(this.now);
- now.setUTCHours(0,0,0,0);
- return now;
- }
- dayOfIndex(index){
- let today = this.today;
- let currentIndex = this.daystart;
- let diff = index - currentIndex;
- today.setUTCDate(today.getUTCDate() + diff);
- return today;
- }
- dayWithOffset(offset){
- return this.dayOfIndex(this.daystart + offset);
- }
- time(hour,minute,flags={}){
- let currentTime = this.now;
- currentTime.setUTCHours(hour,minute);
- return currentTime;
- }
- //Minutes since midnight at which the sun is at his zenith
- //It's set to 13:00
- get sunZenithMinutes(){
- return 780;
- }
- get sunTime(){
- let CurTimeSun = this.hour*60 + this.minutes;
- //CurTimeSun (minuts) <0 - before midday; >0 - after midday
- CurTimeSun = CurTimeSun-this.sunZenithMinutes
- return CurTimeSun;
- }
- advanceTo(hour,minute,advanceToNextDay=false){
- let minuteDifference = (hour * 60 + minute) - (this.hour * 60 + this.minutes);
- if(minuteDifference > 0){
- this.minutes += minuteDifference;
- }else if(advanceToNextDay){
- this.minutes += 1440 + minuteDifference;
- }
- console.log("Time: advanceTo",hour,minute,advanceToNextDay,minuteDifference,this.now);
- }
- ageOfDate(dayOrDate:number|Date,month=undefined,year=undefined){
- let day = dayOrDate;
- if(dayOrDate instanceof Date){
- day = dayOrDate.getUTCDate();
- month=dayOrDate.getUTCMonth() + 1;
- year = dayOrDate.getUTCFullYear();
- }
- let yearDifference = this.year - year;
- if(month > this.month || (month == this.month && day > this.day))
- return yearDifference - 1;
- return yearDifference;
- }
- //29th Feb is not possible
- dateOfAge(age){
- let year = this.year - age;
- let randomMonth = rand(1,12);
- let randomDay = rand(1,daysOfMonth[randomMonth-1]);
- if(randomMonth > this.month || (randomMonth == this.month && randomDay > this.day))
- year -= 1;
- let date = new Date(Date.UTC(year,randomMonth-1,randomDay));
- console.log('Generated Date:',date);
- return date;
- }
- //Year -1: Current year, -2: Year with the next occurance of the date (either this our next)
- daysDifference(day,month,year=-1){
- const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
- let currentDate = this.today;
- let return_positive = false;
- if(year == -1)
- year = this.year;
- else if(year == -2){
- year = this.year;
- return_positive = true;
- }
- let testDate = new Date(Date.UTC(year, month, day));
- let diffDays = Math.round((testDate.getTime() - currentDate.getTime()) / oneDay);
- if(diffDays < 0 && return_positive)
- return this.daysDifference(day,month,this.year+1);
- return diffDays;
- }
- dayStartToDateArray(d){
- let currentDayStart = this.daystart;
- let dayStartDiff = d - currentDayStart;
- let currentDate = this.today;
- currentDate.setDate(currentDate.getDate() + dayStartDiff);
- return [currentDate.getDate(),currentDate.getMonth(),currentDate.getFullYear()];
- }
-
- /**
- * How many minutes is the time in the past. Negativ if it is in the future.
- * @date 9/10/2023 - 7:43:26 PM
- *
- * @param {number} hour
- * @param {number} minute
- * @returns {number}
- */
- timeDifference(hour,minute){
- return (this.hour - hour) * 60 + (this.minutes - minute);
- }
- // execute every n time-units
- execute_every_15_minutes(){
- console.log("Time: 15-Minutes-Tick",this.hour,this.minutes);
- State.variables.pc.execute_every_15_minutes();
- State.variables.wardrobe.execute_every_15_minutes();
- $.wiki(`<<include "stat_15minutes_changes">>`);
- }
- execute_every_1_hour(){
- console.log("Time: 1-Hour-Tick",this.hour,this.minutes);
- State.variables.pc.execute_every_1_hour();
- State.variables.wardrobe.execute_every_1_hour();
- $.wiki(`<<include "stat_hourly_changes">>`);
- }
- execute_every_1_day(){
- console.log("Time: 1-Day-Tick",this.daystart,this.hour,this.minutes);
- State.variables.pc.execute_every_1_day();
- State.variables.wardrobe.execute_every_1_day();
- State.variables.finances.execute_every_1_day();
- }
- execute_every_1_month(){
- console.log("Time: 1-Month-Tick",this.month,this.day,this.hour,this.minutes);
- }
- execute_every_1_year(){
- console.log("Time: 1-Year-Tick",this.year,this.month,this.day,this.hour,this.minutes);
- }
- execute_every_timeUpdate(timeToAdd){
- State.variables.pc.execute_every_timeUpdate(timeToAdd);
- }
- //executed whenever the time changes after everything else has been calculated
- execute_every_timeUpdate_post(){
- /*let missedEvents = this.getPastTimedEvents(undefined,true);
- for(let missedEventIndex in missedEvents){
- let missedEvent = missedEvents[missedEventIndex];
- switch(missedEvent.key){
- case 'date':
- $.wiki('<<datingMissed `'+JSON.stringify(missedEvent)+'`>>');
- break;
- case 'work':
- const jobs = State.variables.jobs;
- jobs.workMissed(missedEvent.data.jobId,missedEvent.endTime);
- default:
- if(missedEvent.data?.type){
- switch(missedEvent.data.type){
- case 'questEvent':
- let questId = missedEvent.data.questId;
- let eventId = missedEvent.data.eventId;
- let repeat = missedEvent.data.repeat;
- State.variables.q.eventExecute(questId,eventId);
- switch(repeat){
- case 'daily':
- this.rescheduleTimedEventByKey(missedEvent.key,'day',1);
- break;
- }
- break;
- }
- }
- }
- missedEvents[missedEventIndex].handled = true;
- }*/
- }
- get minutesTimestamp(){
- // Zero minutesTimestamp will be at New Years Eve of 2015
- //return this.minutesSince(2015,1,1,0,0);
- let yearDifference = this.year - 2015;
- let dayDifference = this.day - 1;
- let hourDifference = this.hour;
- let minutesDifference=this.minutes;
- let days = yearDifference * 365;
- for(let i=0 ; i < this.month - 1;i++){
- days += daysOfMonth[i];
- }
- days += dayDifference;
- let minutes = (days * 24 + hourDifference) * 60 + minutesDifference;
- return minutes;
- }
- // Output
- get dateTimeString(){
- if(!this._now)
- return '';
- let year = (''+this.year).padStart(4,'0');
- let month = (''+this.month).padStart(2,'0');
- let day = (''+this.day).padStart(2,'0');
- let hour = (''+this.hour).padStart(2,'0');
- let minutes = (''+this.minutes).padStart(2,'0');
- let date = day+'.'+month+'.'+year;
- let time = hour+':'+minutes;
- return date+' '+time;
- }
- // ----- special_events -----
- // Special Events are one day long, such has your graduation
- /*_specialEvents = [
- ]
- addEvent(key,day,month,year){
- this._specialEvents.push({
- key: key,
- day: day,
- month: month,
- year: year
- });
- }
- currentSpecialEvents(){
- let result = [];
- for(let specialEvent of this._specialEvents){
- if(specialEvent.day == this.day && specialEvent.month == this.month && specialEvent.year == this.year)
- result.push(specialEvent.key);
- }
- return result;
- }*/
- // ----- timed events -----
- // Timed events have a start date and time, duration and meta-informationen, such as a scheduled date
- _timedEvents:any = {_system:{nextId:0},events:{}}
- addTimedEvent(key,day,month,year,hour,minute,duration,data={}){
- let startTime = new Date(Date.UTC(year, month - 1, day, hour, minute, 0));
- return this.addTimedEventByDate(key,startTime,duration,data);
- }
- addTimedEventByDate(key,startTime,duration,data={}){
- let endTime = new Date(startTime.getTime() + duration*60000);
- let timedEvent = {
- key: key,
- startTime: startTime,
- endTime: endTime,
- duration : duration,
- data: data
- };
- let id = ''+this._timedEvents._system.nextId++;
- //this._timedEvents.push(timedEvents);
- this._timedEvents.events[id] = timedEvent;
- console.log('Timed event added',id,timedEvent);
- return id;
- }
- getCurrentTimedEvents(key=undefined){
- let result = [];
- let now = this.now;
- for(let timedEvent of Object.values(this._timedEvents.events)){
- if(key === undefined || timedEvent['key'] == key){
- if(now.getTime() >= timedEvent['startTime'].getTime() && now.getTime() <= timedEvent['endTime'].getTime())
- result.push(timedEvent);
- }
- }
- return result;
- }
- getPastTimedEvents(key=undefined,ignoreHandled = false){
- let result = [];
- let now = this.now;
- for(let timedEvent of Object.values(this._timedEvents.events)){
- if(ignoreHandled && timedEvent['handled'])
- continue;
- if(key === undefined || timedEvent['key'] == key){
- if(now.getTime() > timedEvent['endTime'].getTime())
- result.push(timedEvent);
- }
- }
- return result;
- }
- rescheduleTimedEventById(id,dateTime){
- if(!this._timedEvents.events[id])
- return false;
- const duration = this._timedEvents.events[id].duration;
- this._timedEvents.events[id].startTime = dateTime;
- this._timedEvents.events[id].endTime= new Date(dateTime.getTime() + duration*60000);
- return true;
- }
- rescheduleTimedEventByKey(key,offsetMode='day',offsetCount=1){
- for(let timedEvent of Object.values(this._timedEvents.events)){
- if(timedEvent['key'] == key){
- switch(offsetMode){
- case 'day':
- timedEvent['startTime'].setUTCDate(timedEvent['startTime'].getUTCDate() + offsetCount);
- timedEvent['endTime'].setUTCDate(timedEvent['endTime'].getUTCDate() + offsetCount);
- break;
- case 'month':
- timedEvent['startTime'].setUTCMonth(timedEvent['startTime'].getUTCMonth() + offsetCount);
- timedEvent['endTime'].setUTCMonth(timedEvent['endTime'].getUTCMonth() + offsetCount);
- break;
- case 'year':
- timedEvent['startTime'].setUTCFullYear(timedEvent['startTime'].getUTCFullYear() + offsetCount);
- timedEvent['endTime'].setUTCFullYear(timedEvent['endTime'].getUTCFullYear() + offsetCount);
- break;
- }
- }
- console.log("Timed event rescheduled:",timedEvent);
- }
- }
- unscheduleTimedEventsByKeyAndData(key,data){
- this._timedEvents = Object.values(this._timedEvents.events).filter((e)=>{
- if(e['key'] != key)
- return true;
- for (const [data_key, data_value] of Object.entries(data)) {
- if(data_value != e['data'][data_key])
- return true;
- }
- return false;
- });
- }
- unscheduleTimedEventById(id){
- return (delete this._timedEvents.events[id]);
- }
- // ----- holidays ----
- //Returns an array of the indizes of the current holidays
-
- currentHolidays(includeSchoolHolidays=true,includeWorkHolidays=true){
- return this.holidaysOfDate(this.now,includeSchoolHolidays,includeWorkHolidays);
- }
- holidaysOfDate(date,includeSchoolHolidays=true,includeWorkHolidays=true){
- date = new Date(date.getTime());
- date.setUTCHours(0,0,0,0);
- let h = holidays;
- let result = [];
- for (const [holiday_key, holiday_value] of Object.entries(h)) {
- let startDate = new Date(date.getTime());
- startDate.setUTCMonth(holiday_value.start[0]-1,holiday_value.start[1]);
- let endDate = new Date(date.getTime());
- endDate.setUTCMonth(holiday_value.end[0]-1,holiday_value.end[1]);
- if(date.getTime() >= startDate.getTime() && date.getTime() <= endDate.getTime()){
- if(
- (includeSchoolHolidays && holiday_value.school) ||
- (includeWorkHolidays && holiday_value.work)
- )
- result.push(holiday_key);
- }
- }
- return result;
- }
- daysOfHolidayLeft(holidayId){
- let holiday = holidays[holidayId];
- return this.daysDifference(holiday.end[1],holiday.end[0],-2) + 1; //+1 since the end of the holidays is counted as well
- }
- get isSchoolDay(){
- if(this.weekday >= 6)
- return false;
- return !this.isSchoolHoliday;
- }
- get isSchoolHoliday(){
- return this.dateIsSchoolHoliday(this.now);
- }
-
- /**
- * @param {Date} date
- * @returns {boolean}
- */
- dateIsSchoolHoliday(date){
- let holidayIds = this.holidaysOfDate(date);
- for(let holidayId of holidayIds){
- let holidayData = holidays[holidayId];
- if(holidayData.school)
- return true;
- }
- return false;
- }
-
- /**
- * Description placeholder
- * @param {string} condition
- * @param {Date|undefined} [dateTime=undefined]
- * @returns {boolean}
- */
- _timetableConditionMet(condition,dateTime=undefined){
- if(!condition)
- return true;
- dateTime ??= this.now;
- const weekDay = dateTime.getUTCDay();
- const isWeekend = (weekDay == 0 || weekDay == 6);
- switch(condition){
- case 'always': return true;
- case 'else': return false;
- case 'noSchoolHoliday': return !this.dateIsSchoolHoliday(dateTime);
- case 'schoolHoliday': return this.dateIsSchoolHoliday(dateTime);
- case 'weekday': return !isWeekend;
- case 'weekend': return isWeekend;
- }
-
- const todaysAbbrev = ['mo','tu','we','th','fr','sa','su'][weekDay];
- if(condition.indexOf(todaysAbbrev) == -1)
- return false;
- return true;
- }
- _timetableGetSchedules(timetable,dateTime=undefined){
- let todaysSchedules = [];
- dateTime ??= this.now;
- for(const [scheduleDay,daySchedules] of Object.entries(timetable)){
- if(!this._timetableConditionMet(scheduleDay))
- continue;
- if(Array.isArray(daySchedules))
- todaysSchedules = todaysSchedules.concat(daySchedules);
- else
- todaysSchedules = todaysSchedules.concat(this._timetableGetSchedules(daySchedules));
- }
-
- if(todaysSchedules.length == 0 && ('else' in timetable)){
- if(Array.isArray(timetable.else))
- todaysSchedules = timetable.else;
- else
- todaysSchedules = this._timetableGetSchedules(timetable.else);
- }
- todaysSchedules = todaysSchedules.filter(schedule => this._timetableConditionMet(schedule.condition));
- todaysSchedules.sort((a,b)=>(a.start[0]*100+a.start[1]) - (b.start[0]*100+b.start[1]));
- return todaysSchedules;
- }
- timetableLookup(timetable,dateTime=undefined){
- dateTime ??= this.now;
- const hour = dateTime.getUTCHours();
- const minute = dateTime.getUTCMinutes();
- const todaysSchedules = this._timetableGetSchedules(timetable,dateTime);
- let currentSchedule=undefined;
- let nextScheduleStart=undefined;
- for(const schedule of todaysSchedules){
- if(schedule.start[0] < hour || (schedule.start[0] == hour && schedule.start[1] <= minute)){
- currentSchedule = schedule;
- }else{
- nextScheduleStart = schedule.start;
- break;
- }
- }
- if(!nextScheduleStart)
- nextScheduleStart = [24,0];
- if("data" in currentSchedule)
- return {current: currentSchedule.data, nextStartTime: nextScheduleStart};
- if("either" in currentSchedule)
- return {current: currentSchedule.either.random(), nextStartTime: nextScheduleStart};
- return undefined;
- }
- _init(gameTime){
- Object.keys(gameTime).forEach(function (pn) {
- this[pn] = clone(gameTime[pn]);
- }, this);
- return this;
- }
- clone = function () {
- return (new setup.GameTime())._init(this);
- };
- toJSON = function () {
- var ownData = {};
- Object.keys(this).forEach(function (pn) {
- if(typeof this[pn] !== "function")
- ownData[pn] = clone(this[pn]);
- }, this);
- return JSON.reviveWrapper('(new setup.GameTime())._init($ReviveData$)', ownData);
- };
- }
- setup.GameTime = GameTime;
- setup.durationToString = function(duration){
- return Math.floor(duration/60).toString()+':'+(duration%60).toString().padStart(2, '0');
- }
- setup.weekDayIntToString ??= function(day:number){
- switch(day){
- case 1: return 'Monday';
- case 2: return 'Tuesday';
- case 3: return 'Wednesday';
- case 4: return 'Thursday';
- case 5: return 'Friday';
- case 6: return 'Saturday';
- case 7: return 'Sunday';
- default: return '???';}
- }
|