/*:
 * @target MZ
 * @plugindesc Background extendable time system with automatic weather change
 * and custom common event callbacks - 1.01.01
 * <pluginName:CycloneTime>
 * @author Hudell
 * @url https://makerdevs.com/plugin/cyclone-time
 *
 * @help
 * ===========================================================================
 *                                    88
 *                                    88
 *                                    88
 *   ,adPPYba, 8b       d8  ,adPPYba, 88  ,adPPYba,  8b,dPPYba,   ,adPPYba,
 *  a8"     "" `8b     d8' a8"     "" 88 a8"     "8a 88P'   `"8a a8P_____88
 *  8b          `8b   d8'  8b         88 8b       d8 88       88 8PP"""""""
 *  "8a,   ,aa   `8b,d8'   "8a,   ,aa 88 "8a,   ,a8" 88       88 "8b,   ,aa
 *   `"Ybbd8"'     Y88'     `"Ybbd8"' 88  `"YbbdP"'  88       88  `"Ybbd8"'
 *                 d8'
 *                d8'
 * Time and Weather System                                           by Hudell
 * ===========================================================================
 * Terms of Use
 * ===========================================================================
 * 1. For support, feature requests or bug reports, you may contact me through
 *  any of the following channels (in order of preference):
 *
 *   1.a. Opening an issue on the plugin's GitHub repository:
 *      https://github.com/Hudell/cyclone-engine
 *   1.b. Tagging me on threads on Rpg Maker related Forums, such as:
 *      rpgmakerweb.com (English)
 *      centrorpg.com (Portuguese)
 *      condadobraveheart.com (Portuguese)
 *   1.c. Opening threads on the plugin's itch.io page
 *   1.d. Tagging my user on Rpg Maker related sub-reddits, such as r/rpgmaker
 *
 * 2. Do not send me Direct Messages asking for support or bug reports.
 * You may only send me direct messages when none of the above platforms are
 * appropiate for it, or when you want to share pictures of cute dogs.
 *
 * 3. A special exception is created for patreon users who get access to my
 * priority support discord server.
 *
 * 4. Sending plugin related questions on channels related to any of my other
 * projects (such as my game's Discord server) may result in an immediate ban
 * from such platforms and I may also choose to ignore your future requests.
 *
 * 5. This plugin is released under the Apache License 2.0 (Apache-2.0).
 *
 * 6. You can send me your own changes to this plugin if you wish to see them
 * included in an update, by registering a Pull Request on the plugin's GitHub
 * repository.
 *
 * 7. This plugin is provided as is. While I'll often read feedback and offer
 * updates to my plugins, I am in no obligation to do so.
 *
 * 8. I'm not responsible for anything created with this plugin.
 * ===========================================================================
 * Did you know?
 * The portuguese word "Tempo" can mean both "Time" and "Weather".
 * ===========================================================================
 * Change Log
 * ===========================================================================
 * 2020-08-30 - Version 1.01.00
 *   * Removed Cyclone Core Dependency
 *
 *
 * 2020-08-19 - Version 1.00.00
 * ===========================================================================
 * @param Time System
 *
 * @param Initial Time
 * @parent Time System
 * @type struct<Time>
 * @default {"second":0,"minute":0,"hour":6,"day":1,"month":1,"year": 1}
 * @desc Set the date and time that the system should be set at on a new game
 *
 * @param Use real months
 * @parent Time System
 * @desc If enabled, the game will use the real world calendars with variable
 * month lengths, leap years and daylight saving time.
 * @default false
 * @type boolean
 *
 * @param Use real time
 * @parent Time System
 * @desc If enabled, the game will use the player's clock
 * @default false
 * @type boolean
 *
 * @param Time Speed
 * @parent Time System
 * @desc How many real time milliseconds should an ingame second last
 * @default 100
 * @type number
 *
 * @param Variable Time Speed
 * @parent Time System
 * @desc Load the length of the second from a variable instead of a fixed value
 * @default 0
 * @type variable
 *
 * @param Seconds in a minute
 * @parent Time System
 * @desc How many ingame seconds should an ingame minute last
 * @default 60
 * @type number
 *
 * @param Minutes in an hour
 * @parent Time System
 * @desc How many ingame minutes should an ingame hour last
 * @default 60
 * @type number
 *
 * @param Hours in a day
 * @parent Time System
 * @desc How many ingame hours should an ingame day last
 * @default 24
 * @type number
 *
 * @param Days in a week
 * @parent Time System
 * @desc How many ingame days should an ingame week last
 * @default 7
 * @type number
 *
 * @param Days in a month
 * @parent Time System
 * @desc How many ingame days should an ingame month last
 * @default 31
 * @type number
 *
 * @param Months in a year
 * @parent Time System
 * @desc How many ingame months should an ingame year last
 * @default 12
 * @type number
 *
 * @param First day ever
 * @parent Time System
 * @desc What day of the week was it on 01/01/0001 ? This is used to determine the week days (IRL it was a monday)
 * @type select
 * @default 1
 * @option Sunday
 * @value 0
 * @option Monday
 * @value 1
 * @option Tuesday
 * @value 2
 * @option Wednesday
 * @value 3
 * @option Thursday
 * @value 4
 * @option Friday
 * @value 5
 * @option Saturday
 * @value 6
 *
 * @param Pause during messages
 * @parent Time System
 * @desc If ON, it will stop the flow of time while messages are being displayed on screen.
 * @type boolean
 * @default true
 *
 * @param Day start time
 * @parent Time System
 * @desc At what time does a new day start
 * This may affect weather and other plugins that are based on this one.
 * @type number
 * @default 6
 *
 * @param Clock main switch
 * @parent Time System
 * @desc A switch that controls if the clock is ticking or not
 * @type switch
 * @default 0
 * @param Time Variables
 * @parent Time System
 * @type struct<TimeVariables>
 * @default
 * @desc Copy the time data to variables to use on events
 *
 * @param Clock pause switch
 * @parent Time System
 * @desc A switch that pauses the clock when turned on
 * @type switch
 * @default 0
 *
 * @param Clock pause tilesets
 * @parent Time System
 * @desc A list of map tilesets where the clock should be paused
 * @type tileset[]
 *
 * @param Weather System
 *
 * @param Weather pause switch
 * @parent Weather System
 * @desc A switch that pauses the weather when turned on
 * @type switch
 * @default 0
 *
 * @param Weather pause tilesets
 * @parent Weather System
 * @desc A list of map tilesets where the weather should be ignored
 * @type tileset[]
 *
 * @param Weather is paused switch
 * @parent Weather System
 * @desc A switch that will be turned on automatically every time the weather system is paused
 * @type switch
 *
 * @param Manual weather switch
 * @parent Weather System
 * @desc When this switch is turned on, the weather system will do nothing
 * @type switch
 * @default 0
 *
 * @param No special weather event
 * @parent Weather System
 * @type common_event
 * @desc The common event that should be triggered when there's no active weather effect
 *
 * @param Rain Effect
 * @parent Weather System
 * @type struct<WeatherEffect>
 * @desc The weather effect is not triggered automatically, you'll need to add a common event with a "Change Weather" command
 *
 * @param Storm Effect
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Snow Effect
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Custom Effect 1
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Custom Effect 2
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Custom Effect 3
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Custom Effect 4
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Custom Effect 5
 * @parent Weather System
 * @type struct<WeatherEffect>
 *
 * @param Current weather variable
 * @parent Weather System
 * @type variable
 * @default 0
 * @desc A variable that will be automatically updated with the code for the current weather
 * Manual changes to this variable will be ignored
 *
 * @param Before weather update
 * @parent Weather System
 * @type common_event
 * @default 0
 * @desc A common event to be executed every time the weather will be updated
 *
 * @param Formats
 *
 * @param Time format
 * @parent Formats
 * @default [hh]:[mm]
 * @desc The format of the time string: [h], [hh], [m], [mm], [s], [ss]. Use [h12] or [hh12] and [ampm] for 12hr clock
 *
 * @param Date format
 * @parent Formats
 * @default [y]-[mm]-[dd]
 * @desc The format of the date string. Accepts [y], [yy], [yyy], [yyyy], [mm], [m], [d], [dd]
 *
 * @param Callbacks
 *
 * @param Time Callbacks
 * @parent Callbacks
 * @type struct<TimeCallback>[]
 * @default
 * @desc Make the system trigger a common event on any specific time
 *
 * @param On change time
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the clock changes
 *
 * @param On change second
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the clock's seconds changes
 *
 * @param On change minute
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the clock's minutes changes
 *
 * @param On change hour
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the clock's hours changes
 *
 * @param On change day
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the date changes
 *
 * @param On change month
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the month changes
 *
 * @param On change year
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time the year changes
 *
 * @param On day start
 * @parent Callbacks
 * @type common_event
 * @default 0
 * @desc Trigger a common event every time a new day starts (as configured on the "day start time" param)
 **/
/*~struct~Time:
 * @param second
 * @type number
 * @default 0
 *
 * @param minute
 * @type number
 * @default 0
 *
 * @param hour
 * @type number
 * @default 6
 *
 * @param day
 * @type number
 * @default 1
 *
 * @param month
 * @type number
 * @default 1
 *
 * @param year
 * @type number
 * @default 1
 */
/*~struct~TimeVariables:
 * @param second
 * @type variable
 * @default 0
 * @desc a variable that will automatically update with the current second
 * Changing the value of this variable will change the clock's second
 *
 * @param minute
 * @type variable
 * @desc a variable that will automatically update with the current minute
 * Changing the value of this variable will change the clock's minute
 *
 * @param hour
 * @type variable
 * @desc a variable that will automatically update with the current hour
 * Changing the value of this variable will change the clock's hour
 *
 * @param hour12
 * @type variable
 * @default 0
 * @desc a variable that will receive the current hour in 12hr format
 * Manual changes to this variable will be ignored
 *
 * @param pm
 * @type switch
 * @default 0
 * @desc a switch that will be turned on after 12:00pm
 * Manual changes to this switch will be ignored
 *
 * @param day
 * @type variable
 * @default 0
 * @desc a variable that will automatically update with the current day
 * Changing the value of this variable will change the calendar's date
 *
 * @param weekDay
 * @type variable
 * @desc a variable that will automatically update with the current week day
 * Manual changes to this variable will be ignored
 *
 * @param month
 * @type variable
 * @default 0
 * @desc a variable that will automatically update with the current month
 * Changing the value of this variable will change the calendar's month
 *
 * @param year
 * @type variable
 * @default 0
 * @desc a variable that will automatically update with the current year
 * Changing the value of this variable will change the calendar's year
 *
 * @param dateString
 * @type variable
 * @default
 * @desc a variable that will automatically update with the current formatted date
 * Changing the value of this variable will change the calendar's year
 *
 * @param timeString
 * @type variable
 * @default
 * @desc a variable that will automatically update with the current formatted time
 * Changing the value of this variable will change the calendar's year
 *
 * @param isPaused
 * @type switch
 * @default
 * @desc a switch that will be turned on whenever the time system is paused
 *
 */
/*~struct~WeatherEffect:
 * @param enabled
 * @type boolean
 * @default false
 * @desc Should this weather effect be enabled?
 *
 * @param commonEvent
 * @type common_event
 * @default 0
 * @desc What common even should be triggered when the weather changes to this?
 *
 * @param chance
 * @type number
 * @default 20
 * @desc What should be the chance of this weather happening? (0-100)
 *
 * @param monthList
 * @type number[]
 * @default []
 * @desc Add any month number to this list to make this weather only occur on them.
 *
 * @param extraParams
 * @type struct<Dictionary>[]
 * @desc Add extra params to this weather effect, to be used by other plugins
 */
/*~struct~TimeCallback:
 * @param type
 * @type select
 * @default hour
 * @option Hour
 * @value hour
 * @option Minute
 * @value minute
 * @option Day
 * @value day
 * @option Week Day
 * @value weekDay
 * @option Month
 * @value month
 * @option Year
 * @value year
 * @option Second
 * @value second
 * @desc What kind of value are you adding a callback to?
 *
 * @param value
 * @type number
 * @desc The value that you want to attach an event to
 *
 * @param event
 * @type common_event
 * @desc The common event that will be triggered when the specificed is met
 */
/*~struct~Dictionary:
 * @param name
 * @type string
 * @desc The name of the custom parameter
 *
 * @param value
 * @type string
 * @desc The value of the custom parameter
 */

(function () {
'use strict';

globalThis.CyclonePatcher=class{static initialize(t){this.pluginName=t,this.superClasses=new Map;}static _descriptorIsProperty(t){return t.get||t.set||!t.value||"function"!=typeof t.value}static _getAllClassDescriptors(t,e=!1){if(t===Object)return {};const r=Object.getOwnPropertyDescriptors(e?t.prototype:t);let s={};if(t.prototype){const r=Object.getPrototypeOf(t.prototype).constructor;r!==Object&&(s=this._getAllClassDescriptors(r,e));}return Object.assign({},s,r)}static _assignDescriptor(t,e,r,s,a=!1){if(this._descriptorIsProperty(r))r.get||r.set?Object.defineProperty(t,s,{get:r.get,set:r.set,enumerable:r.enumerable,configurable:r.configurable}):Object.defineProperty(t,s,{value:r.value,enumerable:r.enumerable,configurable:r.configurable});else {let r=s;if(a)for(;r in t;)r=`_${r}`;t[r]=e[s];}}static _applyPatch(t,e,r,s,a=!1){const n=this._getAllClassDescriptors(t,a),i=a?t.prototype:t,o=a?e.prototype:e,l=Object.getOwnPropertyDescriptors(o);let u=!1;for(const t in l){if(s.includes(t))continue;if(t in n){u=!0;const e=n[t];this._assignDescriptor(r,i,e,t,!0);}const e=l[t];this._assignDescriptor(i,o,e,t);}return u}static patchClass(t,e){const r=this.superClasses&&this.superClasses[t.name]||{},s={},a={},n=e(a,s);if("function"!=typeof n)throw new Error(`Invalid class patch for ${t.name}`);const i=Object.getOwnPropertyNames(class{}),o=Object.getOwnPropertyNames(class{}.prototype),l=this._applyPatch(t,n,r,i),u=this._applyPatch(t,n,s,o,!0);if(l){const t=Object.getOwnPropertyDescriptors(r);for(const e in t)this._assignDescriptor(a,r,t[e],e);u&&(a.$prototype=s);}else Object.assign(a,s);this.superClasses&&(this.superClasses[t.name]=a);}};const t=Object.freeze(["TRUE","ON","1","YES","T","V"]);class e extends CyclonePatcher{static initialize(t){super.initialize(t),this.fileName=void 0,this.params={},this.structs=new Map,this.eventListeners=new Map,this.structs.set("Dictionary",{name:{type:"string",defaultValue:""},value:{type:"string",defaultValue:""}});}static register(t={}){const e=this.loadAllParams();this.params=this.loadParamMap(t,e);}static loadAllParams(){for(const t of globalThis.$plugins){if(!t||!t.status)continue;if(!t.description||!t.description.includes(`<pluginName:${this.pluginName}`))continue;this.fileName=t.name;const e=new Map;for(const r in t.parameters)r&&!r.startsWith("-")&&e.set(r,t.parameters[r]);return e}}static loadParamMap(t,e){const r={};for(const s in t)if(t.hasOwnProperty(s))try{r[s]=this.parseParam(s,t,e);}catch(t){console.error(`CycloneEngine crashed while trying to parse a parameter value (${s}). Please report the following error to Hudell:`),console.log(t);}return r}static registerEvent(t,e){this.eventListeners.has(t)||this.eventListeners.set(t,new Set);this.eventListeners.get(t).add(e);}static removeEventListener(t,e){if(!this.eventListeners.has(t))return;this.eventListeners.get(t).delete(e);}static shouldReturnCallbackResult(t,{abortOnTrue:e,abortOnFalse:r,returnOnValue:s}){return !(!1!==t||!r)||(!(!0!==t||!e)||!(void 0===t||!s))}static runEvent(t,{abortOnTrue:e=!1,abortOnFalse:r=!1,returnOnValue:s=!1}={},...a){if(!this.eventListeners.has(t))return;const n=this.eventListeners.get(t);for(const t of n){if("number"==typeof t){this.runCommonEvent(t);continue}if("function"!=typeof t){console.error("CycloneEngine: Invalid callback type:"),console.log(t);continue}const n=t(...a);if(this.shouldReturnCallbackResult(n,{abortOnTrue:e,abortOnFalse:r,returnOnValue:s}))return n}}static runCommonEvent(t){const e=globalThis.$dataCommonEvents[t];if(!e)return;const r=new Game_Interpreter(1);if(r.setup(e.list,0),!this._interpreters){this._interpreters=new Set;const t=SceneManager.updateMain;SceneManager.updateMain=()=>{t.call(SceneManager),this.update();};}this._interpreters.add(r);}static update(){if(this._interpreters)for(const t of this._interpreters)t.update(),t.isRunning()||this._interpreters.delete(t);}static getPluginFileName(){return this.fileName??this.pluginName}static isTrue(e){return "string"!=typeof e?Boolean(e):t.includes(e.toUpperCase())}static isFalse(t){return !this.isTrue(t)}static getIntParam({value:t,defaultValue:e}){try{const r=parseInt(t);return isNaN(r)?e:r}catch(r){return ""!==t&&console.error(`Cyclone Engine plugin ${this.pluginName}: Param is expected to be an integer number, but the received value was '${t}'.`),e}}static getFloatParam({value:t,defaultValue:e}){try{const r=parseFloat(t.replace(",","."));return isNaN(r)?e:r}catch(r){return ""!==t&&console.error(`Cyclone Engine plugin ${this.pluginName}: Param is expected to be a number, but the received value was '${t}'.`),e}}static getIntListParam({value:t}){return this.parseArray((t??"").trim(),(t=>{try{return parseInt(t.trim())}catch(e){return ""!==t&&console.error(`Cyclone Engine plugin ${this.pluginName}: Param is expected to be a list of integer numbers, but one of the items was '${t}'.`),0}}))}static parseStructArrayParam({data:t,type:e}){const r=[];for(const s of t){const t=this.parseStructParam({value:s,defaultValue:"",type:e});t&&r.push(t);}return r}static getFloatListParam({value:t}){return this.parseArray((t||"").trim(),(t=>{try{return parseFloat(t.trim())}catch(e){return ""!==t&&console.error(`Cyclone Engine plugin ${this.pluginName}: Param ${name} is expected to be a list of numbers, but one of the items was '${t}'.`),0}}))}static getParam({value:t,defaultValue:e,type:r}){if(r.endsWith("[]"))return this.parseArrayParam({value:t,type:r});if(r.startsWith("struct<"))return this.parseStructParam({value:t,defaultValue:e,type:r});if(void 0===t)return e;switch(r){case"int":return this.getIntParam({value:t,defaultValue:e});case"float":return this.getFloatParam({value:t,defaultValue:e});case"boolean":return "boolean"==typeof t?t:this.isTrue(String(t).trim());default:return t}}static getPluginParam(t){return this.params.get(t)}static defaultValueForType(t){switch(t){case"int":return 0;case"boolean":return !1}return ""}static parseParam(t,e,r){let s=e[t];s&&"string"==typeof s&&(s={type:s,defaultValue:this.defaultValueForType(s)});const{name:a=t,type:n="string",defaultValue:i=""}=s;let o;if(r)o=r.get(a)??i;else {o=(this.getPluginParam(a)||{}).value??i;}return this.getParam({value:o,defaultValue:i,type:n})}static parseArrayParam({value:t,type:e}){const r=this.parseArray(t);if(!r||!r.length)return r;const s=e.substr(0,e.length-2),a=[];for(const t of r){const e=this.defaultValueForType(s);a.push(this.getParam({value:t,type:s,defaultValue:e}));}return a}static getRegexMatch(t,e,r){const s=t.match(e);if(s)return s[r]}static parseStructParam({value:t,defaultValue:e,type:r}){let s;if(t)try{s=JSON.parse(t);}catch(e){console.error("Cyclone Engine failed to parse param structure: ",t),console.error(e);}s||(s=JSON.parse(e));const a=this.getRegexMatch(r,/struct<(.*)>/i,1);if(!a)return console.error(`Unknown plugin param type: ${r}`),s;const n=this.structs.get(a);if(!n)return console.error(`Unknown param structure type: ${a}`),s;for(const t in n){if(!n.hasOwnProperty(t))continue;let e=n[t];"string"==typeof e&&(e={type:e,defaultValue:this.defaultValueForType(e)}),s[t]=this.getParam({value:s[t],defaultValue:e.defaultValue,type:e.type});}return s}static parseList(t,e){let r=t;r.startsWith("[")&&(r=r.substr(1)),r.endsWith("]")&&(r=r.substr(0,r.length-1));const s=r.split(",");return e?s.map((t=>e(t))):s}static parseArray(t,e){let r;try{r=JSON.parse(t);}catch(t){return []}return r&&r.length?e?r.map((t=>e(t))):r:[]}static registerCommand(t,e,r){return "function"==typeof e?PluginManager.registerCommand(this.getPluginFileName(),t,e):PluginManager.registerCommand(this.getPluginFileName(),t,(t=>{const s=new Map;for(const e in t)t.hasOwnProperty(e)&&s.set(e,t[e]);const a=this.loadParamMap(e,s);return Object.assign(t,a),r(t)}))}}globalThis.CyclonePlugin=e;

const cycloneWeatherTypes = Object.freeze(['none', 'rain', 'storm', 'snow', 'custom1', 'custom2', 'custom3', 'custom4', 'custom5']);

class CycloneTime$1 extends CyclonePlugin {
  static register() {
    this.initialize('CycloneTime');

    this.structs.set('CycloneTime', {
      second: {
        type: 'int',
        defaultValue: 0,
      },
      minute: {
        type: 'int',
        defaultValue: 0,
      },
      hour: {
        type: 'int',
        defaultValue: 0,
      },
      day: {
        type: 'int',
        defaultValue: 1,
      },
      month: {
        type: 'int',
        defaultValue: 1,
      },
      year: {
        type: 'int',
        defaultValue: 1,
      },
    });

    this.structs.set('CycloneTimeVariables', {
      second: {
        type: 'int',
        defaultValue: 0,
      },
      minute: {
        type: 'int',
        defaultValue: 0,
      },
      hour: {
        type: 'int',
        defaultValue: 0,
      },
      hour12: {
        type: 'int',
        defaultValue: 0,
      },
      day: {
        type: 'int',
        defaultValue: 0,
      },
      pm: {
        type: 'int',
        defaultValue: 0,
      },
      weekDay: {
        type: 'int',
        defaultValue: 0,
      },
      month: {
        type: 'int',
        defaultValue: 0,
      },
      year: {
        type: 'int',
        defaultValue: 0,
      },
      dateString: {
        type: 'int',
        defaultValue: 0,
      },
      timeString: {
        type: 'int',
        defaultValue: 0,
      },
      isPaused: {
        type: 'int',
        defaultValue: 0
      }
    });

    this.structs.set('CycloneWeatherSetting', {
      enabled: {
        type: 'boolean',
        defaultValue: false,
      },
      commonEvent: {
        type: 'int',
        defaultValue: 0,
      },
      chance: {
        type: 'int',
        defaultValue: 20,
      },
      monthList: {
        type: 'int[]',
        defaultValue: '[]',
      },
      extraParams: {
        type: 'struct<Dictionary>[]',
        defaultValue: '{}',
      },
    });

    this.structs.set('TimeCallback', {
      type: {
        type: 'string',
        defaultValue: '',
      },
      value: {
        type: 'int',
        defaultValue: NaN,
      },
      event: {
        type: 'int',
        defaultValue: 0,
      },
    });

    super.register({
      initialTime: {
        name: 'Initial Time',
        type: 'struct<CycloneTime>',
        defaultValue: '{"second":0,"minute":0,"hour":6,"day":1,"month":1,"year": 1}',
      },
      weekDayOffset: {
        name: 'First day ever',
        type: 'int',
        defaultValue: 1,
      },
      pauseDuringMessages: {
        name: 'Pause during messages',
        type: 'boolean',
        defaultValue: true,
      },
      minuteLength: {
        name: 'Seconds in a minute',
        type: 'int',
        defaultValue: 60,
      },
      hourLength: {
        name: 'Minutes in an hour',
        type: 'int',
        defaultValue: 60,
      },
      dayLength: {
        name: 'Hours in a day',
        type: 'int',
        defaultValue: 24,
      },
      weekLength: {
        name: 'Days in a week',
        type: 'int',
        defaultValue: 7,
      },
      monthLength: {
        name: 'Days in a month',
        type: 'int',
        defaultValue: 31,
      },
      yearLength: {
        name: 'Months in a year',
        type: 'int',
        defaultValue: 12,
      },
      secondLength: {
        name: 'Time Speed',
        type: 'int',
        defaultValue: 100,
      },
      secondLengthVariable: {
        name: 'Variable Time Speed',
        type: 'int',
        defaultValue: 0,
      },
      useRealMonths: {
        name: 'Use real months',
        type: 'boolean',
        defaultValue: false,
      },
      useRealTime: {
        name: 'Use real time',
        type: 'boolean',
        defaultValue: false,
      },
      mainSwitchId: {
        name: 'Clock main switch',
        type: 'int',
        defaultValue: 0,
      },
      pauseSwitchId: {
        name: 'Clock pause switch',
        type: 'int',
        defaultValue: 0,
      },
      tilesetList: {
        name: 'Clock pause tilesets',
        type: 'int[]',
        defaultValue: '[]'
      },
      variables: {
        name: 'Time Variables',
        type: 'struct<CycloneTimeVariables>',
        defaultValue: '{"second":0,"minute":0,"hour":0,"day":0,"month":0,"year":0,"pm":0,"weekDay":0}',
      },
      dayStartTime: {
        name: 'Day start time',
        type: 'int',
        defaultValue: 6,
      },
      weatherSwitchId: {
        name: 'Weather pause switch',
        type: 'int',
        defaultValue: 0,
      },
      manualWeatherSwitchId: {
        name: 'Manual weather switch',
        type: 'int',
        defaultValue: 0,
      },
      weatherTilesetList: {
        name: 'Weather pause tilesets',
        type: 'int[]',
        defaultValue: '[]'
      },
      weatherIsPausedSwitchId: {
        name: 'Weather is paused switch',
        type: 'int',
        defaultValue: 0,
      },
      sunEventId: {
        name: 'No special weather event',
        type: 'int',
        defaultValue: 0,
      },
      rain: {
        name: 'Rain Effect',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      storm: {
        name: 'Storm Effect',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      snow: {
        name: 'Snow Effect',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      custom1: {
        name: 'Custom Effect 1',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      custom2: {
        name: 'Custom Effect 2',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      custom3: {
        name: 'Custom Effect 3',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      custom4: {
        name: 'Custom Effect 4',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      custom5: {
        name: 'Custom Effect 5',
        type: 'struct<CycloneWeatherSetting>',
        defaultValue: '{}',
      },
      currentWeatherVariable: {
        name: 'Current weather variable',
        type: 'int',
        defaultValue: 0,
      },
      beforeWeatherEvent: {
        name: 'Before weather update',
        type: 'int',
        defaultValue: 0,
      },
      timeCallbacks: {
        name: 'Time Callbacks',
        type: 'struct<TimeCallback>[]',
        defaultValue: '[]',
      },
      timeFormat: {
        name: 'Time format',
        type: 'string',
        defaultValue: '[hh]:[mm]'
      },
      dateFormat: {
        name: 'Date format',
        type: 'string',
        defaultValue: '[y]-[mm]-[dd]'
      },
      onChangeTime: {
        name: 'On change time',
        type: 'int',
        defaultValue: 0,
      },
      onChangeSecond: {
        name: 'On change second',
        type: 'int',
        defaultValue: 0,
      },
      onChangeMinute: {
        name: 'On change minute',
        type: 'int',
        defaultValue: 0,
      },
      onChangeHour: {
        name: 'On change hour',
        type: 'int',
        defaultValue: 0,
      },
      onChangeDay: {
        name: 'On change day',
        type: 'int',
        defaultValue: 0,
      },
      onChangeMonth: {
        name: 'On change month',
        type: 'int',
        defaultValue: 0,
      },
      onChangeYear: {
        name: 'On change year',
        type: 'int',
        defaultValue: 0,
      },
      onDayStart: {
        name: 'On day start',
        type: 'int',
        defaultValue: 0,
      },
    });

    this.time = 0;
    this.recalculate();
    this.assignCallbacks();
  }

  static get second() { return this._second; }
  static set second(value) { this._second = value; }
  static get minute() { return this._minute; }
  static set minute(value) { this._minute = value; }
  static get hour() { return this._hour; }
  static set hour(value) { this._hour = value; }
  static get day() { return this._day; }
  static set day(value) { this._day = value; }
  static get month() { return this._month; }
  static set month(value) { this._month = value; }
  static get year() { return this._year; }
  static set year(value) { this._year = value; }
  static get weekDay() { return this._weekDay; }
  static set weekDay(value) { this._weekDay = value; }
  static get previousWeather() { return this._previousWeather; }
  static get currentWeather() { return this._currentWeather; }
  static set currentWeather(value) {
    this._previousWeather = this._currentWeather;
    this._currentWeather = value;
    this.updateWeather();
  }

  static get timeString() {
    return this.getTimeString();
  }

  static get dateString() {
    return this.getDateString();
  }

  static get hour12() {
    const hour = this.hour % 12;
    if (hour === 0) {
      return 12;
    }
    return hour;
  }
  static get amPm() {
    if (this.hour < 12) {
      return 'am';
    }

    return 'pm';
  }

  static get yearLength() {
    if (this.useRealMonths) {
      return 12;
    }
    return this.params.yearLength ?? 12;
  }

  static get monthLength() {
    if (this.useRealMonths) {
      return 31;
    }
    return this.params.monthLength ?? 31;
  }

  static get dayLength() {
    if (this.useRealMonths) {
      return 24;
    }
    return this.params.dayLength ?? 24;
  }

  static get hourLength() {
    if (this.useRealMonths) {
      return 60;
    }
    return this.params.hourLength ?? 60;
  }

  static get minuteLength() {
    if (this.useRealMonths) {
      return 60;
    }
    return this.params.minuteLength ?? 60;
  }

  static get secondLength() {
    if (this.useRealTime) {
      return 1000;
    }

    if (this.params.secondLengthVariable) {
      return $gameVariables.value(this.params.secondLengthVariable);
    }
    return this.params.secondLength ?? 100;
  }

  static get useRealTime() {
    return this.params.useRealTime;
  }

  static get useRealMonths() {
    if (this.useRealTime) {
      return true;
    }

    return this.params.useRealMonths;
  }

  static get stopped() {
    const mainSwitchId = this.params.mainSwitchId ?? 0;
    if (mainSwitchId) {
      if ($gameSwitches === undefined || $gameSwitches === null) {
        return true;
      }

      return !$gameSwitches.value(mainSwitchId);
    }

    return this._stopped === true;
  }

  static set stopped(value) {
    const mainSwitchId = this.params.mainSwitchId ?? 0;
    if (mainSwitchId) {
      $gameSwitches.setValue(mainSwitchId, !value);
      return;
    }

    this._stopped = value;
  }

  static get paused() {
    if (SceneManager._scene instanceof Scene_Map) {
      const tilesets = this.params.tilesetList || [];
      if (tilesets.length && tilesets.includes($dataMap.tilesetId)) {
        return true;
      }
    }

    if (this.params.pauseSwitchId) {
      if ($gameSwitches.value(this.params.pauseSwitchId)) {
        return true;
      }
    }

    return false;
  }

  static get manualWeather() {
    const manualWeather = this.params.manualWeatherSwitchId;
    if (manualWeather) {
      return $gameSwitches.value(manualWeather);
    }

    return false;
  }

  static get weatherPaused() {
    if (SceneManager._scene instanceof Scene_Map) {
      const tilesets = this.params.weatherTilesetList || [];
      if (tilesets.length && tilesets.includes($dataMap.tilesetId)) {
        return true;
      }
    }

    if (this.params.weatherSwitchId) {
      if ($gameSwitches.value(this.params.weatherSwitchId)) {
        return true;
      }
    }

    return false;
  }

  static get pausedInternally() {
    if (!$dataMap) {
      return true;
    }

    if ($gamePlayer.isTransferring()) {
      return true;
    }

    if (SceneManager._scene instanceof Scene_Map) {
      if (this.shouldPauseDuringMessages && $gameMessage.isBusy()) {
        return true;
      }
    }

    return false;
  }

  static get shouldPauseDuringMessages() {
    return this.params.pauseDuringMessages;
  }

  static get currentData() {
    return {
      second: this.second,
      minute: this.minute,
      hour: this.hour,
      day: this.day,
      month: this.month,
      year: this.year,
      weekDay: this.weekDay,
      stopped: this.stopped,
    };
  }

  static get tomorrow() {
    return this.getDayAfterDate(this.currentData);
  }

  static loadInitialTime() {
    if (!this.params.initialTime) {
      return;
    }

    this.setTime(this.convertObjectToNumber({
      second: this.params.initialTime.second ?? 0,
      minute: this.params.initialTime.minute ?? 0,
      hour: this.params.initialTime.hour ?? 6,
      day: this.params.initialTime.day ?? 1,
      month: this.params.initialTime.month ?? 1,
      year: this.params.initialTime.year ?? 1,
    }));
  }

  static getDayBeforeDate(data) {
    data.hour = 0;
    data.minute = 0;
    data.second = 0;
    data.day -= 1;

    if (data.day === 0) {
      data.month -= 1;
      data.day = this.monthLength;

      if (data.month === 0) {
        data.year -= 1;
        data.month = this.yearLength;
      }
    }
    const time = this.convertObjectToNumber(data);
    return this.convertNumberToObject(time);
  }

  static getDayAfterDate(data) {
    data.hour = 0;
    data.minute = 0;
    data.second = 0;
    data.day += 1;
    const time = this.convertObjectToNumber(data);
    return this.convertNumberToObject(time);
  }

  static getDateString() {
    const { day, month, year } = this;
    let format = this.params.dateFormat || '[y]-[mm]-[dd]';

    return format
      .replace('[yyyy]', year.padZero(4))
      .replace('[yyy]', year.padZero(3))
      .replace('[yy]', year.padZero(2))
      .replace('[y]', year)
      .replace('[mm]', month.padZero(2))
      .replace('[m]', month)
      .replace('[dd]', day.padZero(2))
      .replace('[d]', day);
  }

  static getTimeString() {
    const { hour, hour12, minute, second, amPm } = this;
    const format = this.params.timeFormat || '[hh]:[mm]';

    return format
      .replace('[hh]', hour.padZero(2))
      .replace('[h]', hour)
      .replace('[hh12]', hour12.padZero(2))
      .replace('[h12]', hour12)
      .replace('[mm]', minute.padZero(2))
      .replace('[m]', minute)
      .replace('[ss]', second.padZero(2))
      .replace('[s]', second)
      .replace('[ampm]', amPm);
  }

  static assignCallbacks() {
    const timeCallbacks = this.params.timeCallbacks;
    if (!timeCallbacks || !timeCallbacks.length) {
      return;
    }

    for (const callback of timeCallbacks) {
      if (!callback || !callback.type || !callback.event || isNaN(Number(callback.value))) {
        continue;
      }

      const eventName = `${ callback.type }:${ callback.value}`;
      this.registerEvent(eventName, callback.event);
    }
  }

  static runTimeChangeEvents(oldData) {
    let changedTime = false;

    const check = (oldValue, newValue, callback) => {
      if (oldValue !== newValue) {
        changedTime = true;
        callback.call(this);
      }
    };

    check(oldData.second, this.second, this.onChangeSecond);
    check(oldData.minute, this.minute, this.onChangeMinute);
    check(oldData.hour, this.hour, this.onChangeHour);
    check(oldData.day, this.day, this.onChangeDay);
    check(oldData.month, this.month, this.onChangeMonth);
    check(oldData.year, this.year, this.onChangeYear);

    if (this.checkIfStartedNewDay(oldData)) {
      this.onStartDay();
    }

    if (changedTime) {
      this.onChangeTime();
    }
  }

  static checkIfStartedNewDay(oldData) {
    const dayStartTime = this.params.dayStartTime ?? 0;

    const dayStartSeconds = dayStartTime * this.hourLength * this.minuteLength;
    const effectiveTime = this.time - dayStartSeconds;
    const oldEffectiveTime = this.convertObjectToNumber(oldData) - dayStartSeconds;

    const newDay = this.convertNumberToObject(effectiveTime).day;
    const oldDay = this.convertNumberToObject(oldEffectiveTime).day;
    return newDay !== oldDay;
  }

  static convertObjectToNumber(dateTime) {
    const months = ((dateTime.year ?? 1) -1) * this.yearLength + (dateTime.month ?? 1) - 1;
    const days = months * this.monthLength + (dateTime.day ?? 1) - 1;
    const hours = days * this.dayLength + (dateTime.hour ?? 0);
    const minutes = hours * this.hourLength + (dateTime.minute ?? 0);
    return minutes * this.minuteLength + (dateTime.second ?? 0);
  }

  static convertNumberToObject(time) {
    let remainingTime = time;
    const secondsPerHour = this.minuteLength * this.hourLength;
    const secondsPerDay = secondsPerHour * this.dayLength;
    const secondsPerMonth = secondsPerDay * this.monthLength;
    const secondsPerYear = secondsPerMonth * this.yearLength;

    const year = Math.floor(remainingTime / secondsPerYear);
    remainingTime -= year * secondsPerYear;
    const month = Math.floor(remainingTime / secondsPerMonth);
    remainingTime -= month * secondsPerMonth;
    const day = Math.floor(remainingTime / secondsPerDay);
    remainingTime -= day * secondsPerDay;
    const hour = Math.floor(remainingTime / secondsPerHour);
    remainingTime -= hour * secondsPerHour;
    const minute = Math.floor(remainingTime / this.minuteLength);
    remainingTime -= minute * this.minuteLength;
    const second = remainingTime;

    return {
      second,
      minute,
      hour,
      day: day + 1,
      month: month + 1,
      year: year + 1
    };
  }

  static recalculate() {
    const data = this.convertNumberToObject(this.time);

    this._second = data.second;
    this._minute = data.minute;
    this._hour = data.hour;
    this._day = data.day;
    this._month = data.month;
    this._year = data.year;
    this._weekDay = data.weekDay;

    this.updateVariables();
  }

  static updateVariables() {
    if (this.time === 0) {
      return;
    }

    const update = (variableId, value) => {
      if (variableId && $gameVariables) {
        $gameVariables._data[variableId] = value;
      }
    };

    const variables = this.params.variables;
    update(variables.second, this.second);
    update(variables.minute, this.minute);
    update(variables.hour, this.hour);
    update(variables.hour12, this.hour12);
    update(variables.day, this.day);
    update(variables.month, this.month);
    update(variables.year, this.year);
    update(variables.timeString, this.timeString);
    update(variables.dateString, this.dateString);

    if ($gameSwitches) {
      if (variables.pm) {
        $gameSwitches._data[variables.pm] = this.amPm === 'pm';
      }

      if (variables.isPaused) {
        $gameSwitches._data[variables.isPaused] = this.pausedInternally || this.paused;
      }
    }

    $gameMap.requestRefresh();
  }

  static updateTime(runEvents = true) {
    const oldData = this.currentData;

    if (this.useRealMonths && !this.useRealTime) {
      this.applyRealTimeLogic();
    }

    this.recalculate();

    if (runEvents) {
      this.runTimeChangeEvents(oldData);
    }
  }

  static applyRealTimeLogic() {
    const date = new Date();
    const obj = this.convertNumberToObject(this.time);

    date.setDate(1);

    date.setFullYear(obj.year);
    date.setMonth(obj.month - 1);
    date.setDate(obj.day);
    date.setHours(obj.hour);
    date.setMinutes(obj.minute);
    date.setSeconds(obj.second);

    this.setTime(this.convertObjectToNumber(this.convertJSDateToObject(date)));
  }

  static convertJSDateToObject(date) {
    return {
      second: date.getSeconds(),
      minute: date.getMinutes(),
      hour: date.getHours(),
      day: date.getDate(),
      month: date.getMonth() + 1,
      year: date.getFullYear(),
      weekDay: date.getDay(),
    };
  }

  static loadRealTime() {
    this.setTime(this.convertObjectToNumber(this.convertJSDateToObject(new Date())));
    this.updateTime();
  }

  static setTime(newTime) {
    const oldData = this.currentData;

    if (typeof newTime === 'object') {
      this.time = this.convertObjectToNumber(newTime);
    } else {
      this.time = newTime;
    }

    this.updateTime(false);
    this.runTimeChangeEvents(oldData);
  }

  static addSeconds(number) {
    this.time += number;
    this.updateTime(true);
  }

  static addMinutes(number) {
    this.addSeconds(number * this.minuteLength);
  }

  static addHours(number) {
    this.addMinutes(number * this.hourLength);
  }

  static addDays(number) {
    this.addHours(number * this.dayLength);
  }

  static addMonths(number) {
    this.addDays(number * this.monthLength);
  }

  static addYears(number) {
    this.addMonths(number * this.yearLength);
  }

  static passTime({seconds = 0, minutes = 0, hours = 0, days = 0, months = 0, years = 0}) {
    const monthsToAdd = years * this.yearLength + months;
    const daysToAdd = monthsToAdd * this.monthLength + days;
    const hoursToAdd = daysToAdd * this.dayLength + hours;
    const minutesToAdd = hoursToAdd * this.hourLength + minutes;

    this.addSeconds(minutesToAdd * this.minuteLength + seconds);
  }

  static progressTime(increment = 1) {
    if (this.stopped || this.pausedInternally || this.paused) {
      const pausedId = this.params.variables && this.params.variables.isPaused;
      if (pausedId) {
        $gameSwitches.setValue(pausedId, true);
      }
      return;
    }

    if (this.useRealTime) {
      this.loadRealTime();
    } else if (SceneManager._scene instanceof Scene_Map) {
      this.addSeconds(increment);
    }
  }

  static maybeRunParamCommonEvent(paramName) {
    const eventId = this.params[paramName];

    if (eventId) {
      this.runCommonEvent(eventId);
    }
  }

  static onChangeSecond() {
    this.runEvent('changeSecond');
    this.runEvent(`second:${ this.second }`);

    this.maybeRunParamCommonEvent('onChangeSecond');
  }

  static onChangeMinute() {
    this.runEvent('changeMinute');
    this.runEvent(`minute:${ this.minute }`);

    this.maybeRunParamCommonEvent('onChangeMinute');
  }

  static onChangeHour() {
    this.runEvent('changeHour');
    this.runEvent(`hour:${ this.hour }`);
    this.runEvent(`time:${ this.hour }:${ this.minute }`);
    this.runEvent(`fullTime:${ this.hour }:${ this.minute }:${ this.second }`);

    this.maybeRunParamCommonEvent('onChangeHour');
  }

  static onStartDay() {
    this.runEvent('startDay');

    this.skipToNextWeather();
    this.maybeRunParamCommonEvent('onDayStart');
  }

  static onChangeDay() {
    this.runEvent('changeDay');
    this.runEvent(`day:${ this.day }`);

    this.maybeRunParamCommonEvent('onChangeDay');
  }

  static onChangeMonth() {
    this.runEvent('changeMonth');
    this.runEvent(`month:${ this.month }`);

    this.maybeRunParamCommonEvent('onChangeMonth');
  }

  static onChangeYear() {
    this.runEvent('changeYear');
    this.runEvent(`year:${ this.year }`);

    this.maybeRunParamCommonEvent('onChangeYear');
  }

  static onChangeTime() {
    this.runEvent('changeTime');

    this.maybeRunParamCommonEvent('onChangeTime');
  }

  static setSecond(value) {
    const data = this.currentData;
    data.second = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static setMinute(value) {
    const data = this.currentData;
    data.minute = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static setHour(value) {
    const data = this.currentData;
    data.hour = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static setDay(value) {
    const data = this.currentData;
    data.day = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static setMonth(value) {
    const data = this.currentData;
    data.month = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static setYear(value) {
    const data = this.currentData;
    data.year = value;

    this.setTime(this.convertObjectToNumber(data));
  }

  static enableTime() {
    if (this._intervalHandler !== undefined) {
      return;
    }

    let length = this.secondLength;
    let increment = 1;
    if (length < 10) {
      const multiplier = Math.ceil(10 / length);
      increment *= multiplier;
      length *= multiplier;
    }

    this._intervalHandler = setInterval(() => {
      this.progressTime(increment);
    }, length);
  }

  static isEnabled() {
    return this._intervalHandler !== undefined;
  }

  static disableTime() {
    if (this._intervalHandler === undefined) {
      return;
    }

    clearInterval(this._intervalHandler);
    this._intervalHandler = undefined;
  }

  static refreshTimeSystem() {
    this.disableTime();
    this.enableTime();
  }

  static usingVariables() {
    const { second, minute, hour, hour12, day, month, year, weekDay } = this.params.variables;
    return second || minute || hour || hour12 || day || month || year || weekDay;
  }

  static isWeatherAvailable(weatherSettings, dateObj) {
    if (!weatherSettings.enabled) {
      return false;
    }

    if (weatherSettings.monthList && weatherSettings.monthListh.length && !weatherSettings.monthListh.includes(dateObj.month)) {
      return false;
    }

    return true;
  }

  static pickRandomWeather(dateTime) {
    const data = typeof dateTime === 'number' ? this.convertNumberToObject(dateTime) : dateTime;
    const availableWeatherTypes = [];

    const allWeathers = [
      { id: 'rain', ...this.params.rain },
      { id: 'storm', ...this.params.storm },
      { id: 'snow', ...this.params.snow },
      { id: 'custom1', ...this.params.custom1 },
      { id: 'custom2', ...this.params.custom2 },
      { id: 'custom3', ...this.params.custom3 },
      { id: 'custom4', ...this.params.custom4 },
      { id: 'custom5', ...this.params.custom5 },
    ];

    for (const weatherSettings of allWeathers) {
      if (this.isWeatherAvailable(weatherSettings, data)) {
        availableWeatherTypes.push(weatherSettings);
      }
    }

    if (!availableWeatherTypes.length) {
      return 'none';
    }

    const maxNumber = availableWeatherTypes.length * 100;
    const randomNumber = Math.randomInt(maxNumber);
    const weatherIndex = Math.floor(randomNumber / 100);
    const chance = randomNumber - weatherIndex * 100;

    const weather = availableWeatherTypes[weatherIndex];
    if (weather.chance > chance) {
      return weather.id;
    }

    return 'none';
  }

  static skipDay() {
    const dayStartTime = this.params.dayStartTime ?? 0;
    const data = this.currentData;
    if (data.hour >= dayStartTime) {
      data.day += 1;
    }

    data.hour = dayStartTime;
    data.minute = 0;
    data.second = 0;

    this.setTime(this.convertObjectToNumber(data));
  }

  static skipToNextWeather() {
    this.currentWeather = this.pickRandomWeather(this.currentData);
  }

  static updateWeatherVariable() {
    const currentWeatherVariable = this.params.currentWeatherVariable;
    if (currentWeatherVariable) {
      const idx = cycloneWeatherTypes.indexOf(this.currentWeather).clamp(0, cycloneWeatherTypes.length -1);
      $gameVariables.setValue(currentWeatherVariable, idx);
    }

    const weatherIsPausedSwitchId = this.params.weatherIsPausedSwitchId;
    if (weatherIsPausedSwitchId) {
      $gameSwitches.setValue(weatherIsPausedSwitchId, this.weatherPaused);
    }
  }

  static updateWeather() {
    const weatherIsPausedSwitchId = this.params.weatherIsPausedSwitchId;
    if (weatherIsPausedSwitchId) {
      $gameSwitches.setValue(weatherIsPausedSwitchId, this.weatherPaused);
    }

    const beforeWeatherEvent = this.params.beforeWeatherEvent;
    if (beforeWeatherEvent) {
      this.runCommonEvent(beforeWeatherEvent);
    }

    if (this.manualWeather) {
      return;
    }

    this.updateWeatherVariable();

    const settings = this.params[this.currentWeather];
    let eventId = this.params.sunEventId;
    if (settings && !this.weatherPaused) {
      eventId = settings.commonEvent ?? eventId;
    }

    if (eventId) {
      this.runCommonEvent(eventId);
    }
  }

  static getData() {
    return {
      time: this.time,
      weather: this.currentWeather,
    };
  }

  static setData(data) {
    if (data.time) {
      this.time = data.time;
      this.recalculate();
    } else {
      this.loadInitialTime();
    }

    this._previousWeather = 'none';
    if (data.weather) {
      this._currentWeather = data.weather;
    } else {
      this._currentWeather = 'none';
    }
  }
}

globalThis.CycloneTime = CycloneTime$1;
CycloneTime$1.register();

CycloneTime.patchClass(DataManager, $super => class {
  static makeSaveContents() {
    const contents = $super.makeSaveContents.call(this);
    contents.cycloneTime = CycloneTime.getData();

    return contents;
  }

  static extractSaveContents(contents) {
    $super.extractSaveContents.call(this, contents);

    if (contents.cycloneTime !== undefined) {
      CycloneTime.setData(contents.cycloneTime);
    }
  }

  static setupNewGame() {
    $super.setupNewGame.call(this);
    CycloneTime.disableTime();
    CycloneTime.loadInitialTime();
    CycloneTime.enableTime();
  }
});

CycloneTime.patchClass(Game_Map, $super => class {
  setup(...args) {
    $super.setup.call(this, ...args);
    CycloneTime.updateWeather();
    CycloneTime.updateVariables();
  }
});

CycloneTime.patchClass(Game_Player, $super => class {
  performTransfer(...args) {
    $super.performTransfer.call(this, ...args);
    CycloneTime.updateWeather();
    CycloneTime.updateVariables();
  }
});

if (CycloneTime.usingVariables()) {
  CycloneTime.patchClass(Game_Variables, $super => class {
    setValue(variableId, value) {
      $super.setValue.call(this, variableId, value);

      switch (variableId) {
        case CycloneTime.params.variables.second:
          return CycloneTime.setSecond(value);
        case CycloneTime.params.variables.minute:
          return CycloneTime.setMinute(value);
        case CycloneTime.params.variables.hour:
          return CycloneTime.setHour(value);
        case CycloneTime.params.variables.day:
          return CycloneTime.setDay(value);
        case CycloneTime.params.variables.month:
          return CycloneTime.setMonth(value);
        case CycloneTime.params.variables.year:
          return CycloneTime.setYear(value);
      }
    }
  });
}
})();