//==========================================================================
// EliMZ_FontManager.js
//==========================================================================

/*:
@target MZ
@base EliMZ_Book

@plugindesc ♦1.2.2♦ Enable the usage of multiple fonts!
@author Hakuen Studio
@url https://hakuenstudio.itch.io/eli-font-manager-for-rpg-maker/rate?source=game

@help
★★★★★ Rate the plugin! Please, is very important to me ^^
● Terms of Use
https://www.hakuenstudio.com/terms-of-use-5-0-0

============================================================================
Features
============================================================================

● Use multiple fonts in-game and attach them into different scenes or 
windows!
● Set different fonts for Game Timer, Battler Names, Damage Pop-up, and 
Game Title! (PRO)
● Store the font changes into a save file(PRO).
● Set predefined settings for the fonts like text color, outline color, 
outline width, italic and bold! (PRO)

============================================================================
How to use
============================================================================

https://docs.google.com/document/d/17OtxyAgKhFHYAkqw5cpkcfUn95J9xM_l2Xkyjss79_Y/edit?usp=sharing

============================================================================

@param fonts
@text Font List
@type struct<fontListSt>[]
@desc Setup here all your fonts.
@default

@param defaultIndex
@text Default Font Index
@type number
@desc The font index of the font list that will be used by default, in case a window or scene didn't have one.
@default 0

@param saveFontChanges
@text Save Font Changes
@type boolean
@desc Choose if you want to save font changes when using plugin command or escape codes.
@default true

@command cmd_changeFont
@text Change Font
@type text
@desc Change the font of a window or/and scene.
@default false

    @arg face
    @text FontFace
    @type text
    @desc The font face you want to use.
    @default 0

    @arg winName
    @text Window Name
    @type combo[]
    @option Window_ActorCommand @option Window_BattleActor @option Window_BattleEnemy @option Window_BattleItem @option Window_BattleLog @option Window_BattleSkill @option Window_BattleStatus @option Window_ChoiceList @option Window_CommandInfo @option Window_DebugEdit @option Window_DebugRange @option Window_DescriptionInfo @option Window_EquipCommand @option Window_EquipItem @option Window_EquipSlot @option Window_EquipStatus @option Window_EventItem @option Window_GameEnd @option Window_Gold @option Window_Help @option Window_ItemCategory @option Window_ItemList @option Window_MapName @option Window_MapSelectCommand @option Window_MenuActor @option Window_MenuCommand @option Window_MenuStatus @option Window_Message @option Window_NameBox @option Window_NameEdit @option Window_NameInput @option Window_NumberInput @option Window_Options @option Window_PartyCommand @option Window_SavefileList @option Window_ScrollText @option Window_ShopBuy @option Window_ShopCommand @option Window_ShopNumber @option Window_ShopSell @option Window_ShopStatus @option Window_SkillList @option Window_SkillStatus @option Window_SkillType @option Window_Status @option Window_StatusEquip @option Window_StatusParam @option Window_TitleCommand @option Window_TitleInfo @option Window_ToastInfo
    @desc Change the font of a window. It is case sensitive. Leave empty to not change.
    @default []

    @arg sceneName
    @text Scene Name
    @type combo[]
    @option Scene_Battle @option Scene_Debug @option Scene_Equip @option Scene_GameEnd @option Scene_Gameover @option Scene_Item @option Scene_Load @option Scene_Map @option Scene_MapSelect @option Scene_Menu @option Scene_MenuInfo @option Scene_Name @option Scene_Option @option Scene_Save @option Scene_Shop @option Scene_Skill @option Scene_Status @option Scene_Title 
    @desc Change the font of a scene. It is case sensitive. Leave empty to not change.
    @default []

@command cmd_resetFont
@text Reset Font
@type text
@desc Revert a window or/and a scene font to the default.
@default false

    @arg winName
    @text Window Name
    @type combo[]
    @option Window_ActorCommand @option Window_BattleActor @option Window_BattleEnemy @option Window_BattleItem @option Window_BattleLog @option Window_BattleSkill @option Window_BattleStatus @option Window_ChoiceList @option Window_CommandInfo @option Window_DebugEdit @option Window_DebugRange @option Window_DescriptionInfo @option Window_EquipCommand @option Window_EquipItem @option Window_EquipSlot @option Window_EquipStatus @option Window_EventItem @option Window_GameEnd @option Window_Gold @option Window_Help @option Window_ItemCategory @option Window_ItemList @option Window_MapName @option Window_MapSelectCommand @option Window_MenuActor @option Window_MenuCommand @option Window_MenuStatus @option Window_Message @option Window_NameBox @option Window_NameEdit @option Window_NameInput @option Window_NumberInput @option Window_Options @option Window_PartyCommand @option Window_SavefileList @option Window_ScrollText @option Window_ShopBuy @option Window_ShopCommand @option Window_ShopNumber @option Window_ShopSell @option Window_ShopStatus @option Window_SkillList @option Window_SkillStatus @option Window_SkillType @option Window_Status @option Window_StatusEquip @option Window_StatusParam @option Window_TitleCommand @option Window_TitleInfo @option Window_ToastInfo
    @desc Change the font of a window. It is case sensitive. Leave empty to not change.
    @default []

    @arg sceneName
    @text Scene Name
    @type combo[]
    @option Scene_Battle @option Scene_Debug @option Scene_Equip @option Scene_GameEnd @option Scene_Gameover @option Scene_Item @option Scene_Load @option Scene_Map @option Scene_MapSelect @option Scene_Menu @option Scene_MenuInfo @option Scene_Name @option Scene_Option @option Scene_Save @option Scene_Shop @option Scene_Skill @option Scene_Status @option Scene_Title 
    @desc Change the font of a scene. It is case sensitive. Leave empty to not change.
    @default []

@command cmd_resetAllFont
@text Reset All Fonts
@desc Revert all windows and scene fonts to the default.

*/

/* -------------------------------- FONT LIST ------------------------------- */
{
/*~struct~fontListSt:

@param file
@text Font file
@type text
@desc The font file to load(with extension!).
@default 

@param face
@text FontFace
@type text
@desc The font face that will be used to reference this font inside game.
@default 

@param size
@text Font Size
@type text
@desc The default font size for this font.
@default 26

@param textColor
@text Text Color
@type text
@desc Choose a color for the text. Supports HTML/HEX/RGB/RGBA.
Default is #ffffff
@default #ffffff

@param outlineColor
@text Outline Color
@type text
@desc Choose a color for the outline. Supports HTML/HEX/RGB/RGBA.
Default is 0, 0, 0, 0.5.
@default 0, 0, 0, 0.5

@param outlineWidth
@text Outline Width
@type number
@desc Default value is 3.
@default 3

@param italic
@text Italic
@type boolean
@desc Set to true to use italic font and false to not.
@default false

@param bold
@text Bold
@type boolean
@desc Set to true to use bold font and false to not.
@default false

@param sceneList
@text Scene List
@type combo[]
@option Scene_Battle @option Scene_Debug @option Scene_Equip @option Scene_GameEnd @option Scene_Gameover @option Scene_Item @option Scene_Load @option Scene_Map @option Scene_MapSelect @option Scene_Menu @option Scene_MenuInfo @option Scene_Name @option Scene_Option @option Scene_Save @option Scene_Shop @option Scene_Skill @option Scene_Status @option Scene_Title 
@desc A list of all scenes that will use this font.
It is case sensitive.
@default []

@param windowList
@text Window List
@type combo[]
@option Window_ActorCommand @option Window_BattleActor @option Window_BattleEnemy @option Window_BattleItem @option Window_BattleLog @option Window_BattleSkill @option Window_BattleStatus @option Window_ChoiceList @option Window_CommandInfo @option Window_DebugEdit @option Window_DebugRange @option Window_DescriptionInfo @option Window_EquipCommand @option Window_EquipItem @option Window_EquipSlot @option Window_EquipStatus @option Window_EventItem @option Window_GameEnd @option Window_Gold @option Window_Help @option Window_ItemCategory @option Window_ItemList @option Window_MapName @option Window_MapSelectCommand @option Window_MenuActor @option Window_MenuCommand @option Window_MenuStatus @option Window_Message @option Window_NameBox @option Window_NameEdit @option Window_NameInput @option Window_NumberInput @option Window_Options @option Window_PartyCommand @option Window_SavefileList @option Window_ScrollText @option Window_ShopBuy @option Window_ShopCommand @option Window_ShopNumber @option Window_ShopSell @option Window_ShopStatus @option Window_SkillList @option Window_SkillStatus @option Window_SkillType @option Window_Status @option Window_StatusEquip @option Window_StatusParam @option Window_TitleCommand @option Window_TitleInfo @option Window_ToastInfo
@desc A list of all windows that will use this font.
It is case sensitive.
@default []

@param isForDamageSprite
@text Use on Damage Pop up
@type boolean
@desc If true, this font will be used to draw the damage values in battle.
@default false

@param isForGaugeLabel
@text Use on Gauge Label
@type boolean
@desc If true, this font will be used to draw the label of the gauges.
@default false

@param isForGaugeValue
@text Use on Gauge Value
@type boolean
@desc If true, this font will be used to draw the values of the gauges.
@default false

@param isForBattlerName
@text Use Battler Name
@type boolean
@desc If true, this font will be used to draw the battler names on battle.
@default false

@param isForGameTimer
@text Use on Game Timer
@type boolean
@desc If true, this font will be used on the game timer.
@default false

@param isForGameTitle
@text Use on Game Title
@type boolean
@desc If true, this font will be used to draw the game title on title screen.
@default false

*/
}

"use strict"

var Eli = Eli || {}
var Imported = Imported || {}
Imported.Eli_FontManager = true

/* ========================================================================== */
/*                                   PLUGIN                                   */
/* ========================================================================== */
Eli.FontManager = {

    pro: true,
    Parameters: class {
        constructor(parameters){
            this.fonts = this.parseFont(JSON.parse(parameters.fonts))
            this.saveFontChanges = parameters.saveFontChanges === "true"
            this.defaultIndex = this.findDefaultFontIndex(parameters.defaultIndex)
        }

        parseFont(parameters){
            const fonts = []
    
            for(const param of parameters){
                const font = JSON.parse(param)
                fonts.push(this.createFont(font))
            }
    
            return fonts
        }

        createFont(font){
            return {
                file: font.file,
                face: font.face,
                size: Number(font.size),
                textColor: Eli.ColorManager.getHexOrName(font.textColor),
                outlineColor: Eli.ColorManager.getHexOrName(font.outlineColor),
                outlineWidth: Number(font.outlineWidth),
                italic: font.italic === "true",
                bold: font.bold === "true",
                isForGameTimer: font.isForGameTimer === "true",
                isForGameTitle: font.isForGameTitle === "true",
                isForDamageSprite: font.isForDamageSprite === "true",
                isForGaugeLabel: font.isForGaugeLabel === "true",
                isForGaugeValue: font.isForGaugeValue === "true",
                isForBattlerName: font.isForBattlerName === "true",
                sceneList: JSON.parse(font.sceneList || "[]"),
                windowList: JSON.parse(font.windowList || "[]"),
            }
        }

        findDefaultFontIndex(defaultIndex){
            const index = this.fonts.findIndex(item => item.face === defaultIndex)
    
            if(index === -1){
                return Number(defaultIndex)
            }else{
                return Math.max(0, index)
            }
    
        }
    },

    initialize(){
        this.initParameters()
        this.initPluginCommands()
    },

    initParameters(){
        const parameters = PluginManager.parameters(Eli.PluginManager.getPluginName())
        this.parameters = new this.Parameters(parameters)
    },

    initPluginCommands(){
        const commands = ["cmd_changeFont", "cmd_resetFont", "cmd_resetAllFont"]
        Eli.PluginManager.registerCommands(this, commands)
    },

    getParam(){
        return this.parameters
    },

    findParameterFont(fontFace){
        if(isNaN(fontFace)){
            return this.getParam().fonts.findIndex(font => font.face.toLowerCase() === fontFace.toLowerCase())
        }else{
            return Number(fontFace)
        }
    },

    findSavedFont(containerName){
        return this.getSavedFonts()[containerName]
    },

    getSavedFonts(){
        return $eliData.contents.FontManager
    },

    changeContainerFont(containerName, fontFace){
        const fontIndex = this.findParameterFont(fontFace)

        if(fontIndex > -1){
            this.getSavedFonts()[containerName] = fontIndex
        }
    },

    removeSavedFont(containerName){
        delete this.getSavedFonts()[containerName]
    },

    cmd_changeFont(args){
        const winList = JSON.parse(args.winName || "[]") 
        const sceneList = JSON.parse(args.sceneName || "[]")

        for(const winName of winList || []){
            this.changeContainerFont(winName, args.face)
        }

        for(const sceneName of sceneList || []){
            this.changeContainerFont(sceneName, args.face)
        }
    },

    cmd_resetFont(args){
        const winList = JSON.parse(args.winName || "[]") 
        const sceneList = JSON.parse(args.sceneName || "[]")

        for(const winName of winList || []){
            this.removeSavedFont(winName)
        }

        for(const sceneName of sceneList || []){
            this.removeSavedFont(sceneName)
        }
    },

    cmd_resetAllFont(args){
        $eliData.initFontManagerData()
    },
    
}

{

const Plugin = Eli.FontManager
const Alias = {}

Plugin.initialize()

/* ------------------------------- SAVED DATA ------------------------------- */
Alias.Eli_SavedContents_initialize = Eli_SavedContents.prototype.initialize
Eli_SavedContents.prototype.initialize = function(){
    Alias.Eli_SavedContents_initialize.call(this)
    this.initFontManagerData()
}

Eli_SavedContents.prototype.initFontManagerData = function(){
    this.contents.FontManager = {}
}

/* ------------------------------- SCENE BOOT ------------------------------- */
Alias.Scene_Boot_loadGameFonts = Scene_Boot.prototype.loadGameFonts
Scene_Boot.prototype.loadGameFonts = function() {
    Alias.Scene_Boot_loadGameFonts.call(this)
    this.loadExtraFonts()
}

Scene_Boot.prototype.loadExtraFonts = function() {
    for(const font of Plugin.getParam().fonts){
        FontManager.load(font.face, font.file)
    }
}

/* ------------------------------- SCENE TITLE ------------------------------ */
// Overwrite
Scene_Title.prototype.drawGameTitle = function() {
    const [text, x, y, maxWidth] = this.createGameTitleSettings()
    this.setTitleFontSettings()

    this._gameTitleSprite.bitmap.drawText(text, x, y, maxWidth, 48, "center")
}

Scene_Title.prototype.createGameTitleSettings = function(){
    const text = $dataSystem.gameTitle
    const x = 20
    const y = Graphics.height / 4
    const maxWidth = Graphics.width - x * 2

    return [text, x, y, maxWidth]
}

Scene_Title.prototype.setTitleFontSettings = function() {
    const bitmap = this._gameTitleSprite.bitmap
    const titleFont = Plugin.getParam().fonts.find(font => font.isForGameTitle) || Plugin.getParam().fonts[0]
    
    bitmap.fontFace = `${titleFont.face}, ${$gameSystem.mainFontFace()}`
    bitmap.fontItalic = titleFont.italic
    bitmap.fontBold = titleFont.bold
    bitmap.fontSize = titleFont.size
    bitmap.textColor = Eli.ColorManager.getHexOrName(titleFont.textColor) || ColorManager.normalColor()
    bitmap.outlineColor = Eli.ColorManager.getHexOrName(titleFont.outlineColor) || "black"
    bitmap.outlineWidth = titleFont.outlineWidth
}

/* --------------------------------- SPRITE --------------------------------- */
Sprite.prototype.getCustomFontFace = function(spriteType, defaultFont){
    const customFont = Plugin.getParam().fonts.find(font => font[spriteType])

    return customFont ? `${customFont.face}, ${defaultFont}` : defaultFont
}

Sprite.prototype.getCustomFontSize = function(spriteType){
    const customFont = Plugin.getParam().fonts.find(font => font[spriteType])

    return customFont?.size
}

/* ------------------------------ SPRITE DAMAGE ----------------------------- */
Alias.Sprite_Damage_fontFace = Sprite_Damage.prototype.fontFace
Sprite_Damage.prototype.fontFace = function() {
    const defaultFont = Alias.Sprite_Damage_fontFace.call(this)

    return this.getCustomFontFace("isForDamageSprite", defaultFont)
}

Alias.Sprite_Damage_fontSize = Sprite_Damage.prototype.fontSize
Sprite_Damage.prototype.fontSize = function() {
    return this.getCustomFontSize("isForDamageSprite") || Alias.Sprite_Damage_fontSize.call(this)
}

/* ------------------------------ SPRITE GAUGE ------------------------------ */
Alias.Sprite_Gauge_labelFontFace = Sprite_Gauge.prototype.labelFontFace
Sprite_Gauge.prototype.labelFontFace = function() {
    const defaultFont = Alias.Sprite_Gauge_labelFontFace.call(this)

    return this.getCustomFontFace("isForGaugeLabel", defaultFont)
}

Alias.Sprite_Gauge_labelFontSize = Sprite_Gauge.prototype.labelFontSize
Sprite_Gauge.prototype.labelFontSize = function() {
    return this.getCustomFontSize("isForGaugeLabel") || Alias.Sprite_Gauge_labelFontSize.call(this)
}

Alias.Sprite_Gauge_valueFontFace = Sprite_Gauge.prototype.valueFontFace
Sprite_Gauge.prototype.valueFontFace = function() {
    const defaultFont = Alias.Sprite_Gauge_valueFontFace.call(this)

    return this.getCustomFontFace("isForGaugeValue", defaultFont)
}

Alias.Sprite_Gauge_valueFontSize = Sprite_Gauge.prototype.valueFontSize
Sprite_Gauge.prototype.valueFontSize = function() {
    return this.getCustomFontSize("isForGaugeValue") || Alias.Sprite_Gauge_valueFontSize.call(this)
}

/* ------------------------------- SPRITE NAME ------------------------------ */
Alias.Sprite_Name_fontFace = Sprite_Name.prototype.fontFace
Sprite_Name.prototype.fontFace = function() {
    const defaultFont = Alias.Sprite_Name_fontFace.call(this)

    return this.getCustomFontFace("isForBattlerName", defaultFont)
}

Alias.Sprite_Name_fontSize = Sprite_Name.prototype.fontSize
Sprite_Name.prototype.fontSize = function() {
    return this.getCustomFontSize("isForBattlerName") || Alias.Sprite_Name_fontSize.call(this)
}

/* ------------------------------ SPRITE TIMER ------------------------------ */
Alias.Sprite_Timer_fontFace = Sprite_Timer.prototype.fontFace
Sprite_Timer.prototype.fontFace = function() {
    const defaultFont = Alias.Sprite_Timer_fontFace.call(this)

    return this.getCustomFontFace("isForGameTimer", defaultFont)
}

Alias.Sprite_Timer_fontSize = Sprite_Timer.prototype.fontSize
Sprite_Timer.prototype.fontSize = function() {
    return this.getCustomFontSize("isForGameTimer") || Alias.Sprite_Timer_fontSize.call(this)
}

/* ------------------------------- WINDOW BASE ------------------------------ */
Alias.Window_Base_initialize = Window_Base.prototype.initialize
Window_Base.prototype.initialize = function(rect) {
    this.initCustomFont()
    Alias.Window_Base_initialize.call(this, rect)
}

Window_Base.prototype.initCustomFont = function() {
    this.customFont = this.findCustomFont()
}

Alias.Window_Base_resetFontSettings = Window_Base.prototype.resetFontSettings
Window_Base.prototype.resetFontSettings = function() {
    Alias.Window_Base_resetFontSettings.call(this)
    this.resetSavedFontChanges()
    this.setCustomFont()
}

Alias.Window_Base_resetTextColor = Window_Base.prototype.resetTextColor
Window_Base.prototype.resetTextColor = function() {
    Alias.Window_Base_resetTextColor.call(this)

    if(this.customFont){
        this.resetCustomFontColors()
    }
}

Window_Base.prototype.setCustomFont = function() {
    this.customFont = this.findCustomFont()

    if(this.customFont){
        this.contents.fontFace = `${this.customFont.face}, ${$gameSystem.mainFontFace()}`
        this.setCustomFontSettings()
    }else{
        this.contents.fontFace = $gameSystem.mainFontFace()
    }
}

Window_Base.prototype.setCustomFontSettings = function() {
    const font = this.customFont
    this.contents.fontSize = font.size || $gameSystem.mainFontSize()
    this.contents.outlineWidth = font.outlineWidth
}

Window_Base.prototype.resetCustomFontColors = function() {
    const font = this.customFont
    this.contents.textColor = font.textColor || ColorManager.normalColor()
    this.contents.outlineColor = font.outlineColor || ColorManager.outlineColor()
}

Window_Base.prototype.findCustomFont = function() {
    const savedFontIndex = this.findSavedFont()
    const defaultIndex = Plugin.getParam().defaultIndex
    
    return Plugin.getParam().fonts[savedFontIndex] || this.findWindowFont() || this.findSceneFont() || Plugin.getParam().fonts[defaultIndex]
}

Window_Base.prototype.findSavedFont = function(){
    const sceneName = SceneManager._scene.constructor.name
    const winName = this.constructor.name

    return Plugin.findSavedFont(sceneName) || Plugin.findSavedFont(winName)
}

Window_Base.prototype.findSceneFont = function(){
    const sceneName = SceneManager._scene.constructor.name
    const fontFace = Plugin.getParam().fonts.find(font => font.sceneList.includes(sceneName))

    return fontFace
}

Window_Base.prototype.findWindowFont = function(){
    const winName = this.constructor.name
    const fontFace = Plugin.getParam().fonts.find(font => font.windowList.includes(winName))

    return fontFace
}

Window_Base.prototype.resetSavedFontChanges = function() {
    if(!Plugin.getParam().saveFontChanges){
        Plugin.removeSavedFont(this.constructor.name)
        Plugin.removeSavedFont(SceneManager._scene.constructor.name)
    }
}

}