//=================================================================================================
// Date_System.js
//=================================================================================================
/*:
* @target MZ
* @plugindesc 时间&日期&日历 <2022-4-11>
* @author 芯☆淡茹水
* @help
*〓 功能说明 〓
*
*1,  日期的基本功能，年月日小时分钟，自动流逝，暂停，继续，改变自动流速，推进，倒退，设定，跳转。
*
*2， 日期的定位比对功能，定位记忆一个当前日期，以便日期推进以后与这个定位的日期
*     进行比对推进了多少。
*
*3， 日期的年月日小时可各自绑定一个公共事件，当对应的值发生变更时，自动运行
*     这个绑定的公共事件。
*
*4， 日期显示内容窗口（时钟，日期，时间，节日，星期，，）自设定。
*
*5,  日历展示。
*
*
*〓 插件命令 〓
*
*1,  命令功能：更改日期自动流逝速度。
*     对应脚本：$gameDate.changeSpeed(speed); <speed:帧数值>
*     用途说明：日期以游戏刷新帧为基础，以多少帧为日期的一分钟来
*               进行日期的自动流逝。
*               初始默认的自动流逝速度为 60 帧。
*
*2,  命令功能：日期开始自动流逝。
*     对应脚本：$gameDate.run();
*     注意事项：日期初始是 暂停自动流逝 的，正式开始游戏时需要
*               用这条插件命令让其开始自动流逝。
*
*3,  命令功能：日期暂停自动流逝。
*     对应脚本：$gameDate.stop();
*
*4,  命令功能：定位并记忆当前日期(个数无限制)。
*     对应脚本：$gameDate.location(name);  <name:定位的名称>
*     用途说明：定位并记忆当前日期，以作为以后时间推进了多少的
*               比对所用，或者用于日期跳转。
*               例如，定位一个名为 每日礼物 的当前日期，在事件里
*               可以用 条件 > 脚本：$gameDate.passedDays('每日礼物') >= 1;
*               来判断时间推进后是否过去了 1天 ，来领取礼物。
*               成功领取礼物后，再次使用该命令对这个 每日礼物 的定位点
*               覆盖定位为当前日期，以便下次领取礼物的判断。
*               详见 〓 脚本判断 〓 。
*     注意事项：若取的定位名称与已有的某个定位名称相同，将会覆盖掉
*               同名的定位的日期，变成当前日期。
*
*
*5,  命令功能：将当前日期跳转到某个定位的日期。
*     对应脚本：$gameDate.skipTo(name);  <name:定位的名称>
*     注意事项：若指定的定位(name)不存在，该命令无效。
*
*6,  命令功能：清除所有的日期定位。
*     对应脚本：$gameDate.clearLocationData(); 
*
*7,  命令功能：日期往前推进。
*     对应脚本：$gameDate.pass(index, num);  <index:日期类型索引> <num:推进值>   
*
*8,  命令功能：日期往后倒退。
*     对应脚本：$gameDate.fallBack(index, num);  <index:日期类型索引> <num:倒退值> 
*
*9,  命令功能：日期指定。
*     对应脚本：$gameDate.appoint(index, num);  <index:日期类型索引> <num:指定值>
*
*10, 命令功能：打开日历场景。
*     对应脚本：SceneManager.push(Scene_Calendar);
*
*
*〓 日期类型索引 〓
*     
*    年：0； 月：1； 日：2； 时：3； 分：4； 时段序号：5 。
*
*
*〓 控制符 〓
*
*对话框文本，新增以日期为基础的控制符。
*
*1,  文本插入当前年数：   \D_YEAR
*
*2,  文本插入当前月数：   \D_MONTH
*
*3,  文本插入当前天数：   \D_DAY
*
*4,  文本插入当前小时数： \D_HOUR
*
*5,  文本插入当前日期：   \D_DATE
*
*6,  文本插入当前时间：   \D_TIME
*
*7,  文本插入当前节日名： \D_FTV
*
*8,  文本插入当前时段名： \D_ITV
*
*
*〓 脚本判断 〓
*
*1,  所有设置关联的公共事件全部运行一遍:  DateManager.callAllCommonEvents();
*     日期系统在其日期时间发生变动时，才自动运行设置关联的公共事件，初始不会运行。
*     此条脚本适用于初始开始游戏时，公共事件内设置有比如依照日期的小时数来改变画
*     面色调的昼夜效果。
*
*2,  日期的当前年数: $gameDate.year;
*     值的范围: 1 ~ 无穷
*
*3,  日期的当前月数: $gameDate.month;
*     值的范围: 1 ~ 12
*
*4,  日期的当前天数: $gameDate.day;
*     值的范围: 1 ~ 当月最大天数
*
*5,  日期的当前小时数: $gameDate.hour;
*     值的范围: 0 ~ 23  (0 为夜间12点)
*
*6,  日期的当前分钟数: $gameDate.minute;
*     值的范围: 0 ~ 59
*
*7,  日期的当前星期数: $gameDate.week;
*     值的范围: 0 ~ 6  (0 为星期日)
*
*8,  日期的当前季节索引: $gameDate.seasonIndex();
*     值的范围: 0 ~ 3  (0:春季；1:夏季；2:秋季；3:冬季)
*
*9,  判断某个定位是否存在: $gameDate.hasLocation(name);
*     name: 定位的名称。
*
*10, 判断当前日期是否有节日: $gameDate.isFestival();
*
*11, 当前日期的节日名: $gameDate.festivalName();
*     当前不是节日时为空字符串。
*
*12, 当前日期的时段序号: $gameDate.intervalIndex();
*     当前未处在某个时段时值为 0。
*     时段序号为该插件参数设置里编辑的时段列表序号 (1, 2, 3, 4...)  
*
*13, 判断当前日期是否是节日: 条件 > 脚本: $gameDate.isFestival();
*      
*14, 以某个定位日期为起点，当前日期推进的年数: $gameDate.passedYears(name);
*     name: 定位的名称。
*     若代入的定位(name)不存在，值为 0 。
*     若在定位后使用了日期倒退功能，值可能为负值 。
*     以下几条皆适用。
*
*15, 以某个定位日期为起点，当前日期推进的月数: $gameDate.passedMonths(name);
*
*16, 以某个定位日期为起点，当前日期推进的天数: $gameDate.passedDays(name);
*
*17, 以某个定位日期为起点，当前日期推进的小时数: $gameDate.passedHours(name);
*
*
* @param 〓 常规设置 〓
* @default
*
* @param global
* @parent 〓 常规设置 〓
* @type boolean
* @text 全域刷新
* @desc 日期是否全域刷新流逝。
* 选择关闭时仅在地图界面刷新流逝。
* @default false
*
* @param style12
* @parent 〓 常规设置 〓
* @type boolean
* @text 12小时制显示
* @desc 是否12小时制显示。
* @default false
*
* @param touchTpt
* @parent 〓 常规设置 〓
* @type boolean
* @text 角色接触半透明
* @desc 角色接触任意日期窗口是否半透明。
* @default true
*
* @param rememberCalendar
* @parent 〓 常规设置 〓
* @type boolean
* @text 日历是否记住
* @desc 开启时，每次打开日历将会显示最后一次退出时的日期页面。
* 关闭时，每次打开日历将会显示当前日期页面。
* @default false
*
* @param intervals
* @parent 〓 常规设置 〓
* @type struct<interval>[]
* @text 时段列表
* @desc 添加时间段。前面的默认序号(1,2,3...)为当前日期的时段序号
* 若设置的时段之间有时间上的重合，将显示靠前设置的时段。
* @default []
*
* @param festivals
* @parent 〓 常规设置 〓
* @type struct<festival>[]
* @text 节日列表
* @desc 添加节日。
* @default []
*
* @param weekWords
* @parent 〓 常规设置 〓
* @type string[]
* @text 星期的列表
* @desc 编辑 7 个星期的用语, 第一个为 星期一 。
* @default ["星期一","星期二","星期三","星期四","星期五","星期六","星期日"]
*
*
* @param 〓 控制设置 〓
* @default
*
* @param mainSwitch
* @parent 〓 控制设置 〓
* @type switch
* @text 总开关
* @desc 控制日期功能的总开关，包括日期流逝，地图日期窗口与日历界面。
* 不设置开关默认为开启。
* @default 0
*
* @param mapSwitch
* @parent 〓 控制设置 〓
* @type switch
* @text 地图日期显示开关
* @desc 控制地图上日期显示与否的开关。
* 不设置开关默认为开启。
* @default 0
*
* @param menuSwitch
* @parent 〓 控制设置 〓
* @type switch
* @text 菜单日历选项开关
* @desc 控制菜单是否有日历选项的开关。
* 不设置开关默认为开启。
* @default 0
*
*
* @param 〓 初始设置 〓
* @default
*
* @param initialYears
* @parent 〓 初始设置 〓
* @type number
* @min 1
* @text 初始年数
* @desc 初始年数(最小 1)。
* @default 1
*
* @param initialMonths
* @parent 〓 初始设置 〓
* @type number
* @min 1
* @max 12
* @text 初始月数
* @desc 初始月数(1 ~ 12)。
* @default 1
*
* @param initialDays
* @parent 〓 初始设置 〓
* @type number
* @min 1
* @max 31
* @text 初始天数
* @desc 初始天数(1 ~ 31)。
* 自动修正实际月份最大天数。
* @default 1
*
* @param initialHours
* @parent 〓 初始设置 〓
* @type number
* @min 0
* @max 23
* @text 初始小时数
* @desc 初始小时数(0 ~ 23)。
* 0 为夜里 12点，也是天数交替的时刻。
* @default 0
* 
*
* @param 〓 公共事件设置 〓
* @default
*
* @param yearEvent
* @parent 〓 公共事件设置 〓
* @type common_event
* @text 年份公共事件
* @desc 日期年份发生变更时，自动运行的公共事件。
* @default 0
*
* @param monthEvent
* @parent 〓 公共事件设置 〓
* @type common_event
* @text 月份公共事件
* @desc 日期月份发生变更时，自动运行的公共事件。
* @default 0
*
* @param dayEvent
* @parent 〓 公共事件设置 〓
* @type common_event
* @text 天数公共事件
* @desc 日期天数发生变更时，自动运行的公共事件。
* @default 0
*
* @param hourEvent
* @parent 〓 公共事件设置 〓
* @type common_event
* @text 小时数公共事件
* @desc 日期小时数发生变更时，自动运行的公共事件。
* @default 0
*
* @param intervalEvent
* @parent 〓 公共事件设置 〓
* @type common_event
* @text 时段公共事件
* @desc 时段序号发生变更时，自动运行的公共事件。
* @default 0
*
*
* @param 〓 窗口设置 〓
* @default
* @param 〓 季节设置 〓
* @parent 〓 窗口设置 〓
* @default
*
* @param seasonImgs
* @parent 〓 季节设置 〓
* @type file[]
* @dir img/pictures/
* @text 季节图片列表
* @desc 选择4张季节图片，1 2 3 4 对应 春 夏 秋 冬 。
* 将其他窗口背景透明，该图片也可当作其他所有窗口的背景。
* @default
*
* @param seasonPoint
* @parent 〓 季节设置 〓
* @text 季节图片坐标
* @desc 季节图片位置坐标，格式： x,y 。
* @default 0,0
*
* @param 〓 时钟窗口 〓
* @parent 〓 窗口设置 〓
* @default
*
* @param clockWindow
* @parent 〓 时钟窗口 〓
* @type struct<window>
* @text 基本设置
* @desc 该窗口的UI图片请选择时钟的圆底盘图片。
* 图片在制图时，时钟圆图像的中心请置于整个图片中心。
* @default
*
* @param hourHand
* @parent 〓 时钟窗口 〓
* @type file
* @dir img/pictures/
* @text 时针图片
* @desc 选择时针图片。
* 图像需要指针向上。
* @default
*
* @param hourAxis
* @parent 〓 时钟窗口 〓
* @text 时针转动中心
* @desc 转动中心的图片位置坐标，格式: x,y 。
* 时针会依照这个设置的中心为圆心转动。
* @default 0,0
*
* @param minuteHand
* @parent 〓 时钟窗口 〓
* @type file
* @dir img/pictures/
* @text 分针图片
* @desc 选择分针图片。
* 图像需要指针向上。
* @default
*
* @param minuteAxis
* @parent 〓 时钟窗口 〓
* @text 分针转动中心
* @desc 转动中心的图片位置坐标，格式: x,y 。
* 分针会依照这个设置的中心为圆心转动。
* @default 0,0
*
* @param dateWindow
* @parent 〓 窗口设置 〓
* @type struct<window>
* @text 日期窗口
* @desc 日期窗口设置。
* @default
*
* @param timeWindow
* @parent 〓 窗口设置 〓
* @type struct<window>
* @text 时间窗口
* @desc 时间窗口设置。
* @default
*
* @param weekWindow
* @parent 〓 窗口设置 〓
* @type struct<window>
* @text 星期窗口
* @desc 星期窗口设置。
* @default
*
* @param festivalWindow
* @parent 〓 窗口设置 〓
* @type struct<window>
* @text 节日窗口
* @desc 节日窗口设置。
* 该窗口在当前不是节日时会隐藏。
* @default
*
* @param calendarTitle
* @parent 〓 窗口设置 〓
* @type file
* @dir img/pictures/
* @text 日历标题窗口UI
* @desc 选择日历标题窗口UI图片。
* (日历界面里的上面那个窗口)
* @default
*
* @param calendarInfo
* @parent 〓 窗口设置 〓
* @type file
* @dir img/pictures/
* @text 日历信息窗口UI
* @desc 选择日历天数列表窗口UI图片。
* (日历界面里的下面那个窗口)
* @default
*
* @param calendarCud
* @parent 〓 窗口设置 〓
* @type file
* @dir img/pictures/
* @text 日历当天标志图片
* @desc 日历天数列表窗口显示的天数是当天的标注图片。
* @default
*
*
* @param 〓 颜色设置 〓
* @default
*
* @param fntColor
* @parent 〓 颜色设置 〓
* @type number
* @text 节日文字色
* @desc 日历窗口里描绘节日文字的颜色色号。
* @default 2
*
*
* @param 〓 用语设置 〓
* @default
*
* @param wordYear
* @parent 〓 用语设置 〓
* @text 年的用语
* @desc 年的用语。
* @default 年
*
* @param wordMonth
* @parent 〓 用语设置 〓
* @text 月的用语
* @desc 月的用语。
* @default 月
*
* @param calendar
* @parent 〓 用语设置 〓
* @text 日历用语
* @desc 日历的用语。
* @default 日历
*
* @param formatDate
* @parent 〓 用语设置 〓
* @text 日期格式
* @desc %y:年数值； %m:月数值; %d:日数值。
* @default %y年 - %m月 - %d日
*
* @param formatTime
* @parent 〓 用语设置 〓
* @text 时间格式
* @desc %h:小时数值； %n:分钟数值。
* @default %h : %n
*
*
* @command ChangeDateSpeed
* @text 更改速度
* @desc 更改日期自动流逝的速度。
* 流逝速度以游戏刷新帧为基础，xx帧为一分钟。
*
* @arg speed
* @text 速度
* @desc 指定流逝的速度，多少帧为一分钟。
* @default 60
*
*
* @command DateRun
* @text 日期运行
* @desc 日期开始自动流逝。
*
*
* @command DateStop
* @text 日期停止
* @desc 日期暂停自动流逝。
* 
*
* @command DateLocation
* @text 日期定位
* @desc 定位并记忆当前日期，以作为以后日期流逝量的比对。
*
* @arg name
* @text 定位名
* @desc 定位的名称，与该条定位比对时用该名称字符串。
* @default
* 
*
* @command DateSkip
* @text 日期跳转
* @desc 将当前日期跳转到某个定位的日期。
*
* @arg name
* @text 跳转到
* @desc 跳转到的目标定位名称。
* @default
*
*
* @command ClearDateLocation
* @text 清空定位
* @desc 清除所有的定位记录。
*
*
* @command DatePass
* @text 日期推进
* @desc 日期的 年/月/日/小时 推进。
*
* @arg index
* @type select
* @option 年
* @value 0
* @option 月
* @value 1
* @option 日
* @value 2
* @option 小时
* @value 3
* @text 推进类型
* @desc 选择推进类型。
* @default 0
*
* @arg num
* @type number
* @text 推进量
* @desc 推进的数值。
* @default 0
*
*
* @command DateRecall
* @text 日期倒退
* @desc 日期的 年/月/日/小时 倒退。
*
* @arg index
* @type select
* @option 年
* @value 0
* @option 月
* @value 1
* @option 日
* @value 2
* @option 小时
* @value 3
* @text 倒退类型
* @desc 选择倒退类型。
* @default 0
*
* @arg num
* @type number
* @text 倒退量
* @desc 倒退的数值。
* @default 0
*
*
* @command DateAppoint
* @text 日期指定
* @desc 日期的 年/月/日/小时 指定。
*
* @arg index
* @type select
* @option 年
* @value 0
* @option 月
* @value 1
* @option 日
* @value 2
* @option 小时
* @value 3
* @text 指定类型
* @desc 选择指定类型。
* @default 0
*
* @arg num
* @type number
* @text 指定量
* @desc 指定的数值。
* @default 0
*
*
* @command OpenSceneCalendar
* @text 打开日历场景
* @desc 打开日历场景。
*
*/
/*~struct~festival: 
 *
 * @param name
 * @text 节日名字
 * @desc 节日的名字。
 * @default
 * 
 * @param month
 * @type number
 * @min 1
 * @max 12
 * @text 节日所在的月数
 * @desc 该节日在哪个月（1 ~ 12）。
 * @default 1
 * 
 * @param day
 * @type number
 * @min 1
 * @max 31
 * @text 节日所在的天数
 * @desc 该节日在这个月的几号（1 ~ 31）。
 * @default 1
 * 
 * 
*/
/*~struct~interval: 
 *
 * @param name
 * @text 时段名字
 * @desc 时间段的名字。
 * @default
 * 
 * @param start
 * @type number
 * @min 1
 * @max 24
 * @text 开始的小时
 * @desc 该时段开始的小时数（0 ~ 23）。
 * @default 0
 * 
 * @param end
 * @type number
 * @min 1
 * @max 24
 * @text 结束的小时
 * @desc 该时段结束的小时数（0 ~ 23）。
 * 该时段不包含这个小时数，一到这个小时，该时段结束。
 * @default 0
 * 
 * 
*/
/*~struct~window: 
 * 
 * @param enable
 * @type boolean
 * @text 是否启用
 * @desc 是否启用该窗口。
 * @default false
 * 
 * @param ui
 * @type file
 * @dir img/pictures/
 * @text UI图片
 * @desc 使用图片作为窗口。
 * @default
 * 
 * @param tpt
 * @type boolean
 * @text 窗口背景透明
 * @desc 只有在使用默认窗口时有效。
 * @default false
 * 
 * @param x
 * @type number
 * @text X坐标
 * @desc 窗口X坐标。
 * @default 0
 * 
 * @param y
 * @type number
 * @text Y坐标
 * @desc 窗口Y坐标。
 * @default 0
 * 
 * @param w
 * @type number
 * @min 32
 * @text 宽度
 * @desc 窗口的宽度。
 * @default 126
 * 
 * @param h
 * @type number
 * @min 32
 * @text 高度
 * @desc 窗口的高度。
 * @default 48
 * 
 * @param icon
 * @type number
 * @text 图标
 * @desc 窗口描绘的图标序号。
 * @default 0
 * 
 * @param fontSize
 * @type number
 * @text 文字大小
 * @desc 窗口描绘的文字大小。
 * @default 26
 * 
 * @param fontColor
 * @type number
 * @text 文字颜色
 * @desc 窗口描绘文字的颜色色号。
 * @default 0
 * 
 * @param align
 * @type select
 * @option 靠左
 * @value left
 * @option 居中
 * @value center
 * @option 靠右
 * @value right
 * @text 对齐方式
 * @desc 窗口描绘文字的对齐方式。
 * @default left
 * 
*/
//=================================================================================================
;(() => {
//=================================================================================================
window.$gameDate = null;
//=================================================================================================
const pluginName = 'XdRs_DateSystem';
const parameters = PluginManager.parameters(pluginName);
//=================================================================================================
PluginManager.registerCommand(pluginName, 'ChangeDateSpeed', args => {
    $gameDate.changeSpeed(parseInt(args.speed));
});
PluginManager.registerCommand(pluginName, 'DateRun',  () => $gameDate.run());
PluginManager.registerCommand(pluginName, 'DateStop', () => $gameDate.stop());
PluginManager.registerCommand(pluginName, 'DateLocation', args => {
    if (args.name) $gameDate.location(args.name);
});
PluginManager.registerCommand(pluginName, 'DateSkip', args => {
    if (args.name) $gameDate.skipTo(args.name);
});
PluginManager.registerCommand(pluginName, 'ClearDateLocation', () => $gameDate.clearLocationData());
PluginManager.registerCommand(pluginName, 'DatePass', args => {
    $gameDate.pass(parseInt(args.index), parseInt(args.num));
});
PluginManager.registerCommand(pluginName, 'DateRecall', args => {
    $gameDate.fallBack(parseInt(args.index), parseInt(args.num));
});
PluginManager.registerCommand(pluginName, 'DateAppoint', args => {
    $gameDate.appoint(parseInt(args.index), parseInt(args.num));
});
PluginManager.registerCommand(pluginName, 'OpenSceneCalendar', args => {
    SceneManager.push(Scene_Calendar);
});
//=================================================================================================
const XR_DataManager_createGameObjects = DataManager.createGameObjects;
DataManager.createGameObjects = function() {
    $gameDate = new Game_Date();
    XR_DataManager_createGameObjects.call(this);
};
const XR_DataManager_makeSaveContents = DataManager.makeSaveContents;
DataManager.makeSaveContents = function() {
    const contents = XR_DataManager_makeSaveContents.call(this);
    contents.date = $gameDate;
    return contents;
};
const XR_DataManager_extractSaveContents = DataManager.extractSaveContents;
DataManager.extractSaveContents = function(contents) {
    $gameDate = contents.date;
    XR_DataManager_extractSaveContents.call(this, contents);
};
//=================================================================================================
const XR_SceneManager_initialize = SceneManager.initialize;
SceneManager.initialize = function() {
    XR_SceneManager_initialize.call(this);
    DateManager.initialize();
};
SceneManager.isMapScene = function() {
    return this._scene instanceof Scene_Map;
};
SceneManager.operationDateController = function(result) {
    if (this.isMapScene()) {
        this._scene[result ? 'createDateController' : 'removeDateController']();
    }
};
const XR_SceneManager_updateMain = SceneManager.updateMain;
SceneManager.updateMain = function() {
    XR_SceneManager_updateMain.call(this);
    $gameDate && $gameDate.update();
};
//=================================================================================================
// 日期 Manager
//=================================================================================================
function DateManager() { throw new Error('This is a static class'); }
DateManager.initialize = function() {
    this.initIntervals();
    this.initFestivals();
    this.initWeekWords();
    this.initSeasonImgs();
    this.initCommonEvents();
    this.initControlSwitchs();
};
DateManager.initIntervals = function() {
    this._intervals = {};
    const arr = JSON.parse(parameters['intervals']);
    for (const str of arr) {
        if (str) {
            const struct = JSON.parse(str);
            if (struct.name) {
                const s = parseInt(struct.start), e = parseInt(struct.end);
                if (s !== e) {
                    const icon = parseInt(struct.icon) || 0;
                    const data = {'icon':icon, 'start':s, 'end':e};
                    this._intervals[struct.name] = data;
                }
            }
        }
    }
};
DateManager.initFestivals = function() {
    this._festivals = {};
    const arr = JSON.parse(parameters['festivals']);
    for (const str of arr) {
        if (str) {
            const struct = JSON.parse(str);
            if (struct.name) {
                const m = parseInt(struct.month) - 1;
                const d = parseInt(struct.day) - 1;
                this._festivals[[m,d]] = struct.name;
            }
        }
    }
};
DateManager.initWeekWords = function() {
    this._weekWords = [];
    const arr = JSON.parse(parameters['weekWords']);
    const len = Math.min(7, arr.length);
    for (let i=0;i<len;++i) {
        let index = i === 6 ? 0 : i + 1;
        this._weekWords[index] = arr[i];
    }
};
DateManager.initSeasonImgs = function() {
    this._seasonImgs = [];
    if (parameters['seasonImgs']) {
        this._seasonImgs = JSON.parse(parameters['seasonImgs']);
    }
};
DateManager.initCommonEvents = function() {
    this._commonEvents = [];
    const arr = ['year','month','day','hour', '', 'interval'];
    for (let i=0;i<arr.length;++i) {
        this._commonEvents[i] = parseInt(parameters[arr[i]+'Event']) || 0;
    }
};
DateManager.initControlSwitchs = function() {
    this._switchs = [];
    const arr = ['main','map','menu'];
    for (let i=0;i<arr.length;++i) {
        let id = parseInt(parameters[arr[i] + 'Switch']) || 0;
        this._switchs[i] = id;
    }
};
DateManager.setController = function(controller) {
    this._controller = controller;
};
DateManager.getStartArr = function() {
    const arr = [1, 0, 0, 0, 0, 0];
    const syms = ['Years','Months','Days','Hours'];
    for (let i=0;i<4;++i) {
        let num = parseInt(parameters['initial'+syms[i]]);
        if (i > 0 && i !== 3) num = num - 1;
        let min = i === 0 ? 1 : 0;
        arr[i] = Math.max(min, num);
    }
    return arr;
};
DateManager.isDateEnabled = function() {
    if ($gameSwitches) {
        const id = this._switchs[0] || 0;
        return id === 0 || $gameSwitches.value(id);
    }
    return false;
};
DateManager.isSwitchOn = function(sym) {
    if ($gameSwitches) {
        const index = ['main','map','menu'].indexOf(sym);
        const id = this._switchs[index];
        return id === 0 || $gameSwitches.value(id);
    }
    return false;
};
DateManager.isControllerVisibility = function() {
    return this.isSwitchOn('main') && this.isSwitchOn('map');
};
DateManager.setupControllerVisibility = function(switchId) {
    if (this._switchs.contains(switchId) && this._switchs[2] !== switchId) {
        const result = this.isControllerVisibility();
        SceneManager.operationDateController(result);
    }
};
DateManager.callCommonEvent = function(index) {
    if ($gameTemp) {
        const id = this._commonEvents[index];
        if ($dataCommonEvents[id]) {
            $gameTemp.reserveCommonEvent(id);
        }
    }
};
DateManager.callAllCommonEvents = function() {
    for (let i=0;i<6;++i) this.callCommonEvent(i);
};
DateManager.weeks = function() {
    return this._weekWords;
};
DateManager.weekText = function(index) {
    return this._weekWords[index];
};
DateManager.isLeapYear = function(year) {
    return !(year%4) && !!(year%100) || !(year%400);
};
DateManager.maximumDays = function(dateArr) {
    if (dateArr[1] === 1) return this.isLeapYear(dateArr[0]) ? 29 : 28;
    const result = dateArr[1] < 7 ? !(dateArr[1]%2) : !!(dateArr[1]%2);
    return result ? 31 : 30;
};
DateManager.maxValue = function(index, dateArr) {
    if (index === 2) return this.maximumDays(dateArr);
    return [Infinity, 12, 0, 24, 60][index];
};
DateManager.getIntervalIndex = function(hour) {
    const arr = Object.keys(this._intervals);
    for (let i=0;i<arr.length;++i) {
        let d = this._intervals[arr[i]];
        let result = false;
        if (d.end < d.start) {
            if (hour >= d.start || hour < d.end) {
                result = true;
            }
        } else {
            if (hour >= d.start && hour < d.end) {
                result = true;
            }
        }
        if (result) return i + 1;   
    }
    return 0;
};
DateManager.intervalName = function(index) {
    if (index > 0) {
        const arr = Object.keys(this._intervals);
        return arr[index - 1] || '';
    }
    return '';
};
DateManager.festivalName = function(dateArr) {
    if (dateArr) {
        const key = [dateArr[1], dateArr[2]];
        return this._festivals[key] || '';
    }
    return '';
};
DateManager.seasonImg = function(index) {
    return this._seasonImgs[index] || '';
};
DateManager.changeToBefore = function(index, dateArr) {
    let n = this.maxValue(index, dateArr);
    if (index === 2) {
        if (dateArr[1] === 0) {
            dateArr[0] = Math.max(1, dateArr[0] - 1);
        }
        dateArr[1] = (dateArr[1] + 11) % 12;
        n = this.maximumDays(dateArr);
    }
    dateArr[index] = (dateArr[index] + n - 1) % n;
    return dateArr;
};
DateManager.totalDays = function(dateArr) {
    let total = 0;
    for (let i=0;i<dateArr[0];++i) {
        total += i === 0 ? 0 : (this.isLeapYear(i) ? 366 : 365);
    }
    for (let i=0;i<dateArr[1];++i) {
        total += this.maximumDays([dateArr[0], i]);
    }
    return total + dateArr[2] + 1;
};
DateManager.onChange = function(index) {
    this.callCommonEvent(index);
    if (this._controller) {
        this._controller.onChange(index);
    }
};
window.DateManager = DateManager;
//=================================================================================================
const XR_Game_Switches_setValue = Game_Switches.prototype.setValue;
Game_Switches.prototype.setValue = function(switchId, value) {
    const tmp = this.value(switchId);
    XR_Game_Switches_setValue.call(this, switchId, value);
    if (tmp !== this.value(switchId)) {
        DateManager.setupControllerVisibility(switchId);
    }
};
//=================================================================================================
// 日期实例对象
//=================================================================================================
function Game_Date() {
    this.initialize(...arguments);
}
Object.defineProperties(Game_Date.prototype, { 
    /** 年份值 */
    year:   { get: function() { return this._data[0]; }, configurable: true },
    /** 月份值（1 ~ 12） */
    month:  { get: function() { return this._data[1] + 1; }, configurable: true },
    /** 天数值（1 ~ 当月最大天数） */
    day:    { get: function() { return this._data[2] + 1; }, configurable: true },
    /** 小时值（0 ~ 23） */
    hour:   { get: function() { return this._data[3]; },   configurable: true },
    /** 分钟值（0 ~ 59） */
    minute: { get: function() { return this._data[4]; },   configurable: true },
    /** 星期值（0 ~ 6） */
    week:   { get: function() { return this._weekIndex; }, configurable: true }
});
Game_Date.prototype.initialize = function() {
    this._isGlobalPass = !!eval(parameters['global']);
    this._isStyle12 = !!eval(parameters['style12']);
    this._data = DateManager.getStartArr();
    this._calendarData = null;
    this._speed = 60;
    this._count = 0;
    this.clearLocationData();
    this.refreshWeekIndex();
    this.refreshInterval();
    this.stop();
};
Game_Date.prototype.clearLocationData = function() {
    this._locationData = {};
};
Game_Date.prototype.dateArr = function() {
    return this._data;
};
Game_Date.prototype.run = function() {
    this._isRuning = true;
};
Game_Date.prototype.stop = function() {
    this._isRuning = false;
};
Game_Date.prototype.isRuning = function() {
    return this._isRuning;
};
Game_Date.prototype.location = function(name) {
    this._locationData[name] = this._data.clone();
};
Game_Date.prototype.getLocationArr = function(name) {
    return this._locationData[name];
};
Game_Date.prototype.hasLocation = function(name) {
    return !!this.getLocationArr(name);
};
Game_Date.prototype.saveCalendarData = function(arr) {
    this._calendarData = arr;
};
Game_Date.prototype.getCalendarData = function() {
    if (!!this._calendarData && !!eval(parameters['rememberCalendar'])) {
        return this._calendarData.clone();
    }
    return this._data.slice(0, 2);
};
Game_Date.prototype.changeSpeed = function(speed) {
    this._speed = Math.max(1, speed);
};
Game_Date.prototype.skipTo = function(name) {
    if (this.hasLocation(name)) {
        const copy = this._data.clone();
        this._data = this.getLocationArr(name).clone();
        for (let i=0;i<this._data.length;++i) {
            this._data[i] !== copy[i] && this.onChange(i);
        }
    }
};
Game_Date.prototype.pass = function(index, num) {
    if (index >= 0 && index < 5) {
        num = num || 1;
        const tmp = this._data[index];
        const copyArr = this._data.clone();
        this._data[index] += num;
        if (index === 0 && this._data[index] <= 0) { /**年份最小限制 */
            this._data[index] = 1;
            for (let i=1;i<5;++i) this._data[i] = 0;
        } else {
            if (this._data[index] < 0) {  /**倒退时小于当前最小值的上级循环处理 */
                arguments.callee.call(this, index - 1, -1);
                const arr = DateManager.changeToBefore(index, copyArr);
                const max = DateManager.maxValue(index, arr);
                let n = Math.abs(this._data[index]);
                while (n >= max) {
                    n -= max;
                    arguments.callee.call(this, index - 1, -1);
                }
                this._data[index] = max - n;
            } else {     /**推进时大于当前最大值的上级循环处理 */
                const max = DateManager.maxValue(index, this._data);
                while (this._data[index] >= max) {
                    this._data[index] -= max;
                    arguments.callee.call(this, index - 1, 1);
                }
            }
        }
        if (tmp !== this._data[index]) {
            index < 2 && this.correctionDays();
            this.onChange(index);
        }
    }
};
/**修正最大天数 */
Game_Date.prototype.correctionDays = function() {
    const maxDays = DateManager.maximumDays(this._data);
    if (this._data[2] >= maxDays) {
        this._data[2] = maxDays - 1;
        this.onChange(2);
    }
};
Game_Date.prototype.fallBack = function(index, num) {
    num = num || 1;
    this.pass(index, -num);
};
Game_Date.prototype.appoint = function(index, num) {
    const tmp = this._data[index];
    const max = DateManager.maxValue(index, this._data);
    this._data[index] = Math.max(0, Math.min(max-1, num));
    if (tmp !== this._data[index]) {
        index < 2 && this.correctionDays();
        this.onChange(index);
    }
};
Game_Date.prototype.onChange = function(index) {
    index < 3   && this.refreshWeekIndex();
    index === 3 && this.refreshInterval();
    DateManager.onChange(index);
};
Game_Date.prototype.refreshWeekIndex = function() {
    const days = DateManager.totalDays(this._data);
    this._weekIndex = days % 7;
};
Game_Date.prototype.refreshInterval = function() {
    const tmp = this._data[5];
    this._data[5] = DateManager.getIntervalIndex(this._data[3]);
    if (tmp !== this._data[5]) {
        DateManager.onChange(5);
    }
};
Game_Date.prototype.isFestival = function() {
    return !!this.festivalName();
};
Game_Date.prototype.festivalName = function() {
    return DateManager.festivalName(this._data);
};
Game_Date.prototype.dateText = function() {
    let text = parameters['formatDate'];
    text = text.replace(/%y/, ''+this.year);
    text = text.replace(/%m/, ''+this.month);
    text = text.replace(/%d/, ''+this.day);
    return text;
};
Game_Date.prototype.pureTimeText = function() {
    let text = parameters['formatTime'];
    let hour = this.hour;
    if (this._isStyle12) {
        hour = hour > 12 ? hour - 12 : hour;
    }
    text = text.replace(/%h/, hour.padZero(2));
    text = text.replace(/%n/, this.minute.padZero(2));
    return text;
};
Game_Date.prototype.timeText = function() {
    const name = this.intervalName();
    const text = this.pureTimeText();
    return name ? name + ' ' + text : text;
};
Game_Date.prototype.weekText = function() {
    return DateManager.weekText(this._weekIndex);
};
Game_Date.prototype.seasonIndex = function() {
    return Math.floor(this._data[1] / 3);
};
Game_Date.prototype.seasonImg = function() {
    return DateManager.seasonImg(this.seasonIndex());
};
Game_Date.prototype.intervalIndex = function() {
    return this._data[5];
};
Game_Date.prototype.intervalName = function() {
    return DateManager.intervalName(this.intervalIndex());
};
Game_Date.prototype.canPass = function() {
    if (DateManager.isDateEnabled() && this.isRuning()) {
        return this._isGlobalPass || SceneManager.isMapScene();
    }
    return false;
};
Game_Date.prototype.update = function() {
    if (this.canPass()) {
        if (this._count >= this._speed) {
            this._count = 0;
            this.pass(4);
        }
        this._count++;
    }
};
Game_Date.prototype.passedYears = function(LocationName) {
    const lastArr = this.getLocationArr(LocationName);
    if (lastArr) return this.dateArr()[0] - lastArr[0];
    return 0;
};
Game_Date.prototype.passedMonths = function(LocationName) {
    const lastArr = this.getLocationArr(LocationName);
    if (lastArr) {
        const month1 = this.dateArr()[0] * 12 + this.dateArr()[1];
        const month2 = lastArr[0] * 12 + lastArr[1]; 
        return month1 - month2;
    }
    return 0;
};
Game_Date.prototype.passedDays = function(LocationName) {
    const lastArr = this.getLocationArr(LocationName);
    if (lastArr) {
        const days1 = DateManager.totalDays(this.dateArr());
        const days2 = DateManager.totalDays(lastArr);
        return days1 - days2;
    }
    return 0;
};
Game_Date.prototype.passedHours = function(LocationName) {
    const lastArr = this.getLocationArr(LocationName);
    if (lastArr) {
        const hours1 = DateManager.totalDays(this.dateArr()) * 24 + this.dateArr()[3];
        const hours2 = DateManager.totalDays(lastArr) * 24 + lastArr[3];
        return hours1 - hours2;
    }
    return 0;
};
window.Game_Date = Game_Date;
//=================================================================================================
const XR_Window_Base_convertEscapeCharacters = Window_Base.prototype.convertEscapeCharacters;
Window_Base.prototype.convertEscapeCharacters = function(text) {
    text = XR_Window_Base_convertEscapeCharacters.call(this, text);
    text = text.replace(/\x1bD_YEAR/g,  $gameDate.year);
    text = text.replace(/\x1bD_MONTH/g, $gameDate.month);
    text = text.replace(/\x1bD_DAY/g,   $gameDate.day);
    text = text.replace(/\x1bD_HOUR/g,  $gameDate.hour);
    text = text.replace(/\x1bD_DATE/g,  $gameDate.dateText());
    text = text.replace(/\x1bD_TIME/g,  $gameDate.pureTimeText());
    text = text.replace(/\x1bD_FTV/g,   $gameDate.festivalName());
    text = text.replace(/\x1bD_ITV/g,   $gameDate.intervalName());
    return text;
};
//=================================================================================================
// 日期基本窗口
//=================================================================================================
function Window_DateBase() {
    this.initialize(...arguments);
}
Window_DateBase.prototype = Object.create(Window_Base.prototype);
Window_DateBase.prototype.constructor = Window_DateBase;
Window_DateBase.prototype.initialize = function(data) {
    this._data = data;
    const rect = this._data ? this._data.rect : new Rectangle();
    this._touchTpt = Function('return !!'+parameters['touchTpt']);
    Window_Base.prototype.initialize.call(this, rect);
    this.setupUiFace();
    this.createParts();
    this.refresh();
};
Window_DateBase.prototype.relationArr = function() {
    return [];
};
Window_DateBase.prototype.lineHeight = function() {
    return this.contentsHeight();
};
Window_DateBase.prototype.setupUiFace = function() {
    const uiName = this._data ? this._data.ui : '';
    if (uiName) {
        this._uiSprite = new Sprite(ImageManager.loadPicture(uiName));
        this.addChildToBack(this._uiSprite);
    }
    this._isBackTpt = !!this._uiSprite || (this._data && this._data.tpt);
    if (this._isBackTpt) this.opacity = 0;
};
Window_DateBase.prototype.createParts = function() {
};
Window_DateBase.prototype.resetFontSettings = function() {
    Window_Base.prototype.resetFontSettings.call(this);
    if (this._data) {
        const size = Math.min(this.lineHeight() - 4, this._data.fontSize);
        this.contents.fontSize = size;
    }
};
Window_DateBase.prototype.resetTextColor = function() {
    Window_Base.prototype.resetTextColor.call(this);
    if (this._data) {
        const color = ColorManager.textColor(this._data.fontColor);
        this.changeTextColor(color);
    }
};
Window_DateBase.prototype.currentText = function() {
    return '';
};
Window_DateBase.prototype.currentIcon = function() {
    return this._data ? this._data.icon : 0;
};
Window_DateBase.prototype.isVisibility = function() {
    return !!this._data && this._data.enable;
};
Window_DateBase.prototype.onChange = function(index) {
    if (this.relationArr().contains(index)) {
        this.refresh();
    }
};
Window_DateBase.prototype.refresh = function() {
    this.visible = this.isVisibility();
    if (this.visible) {
        this.contents.clear();
        this.drawAll();
    }
};
Window_DateBase.prototype.drawAll = function() {
    let x = 0;
    const icon = this.currentIcon();
    const text = this.currentText();
    if (icon > 0) {
        x += this.drawIcon(icon, x) + 4;
    }
    if (text && this._data) {
        const w = this.contentsWidth() - x;
        this.drawText(text, x, 0, w, this._data.align);
    }
};
Window_DateBase.prototype.drawIcon = function(iconIndex, x) {
    const bitmap = ImageManager.loadSystem('IconSet');
    const pw = ImageManager.iconWidth, ph = ImageManager.iconHeight;
    const sx = (iconIndex % 16) * pw, sy = Math.floor(iconIndex / 16) * ph;
    const size = Math.min(this.contentsHeight(), ph);
    const y = (this.contentsHeight() - size) / 2;
    this.contents.blt(bitmap, sx, sy, pw, ph, x, y, size, size);
    return size;
};
Window_DateBase.prototype.isTouchPlayer = function() {
    const x = $gamePlayer.screenX() - 48;
    const y = $gamePlayer.screenY() - 96;
    if (this.x > (x + 96) || this.y > (y + 96)) return false;
    if ((this.x + this.width) < x)  return false;
    if ((this.y + this.height) < y) return false;
    return true;
};
Window_DateBase.prototype.changeOpacity = function(opacity) {
    if (!this._isBackTpt && !this._uiSprite) {
        this.opacity = opacity;
    }
    if (this._uiSprite) this._uiSprite.opacity = opacity;
    this._contentsSprite.opacity = opacity;
};
Window_DateBase.prototype.update = function() {
    Window_Base.prototype.update.call(this);
    this.updatePlayerTouch();
};
Window_DateBase.prototype.updatePlayerTouch = function() {
    if (this.visible && this._touchTpt) {
        if (this._isTouched !== this.isTouchPlayer()) {
            this._isTouched = this.isTouchPlayer();
            this.changeOpacity(this._isTouched ? 120 : 255);
        }
    }
};
//=================================================================================================
// 日期时钟窗口
//=================================================================================================
function Window_ClockDisk() {
    this.initialize(...arguments);
}
Window_ClockDisk.prototype = Object.create(Window_DateBase.prototype);
Window_ClockDisk.prototype.constructor = Window_ClockDisk;
Window_ClockDisk.prototype.createParts = function() {
    if (this.isVisibility()) {
        const x = this.width / 2, y = this.height / 2;
        this._hourNeedle = new Sprite_ClockNeedle('hour', x, y);
        this._minuteNeedle = new Sprite_ClockNeedle('minute', x, y);
        this.addChild(this._hourNeedle);
        this.addChild(this._minuteNeedle);
    }
};
Window_ClockDisk.prototype.onChange = function(index) {
    if (this.isVisibility()) {
        this._hourNeedle.onChange(index);
        this._minuteNeedle.onChange(index);
    }
};
Window_ClockDisk.prototype.changeOpacity = function(opacity) {
    Window_DateBase.prototype.changeOpacity.call(this, opacity);
    if (this.isVisibility()) {
        this._hourNeedle.opacity = opacity;
        this._minuteNeedle.opacity = opacity;
    }
};
//=================================================================================================
// 日期窗口
//=================================================================================================
function Window_DisplyDate() {
    this.initialize(...arguments);
}
Window_DisplyDate.prototype = Object.create(Window_DateBase.prototype);
Window_DisplyDate.prototype.constructor = Window_DisplyDate;
Window_DisplyDate.prototype.relationArr = function() {
    return [0, 1, 2];
};
Window_DisplyDate.prototype.currentText = function() {
    return $gameDate.dateText();
};
//=================================================================================================
// 日期时间窗口
//=================================================================================================
function Window_DisplyTime() {
    this.initialize(...arguments);
}
Window_DisplyTime.prototype = Object.create(Window_DateBase.prototype);
Window_DisplyTime.prototype.constructor = Window_DisplyTime;
Window_DisplyTime.prototype.relationArr = function() {
    return [3, 4];
};
Window_DisplyTime.prototype.currentText = function() {
    return $gameDate.timeText();
};
//=================================================================================================
// 日期星期窗口
//=================================================================================================
function Window_DisplyWeek() {
    this.initialize(...arguments);
}
Window_DisplyWeek.prototype = Object.create(Window_DateBase.prototype);
Window_DisplyWeek.prototype.constructor = Window_DisplyWeek;
Window_DisplyWeek.prototype.relationArr = function() {
    return [0, 1, 2];
};
Window_DisplyWeek.prototype.currentText = function() {
    return $gameDate.weekText();
};
//=================================================================================================
// 日期节日窗口
//=================================================================================================
function Window_DisplyFestival() {
    this.initialize(...arguments);
}
Window_DisplyFestival.prototype = Object.create(Window_DateBase.prototype);
Window_DisplyFestival.prototype.constructor = Window_DisplyFestival;
Window_DisplyFestival.prototype.relationArr = function() {
    return [1, 2];
};
Window_DisplyFestival.prototype.currentText = function() {
    return $gameDate.festivalName();
};
Window_DisplyFestival.prototype.isVisibility = function() {
    return $gameDate.isFestival() && Window_DateBase.prototype.isVisibility.call(this);
};
//=================================================================================================
// 日历标题窗口
//=================================================================================================
function Window_CalendarTitle() {
    this.initialize(...arguments);
}
Window_CalendarTitle.prototype = Object.create(Window_Base.prototype);
Window_CalendarTitle.prototype.constructor = Window_CalendarTitle;
Window_CalendarTitle.prototype.initialize = function(rect) {
    Window_Base.prototype.initialize.call(this, rect);
    this._index = 1;
    this.setupUiFace();
    this.createButtons();
};
Window_CalendarTitle.prototype.setupUiFace = function() {
    const name = parameters['calendarTitle'];
    if (name) {
        this.opacity = 0;
        this._uiSprite = new Sprite(ImageManager.loadPicture(name));
        this.addChildToBack(this._uiSprite);
    }
};
Window_CalendarTitle.prototype.createButtons = function() {
    this._upBtn = new Sprite_Button('pageup');
    this._dnBtn = new Sprite_Button('pagedown');
    this._upBtn.setClickHandler(() => this.changeDate(0));
    this._dnBtn.setClickHandler(() => this.changeDate(1));
    this.onIndexChange();
    this.addChild(this._upBtn);
    this.addChild(this._dnBtn);
};
Window_CalendarTitle.prototype.lineHeight = function() {
    return 48;
};
Window_CalendarTitle.prototype.setIndex = function(index) {
    const tmp = this._index;
    this._index = Math.max(0, Math.min(1, index));
    if (tmp !== this._index) {
        SoundManager.playCursor();
        this.onIndexChange();
    }
};
Window_CalendarTitle.prototype.onIndexChange = function() {
    const y = this._index * this.lineHeight() + this._padding;
    this._upBtn.y = y;
    this._dnBtn.y = y;
};
Window_CalendarTitle.prototype.changeDate = function(type) {
    SoundManager.playOk();
    this.parent.changeDateArr(this._index, type);
};
Window_CalendarTitle.prototype.refresh = function() {
    this.contents.clear();
    const tmp = this._maxTextWidth;
    const text1 = this.parent.dateText(0) + ' ' + parameters['wordYear'];
    const text2 = this.parent.dateText(1) + ' ' + parameters['wordMonth'];
    const cw1 = this.textWidth(text1), cw2 = this.textWidth(text2);
    this._maxTextWidth = Math.max(cw1, cw2);
    this.refreshButtons();
    if (tmp != this._maxTextWidth) {
        this.contentsBack.clear();
        const x = this._upBtn.x + this._upBtn.blockWidth() - this._padding + 4;
        const w = this._maxTextWidth + this._upBtn.blockWidth() * 2 - 8;
        for (let i=0;i<2;++i) {
            let rect = new Rectangle(x, i * this.lineHeight() + 4, w, this.lineHeight() - 8);
            Window_Selectable.prototype.drawBackgroundRect.call(this, rect);
        }
    }
    this.resetTextColor();
    this.drawText(text1, 0, 0, this.contents.width, 'center');
    this.drawText(text2, 0, this.lineHeight(), this.contents.width, 'center');
};
Window_CalendarTitle.prototype.refreshButtons = function() {
    const cx = this.width / 2;
    this._upBtn.x = cx - this._maxTextWidth / 2 - this._upBtn.blockWidth() * 2;
    this._dnBtn.x = cx + this._maxTextWidth / 2 + this._dnBtn.blockWidth();
};
Window_CalendarTitle.prototype.isInputAction = function(sym) {
    return Input.isTriggered(sym) || Input.isRepeated(sym);
};
Window_CalendarTitle.prototype.getTouchIndex = function() {
    const x = this.x + this._upBtn.x + this._upBtn.blockWidth();
    const w = this._maxTextWidth + this._upBtn.blockWidth() * 2;
    const h = this.lineHeight();
    for (let i=0;i<2;++i) {
        let y = i * h + this._padding + this.y;
        if (TouchInput.x < x || TouchInput.y < y) continue;
        if (TouchInput.x > (x + w) || TouchInput.y > (y + h)) continue;
        return i;
    }
    return null;
};
Window_CalendarTitle.prototype.update = function() {
    Window_Base.prototype.update.call(this);
    this.updateInput();
    this.updateTouchInput();
};
Window_CalendarTitle.prototype.updateInput = function() {
    if (this.isInputAction('up'))     return this.setIndex((this._index + 1) % 2);
    if (this.isInputAction('down'))   return this.setIndex((this._index + 1) % 2);
    if (this.isInputAction('left'))   return this.changeDate(0);
    if (this.isInputAction('right'))  return this.changeDate(1);
    if (this.isInputAction('cancel')) {
        SoundManager.playCancel();
        this.parent.popScene();
    }
};
Window_CalendarTitle.prototype.updateTouchInput = function() {
    if (TouchInput.isTriggered()) {
        const index = this.getTouchIndex();
        index !== null && this.setIndex(index);
    }
    if (TouchInput.isCancelled()) {
        SoundManager.playCancel();
        this.parent.popScene();
    }
};
//=================================================================================================
// 日历天数列表窗口
//=================================================================================================
function Window_CalendarInfo() {
    this.initialize(...arguments);
}
Window_CalendarInfo.prototype = Object.create(Window_Base.prototype);
Window_CalendarInfo.prototype.constructor = Window_CalendarInfo;
Window_CalendarInfo.prototype.initialize = function(rect) {
    Window_Base.prototype.initialize.call(this, rect);
    this._markImg = parameters['calendarCud'];
    this.setupUiFace();
};
Window_CalendarInfo.prototype.setupUiFace = function() {
    const name = parameters['calendarInfo'];
    if (name) {
        this.opacity = 0;
        this._uiSprite = new Sprite(ImageManager.loadPicture(name));
        this.addChildToBack(this._uiSprite);
    }
};
Window_CalendarInfo.prototype.maxItems = function() {
    return this.parent ? this.parent.maxDays() : 0;
};
Window_CalendarInfo.prototype.itemRect = function(index) {
    const w = this.contents.width / 7;
    const h = (this.contents.height - this.lineHeight()) / 6;
    const x = index % 7 * w;
    const y = Math.floor(index / 7) * h + this.lineHeight();
    return new Rectangle(x, y, w, h);
};
Window_CalendarInfo.prototype.refresh = function() {
    this._startIndex = this.parent.startIndex();
    this.contents.clear();
    this.drawWeeks();
    this.drawList();
};
Window_CalendarInfo.prototype.drawWeeks = function() {
    const arr = DateManager.weeks();
    const w = this.contents.width / 7;
    this.changeTextColor(this.systemColor());
    for (let i=0;i<7;++i) {
        let text = arr[i] || '';
        this.drawText(text, i*w, 0, w, 'center');
    }
};
Window_CalendarInfo.prototype.drawList = function() {
    this.resetTextColor();
    for (let i=0;i<this.maxItems();++i) {
        if (this.parent.isCurrentDay(i) && this._markImg) {
            ImageManager.loadPicture(this._markImg).addLoadListener(() => {
                this.drawDay(i);
            });
        } else this.drawDay(i);
    }
};
Window_CalendarInfo.prototype.drawDay = function(index) {
    const rIndex = index + this._startIndex;
    const rect = this.itemRect(rIndex);
    if (this.parent.isCurrentDay(index) && this._markImg) {
        const bitmap = ImageManager.loadPicture(this._markImg);
        const bx = rect.x + (rect.width - bitmap.width) / 2;
        const by = rect.y + (rect.height - bitmap.height) / 2;
        this.contents.blt(bitmap, 0, 0, bitmap.width, bitmap.height, bx, by);
    }
    this.contents.drawText(''+(index+1), rect.x, rect.y, rect.width, rect.height, 'center');
    const text = this.parent.festivalName(index);
    if (!!text) {
        const color = ColorManager.textColor(parseInt(parameters['fntColor']) || 0);
        const y = rect.y + rect.height / 2 + this.contents.fontSize / 2;
        this.changeTextColor(color);
        this.contents.fontSize = 16;
        this.contents.drawText(text, rect.x, y, rect.width, 20, 'center');
        this.resetFontSettings();
    }
};
//=================================================================================================
const XR_Window_MenuCommand_addOriginalCommands = Window_MenuCommand.prototype.addOriginalCommands;
Window_MenuCommand.prototype.addOriginalCommands = function() {
    if (DateManager.isSwitchOn('main') && DateManager.isSwitchOn('menu')) {
        this.addCommand(parameters['calendar'], 'calendar');
    }
    XR_Window_MenuCommand_addOriginalCommands.call(this);
};
//=================================================================================================
// 日期季节精灵
//=================================================================================================
function Sprite_DateSeason() {
    this.initialize(...arguments);
}
Sprite_DateSeason.prototype = Object.create(Sprite.prototype);
Sprite_DateSeason.prototype.constructor = Sprite_DateSeason;
Sprite_DateSeason.prototype.initialize = function() {
    Sprite.prototype.initialize.call(this);
    this.setPosition();
    this.refresh();
};
Sprite_DateSeason.prototype.onChange = function(index) {
    index === 1 && this.refresh();
};
Sprite_DateSeason.prototype.setPosition = function() {
    const arr = parameters['seasonPoint'].split(',').map(n => {
        return parseInt(n) || 0;
    });
    this.move(arr[0], arr[1]);
};
Sprite_DateSeason.prototype.refresh = function() {
    const name = $gameDate.seasonImg();
    if (name) this.bitmap = ImageManager.loadPicture(name);
    else this.bitmap = null;
};
//=================================================================================================
// 日期时钟指针精灵（时针 + 分针）
//=================================================================================================
function Sprite_ClockNeedle() {
    this.initialize(...arguments);
}
Sprite_ClockNeedle.prototype = Object.create(Sprite.prototype);
Sprite_ClockNeedle.prototype.constructor = Sprite_ClockNeedle;
Sprite_ClockNeedle.prototype.initialize = function(name, x, y) {
    Sprite.prototype.initialize.call(this);
    this._name = name;
    this.setup();
    this.move(x, y);
};
Sprite_ClockNeedle.prototype.setup = function() {
    const uiName = parameters[this._name + 'Hand'];
    if (uiName) {
        this.bitmap = ImageManager.loadPicture(uiName);
        this.bitmap.addLoadListener(this.setAxis.bind(this));
        this.refresh();
    }
};
Sprite_ClockNeedle.prototype.index = function() {
    return this._name === 'hour' ? 3 : 4;
};
Sprite_ClockNeedle.prototype.onChange = function(index) {
    index === 4 && this.refresh();
};
Sprite_ClockNeedle.prototype.setAxis = function() {
    const arr = parameters[this._name + 'Axis'].split(',').map(n => {
        return parseInt(n) || 0;
    });
    const ax = Math.min(1, arr[0] / this.bitmap.width);
    const ay = Math.min(1, arr[1] / this.bitmap.height);
    this.anchor = new Point(ax, ay);
};
Sprite_ClockNeedle.prototype.refresh = function() {
    const index = this.index();
    let now = $gameDate._data[index];
    if (index === 3) {
        now = now * 60 + $gameDate._data[4];
    }
    const angle = now * 360 / (index === 3 ? 720 : 60);
    this.rotation = (angle * Math.PI) / 180;
};
//=================================================================================================
// 日期窗口 图层+管理 精灵
//=================================================================================================
function Sprite_DateController() {
    this.initialize(...arguments);
}
Sprite_DateController.prototype = Object.create(Sprite.prototype);
Sprite_DateController.prototype.constructor = Sprite_DateController;
Sprite_DateController.prototype.initialize = function() {
    Sprite.prototype.initialize.call(this);
    this.createAllWindows();
};
Sprite_DateController.prototype.getWindowData = function(sym) {
    const struct = parameters[sym + 'Window'];
    if (struct) {
        const data = JSON.parse(struct);
        const x = parseInt(data.x) || 0;
        const y = parseInt(data.y) || 0;
        const w = parseInt(data.w) || 160;
        const h = parseInt(data.h) || 48;
        data.tpt = !!eval(data.tpt);
        data.enable = !!eval(data.enable);
        data.icon = parseInt(data.icon) || 0;
        data.rect = new Rectangle(x, y, w, h);
        data.fontSize = parseInt(data.fontSize) || 26;
        data.fontColor = parseInt(data.fontColor) || 0;
        return data;
    }
    return null;
};
Sprite_DateController.prototype.createAllWindows = function() {
    this._windows = [];
    this._windows.push(new Sprite_DateSeason());
    this._windows.push(new Window_ClockDisk(this.getWindowData('clock')));
    this._windows.push(new Window_DisplyDate(this.getWindowData('date')));
    this._windows.push(new Window_DisplyTime(this.getWindowData('time')));
    this._windows.push(new Window_DisplyWeek(this.getWindowData('week')));
    this._windows.push(new Window_DisplyFestival(this.getWindowData('festival')));
    this._windows.forEach(w => this.addChild(w));
};
Sprite_DateController.prototype.onChange = function(index) {
    for (const w of this._windows) w.onChange(index);
};
//=================================================================================================
const XR_Scene_Map_terminate = Scene_Map.prototype.terminate;
Scene_Map.prototype.terminate = function() {
    XR_Scene_Map_terminate.call(this);
    DateManager.setController(null);
};
const XR_Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
Scene_Map.prototype.createAllWindows = function() {
    this.createControllerLayer();
    this.createDateController();
    XR_Scene_Map_createAllWindows.call(this);
};
Scene_Map.prototype.createControllerLayer = function() {
    this._controllerLayer = new Sprite();
    this.addChild(this._controllerLayer);
};
Scene_Map.prototype.createDateController = function() {
    if (!this._dateController && DateManager.isControllerVisibility()) {
        this._dateController = new Sprite_DateController();
        DateManager.setController(this._dateController);
        this._controllerLayer.addChild(this._dateController);
    }
};
Scene_Map.prototype.removeDateController = function() {
    if (this._dateController) {
        this._controllerLayer.removeChild(this._dateController);
        DateManager.setController(null);
        this._dateController.destroy();
        this._dateController = null;
    }
};
//=================================================================================================
const XR_Scene_Menu_createCommandWindow = Scene_Menu.prototype.createCommandWindow;
Scene_Menu.prototype.createCommandWindow = function() {
    XR_Scene_Menu_createCommandWindow.call(this);
    this._commandWindow.setHandler('calendar', this.commandCalendar.bind(this));
};
Scene_Menu.prototype.commandCalendar = function() {
    SceneManager.push(Scene_Calendar);
};
//=================================================================================================
// 日历场景
//=================================================================================================
function Scene_Calendar() {
    this.initialize(...arguments);
}
Scene_Calendar.prototype = Object.create(Scene_MenuBase.prototype);
Scene_Calendar.prototype.constructor = Scene_Calendar;
Scene_Calendar.prototype.initialize = function() {
    Scene_MenuBase.prototype.initialize.call(this);
    this._dateArr = $gameDate.getCalendarData();
};
Scene_Calendar.prototype.terminate = function() {
    Scene_MenuBase.prototype.terminate.call(this);
    DateManager.setController(null);
    if (!!eval(parameters['rememberCalendar'])) {
        $gameDate.saveCalendarData(this._dateArr);
    }
};
Scene_Calendar.prototype.onChange = function(index) {
    index < 3 && this._infoWindow.refresh();
};
Scene_Calendar.prototype.dateArr = function() {
    return this._dateArr;
};
Scene_Calendar.prototype.titleWindowRect = function() {
    const wx = 0;
    const wy = this.mainAreaTop();
    const ww = Graphics.width;
    const wh = 120;
    return new Rectangle(wx, wy, ww, wh);
};
Scene_Calendar.prototype.infoWindowRect = function() {
    const wx = 0;
    const wy = this.mainAreaTop() + 120;
    const ww = Graphics.width;
    const wh = Graphics.height - wy;
    return new Rectangle(wx, wy, ww, wh);
};
Scene_Calendar.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createTitleWindow();
    this.createInfoWindow();
    this.refreshAllWIndows();
    DateManager.setController(this);
};
Scene_Calendar.prototype.createTitleWindow = function() {
    this._titleWindow = new Window_CalendarTitle(this.titleWindowRect());
    this.addChild(this._titleWindow);
};
Scene_Calendar.prototype.createInfoWindow = function() {
    this._infoWindow = new Window_CalendarInfo(this.infoWindowRect());
    this.addChild(this._infoWindow);
};
Scene_Calendar.prototype.changeDateArr = function(index, type) {
    const tmp = this._dateArr[index];
    if (index < 2) {
        this._dateArr[index] += (type === 0 ? -1 : 1);
        if (this._dateArr[index] < 0) {
            if (index === 1) {
                this._dateArr[0] = Math.max(1, this._dateArr[0] - 1);
                this._dateArr[index] = 12 - Math.abs(this._dateArr[index]);
            } else this._dateArr[index] = 1;
        } else {
            if (index === 1 && this._dateArr[index] >= 12) {
                this._dateArr[0] = this._dateArr[0] + 1;
                this._dateArr[index] = this._dateArr[index] % 12;
            }
        }
    }
    if (tmp !== this._dateArr[index]) {
        this.refreshAllWIndows();
    }
};
Scene_Calendar.prototype.dateText = function(index) {
    const num = this._dateArr[index] || 0;
    return ''+(num + (index === 1 ? 1 : 0));
};
Scene_Calendar.prototype.isCurrentDay = function(day) {
    if ($gameDate._data[0] !== this._dateArr[0]) return false;
    if ($gameDate._data[1] !== this._dateArr[1]) return false;
    return $gameDate._data[2] === day;
};
Scene_Calendar.prototype.startIndex = function() {
    this._dateArr[2] = 0;
    const days = DateManager.totalDays(this._dateArr);
    return days % 7;
};
Scene_Calendar.prototype.maxDays = function() {
    return DateManager.maximumDays(this._dateArr);
};
Scene_Calendar.prototype.festivalName = function(day) {
    this._dateArr[2] = day;
    return DateManager.festivalName(this._dateArr);
};
Scene_Calendar.prototype.refreshAllWIndows = function() {
    this._titleWindow.refresh();
    this._infoWindow.refresh();
};
window.Scene_Calendar = Scene_Calendar;
//=================================================================================================
})();
//=================================================================================================
// end
//=================================================================================================