//-----------------------------------------------------------------------------
//  Galv's Message Styles MZ
//-----------------------------------------------------------------------------
//  For: RPGMAKER MV
//  GALV_MessageStylesMZ.js
//-----------------------------------------------------------------------------
//  2020-11-07 - Version 2.1 - added plugin order fix
//  2020-10-18 - Version 2.0 - hopefully fixed bugs with other text commands
//  2020-10-11 - Version 1.9 - fixed another text command issue
//  2020-10-04 - Version 1.8 - fixed issue when using other text commands after
//                             the pop command
//  2020-10-02 - Version 1.7 - fixed position issue when using larger screen
//                             width/height than the UI.
//  2020-09-28 - Version 1.6 - added compatibility with Galv's Cam Control zoom
//  2020-09-26 - Version 1.5 - fixed some code scope issues
//  2020-09-22 - Version 1.4 - added compatibility codes
//  2020-09-19 - Version 1.3 - added ability to add y offset per message
//                             more code updates/improvements
//  2020-09-18 - Version 1.2 - added ability to change message windowskin,
//                             arrow graphics, code updates and improvements,
//                             fixed target x,y bug and changed syntax method
//	                           fixed 'middle' align arrow to be invisible
//  2020-09-17 - Version 1.1 - fixed a bug with the \. and \| wait codes
//  2020-09-16 - Version 1.0 - release
//-----------------------------------------------------------------------------
// Terms can be found at:
// galvs-scripts.com
//-----------------------------------------------------------------------------

var Imported = Imported || {};
Imported.Galv_MessageStyles = true;

var Galv = Galv || {}; // Galv's main object
Galv.Mstyle = Galv.Mstyle || {}; // Galv's stuff
Galv.Mstyle.pluginName = "GALV_MessageStylesMZ";

//-----------------------------------------------------------------------------
/*:
 * @plugindesc (v.2.1) 'Show Text' windows float above characters and change visuals during game.
 * @url http://galvs-scripts.com
 * @target MZ
 * @author Galv
 * @orderAfter GALV_MessageTimerMZ
 *
 * @param iIndicator
 * @text Input Indicator Position
 * @desc pos,x,y - pos is a direction number (numpad). 1,2,3,4,6,7,8,9.
 * @default 2,0,-12
 *
 * @param mPadding
 * @text Message Padding
 * @desc Adds padding around the text in the message box... top,right,bottom,left.
 * @default 0,0,0,0
 *
 * @param invertPos
 * @text Invert Floating Message
 * @type boolean
 * @default false
 * @desc When showing a floating message, displaying window position 'Bottom' will instead be top and vice verca.
 *
 * @param aGraphic
 * @text Arrow Graphic
 * @desc Image from /img/system/ that is used to point at the target of a floating message box. Leave blank for none.
 * @default WindowArrow
 *
 * @param yOffset
 * @text Default Y Offset
 * @desc How many pixels above the event/actor the message box will appear.
 * @default 60
 *
 *
 * @command mWindowStyle
 * @text Message Window Style
 * @desc Set the styles for the default message window (not using \pop).
 *
 * @arg windowskin
 * @text Windowskin
 * @default Window
 * @desc The windowskin graphic from /img/system (without extension)
 *
 *
 * @command pWindowStyle
 * @text Pop Window Style
 * @desc Set the styles for the popup message window (when \pop is used).
 *
 * @arg windowskin
 * @text Windowskin
 * @default Window
 * @desc The windowskin graphic from /img/system (without extension).
 *
 * @arg arrowGraphic
 * @text Arrow Graphic
 * @default WindowArrow
 * @dec Change the arrow graphic for the popup window.
 *
 *
 * @command defaultWindowStyle
 * @text Reset Window Styles
 * @desc Changes styles for both windows to default.
 *
 * @help
 *   Galv's Message Styles
 * ----------------------------------------------------------------------------
 * The main purpose of this plugin is to allow your "Show Text" message boxes
 * to have a different style to other windows in the game. The plugin settings
 * have a variety of visual settings you can tweak, and in addition using a
 * text code in Show Text messages will allow you to turn that message into a
 * floating message.
 *
 * NOTE: The use of /{ and \} text commands are not currently supported inside
 * pop message windows.
 *
 * ----------------------------------------------------------------------------
 *   CODE to use inside a SHOW TEXT message event command
 * ----------------------------------------------------------------------------
 * The following code must be put in the first line of a Show Message event
 * command to work.
 *
 *       \pop[t]
 *
 * t = event Id - to target an event on the map
 *     0 to target the event the Show Text command is used in
 *     -1,-2,-3,-4... negative numbers to target followers in those postions
 *     a1,a2,a3, etc... to target a specific actor IF they are a follower. If
 *                      not a follower, the message will not display
 *     x|y to target a SCREEN pixel position.
 *
 * EXAMPLES
 * \pop[23]  // targets event 23
 * \pop[-3]  // targets the 3rd follower in your follower lineup
 * \pop[a8]  // targets actor 8, only if the actor is a follower on the map
 * \pop[500|200] // targets center of message to screen position at
 *               // 500px X and 200px Y
 *
 * OPTIONALLY:
 * Advanced data can be added via the \pop[] text within a message.
 *
 *       \pop[t,y,windowskin,windowarrow]
 *
 * t      = same as above
 * y      = another modifier for y offset in pixels - for taller sprites.
 *          set to 0 to not modify the default y offset
 * windowskin = filename for a different window to use (blank for no change)
 * windowarrow = filename for a different arrow to use (blank for no change)
 *
 * ----------------------------------------------------------------------------
 *   PLUGIN COMMANDS
 * ----------------------------------------------------------------------------
 * There are plugin commands available to change windowskins. When they are
 * used, all messages will use the new settings until they used again to
 * change them back to defaults. These are a work in progress, more features
 * may be added to them.
 *
 */
//-----------------------------------------------------------------------------
//  CODE STUFFS
//-----------------------------------------------------------------------------

// PLUGIN COMMANDS
//-----------------------------------------------------------------------------

PluginManager.registerCommand(
  Galv.Mstyle.pluginName,
  "mWindowStyle",
  (args) => {
    args.index = 0;
    $gameSystem.updateMStyles(args);
  }
);

PluginManager.registerCommand(
  Galv.Mstyle.pluginName,
  "pWindowStyle",
  (args) => {
    args.index = 1;
    $gameSystem.updateMStyles(args);
  }
);

PluginManager.registerCommand(
  Galv.Mstyle.pluginName,
  "defaultWindowStyle",
  (args) => {
    $gameSystem.buildMStyles();
  }
);

Galv.Mstyle.invertPos =
  PluginManager.parameters(Galv.Mstyle.pluginName)["invertPos"] == "true";
Galv.Mstyle.arrow = PluginManager.parameters(Galv.Mstyle.pluginName)[
  "aGraphic"
];
Galv.Mstyle.yOffset = Number(
  PluginManager.parameters(Galv.Mstyle.pluginName)["yOffset"]
);

// If screen is bigger than ui
Galv.Mstyle.screenXOffset = 0;
Galv.Mstyle.screenYOffset = 0;

Galv.Mstyle.indPos = PluginManager.parameters(Galv.Mstyle.pluginName)[
  "iIndicator"
].split(",");
for (let i = 0; i < Galv.Mstyle.indPos.length; i++) {
  Galv.Mstyle.indPos[i] = Number(Galv.Mstyle.indPos[i]);
}

Galv.Mstyle.padding = PluginManager.parameters(Galv.Mstyle.pluginName)[
  "mPadding"
].split(",");
for (let i = 0; i < Galv.Mstyle.padding.length; i++) {
  Galv.Mstyle.padding[i] = Number(Galv.Mstyle.padding[i]);
}

Galv.Mstyle.target = null;
Galv.Mstyle.thisEvent = null;
Galv.Mstyle.refreshOnClose = false;
Galv.Mstyle.tempPopData = {};

Galv.Mstyle.checkTarget = function (text) {
  let target = {};
  let tmp = text.replace(/\\/g, "\x1b");
  tmp = tmp.replace(/\x1b\x1b/g, "\\");
  tmp = tmp.replace(/\x1bV\[(\d+)\]/gi, (_, p1) =>
    $gameVariables.value(parseInt(p1))
  );

  let popData = tmp.match(/\x1bpop\[[^\]]*\]/gi);

  if (popData) {
    const data = popData[0].match(/\[(.*)\]/)[1].split(",");
    const d = data[0].split("|");
    if (!d[1]) {
      // target is an id only
      target.id = d[0];
    } else {
      // target is an x,y
      target.x = d[0];
      target.y = d[1];
    }

    target.extra = []; // additional potential data here
    for (let i = 1; i < data.length; i++) {
      target.extra.push(data[i]);
    }
  }
  return target;
};

Galv.Mstyle.setTarget = function (target) {
  // build temp pop data object
  this.buildTempPopData(target);

  if (target.y) {
    // Target has a Y value, so it's an X,Y object
    this.xyTarget = {
      _x: Number(target.x),
      _y: Number(target.y),
      screenX: function () {
        return this._x;
      },
      screenY: function () {
        return this._y;
      },
    };
    return this.xyTarget;
  } else if (!target.id.contains("a")) {
    // Target is an ID (event or negatives for follower) and NOT and x,y location
    target.id = Number(target.id);
    // event ID or player
    if (target.id >= -1) {
      switch (target.id) {
        case 0:
          return $gameMap.event(this.thisEvent);
          break;
        case -1:
          return $gamePlayer;
          break;
        default:
          return $gameMap.event(target.id);
          break;
      }
    } else {
      // Target is a follower
      const f = Math.abs(target.id);
      if (f > $gameParty.battleMembers().length) {
        // if no follower exists - don't do it!
        return false;
      } else {
        return $gamePlayer._followers.follower(f - 2);
      }
    }
  } else if (target.id.contains("a")) {
    // Target an actor - check if the actor is in the followers
    const actor = $gameActors.actor(Number(target.id.replace("a", "")));
    actorIndex = actor.index();
    if (actorIndex < 0 || actorIndex > $gameParty.battleMembers().length) {
      return false;
    } else {
      const ind = actorIndex - 1;
      return ind < 0 ? $gamePlayer : $gamePlayer._followers.follower(ind);
    }
  }
};

Galv.Mstyle.buildTempPopData = function (target) {
  this.tempPopData = {}; // reset temp data
  this.tempPopData.array = target.extra || []; // array of extra data
  this.processTempPopData();
};

Galv.Mstyle.processTempPopData = function () {
  let data = this.tempPopData.array;
  this.tempPopData.yo = Number(data[0]) || 0;
  this.tempPopData.windowskin = data[1] || "";
  this.tempPopData.windowarrow = data[2] || "";
  // Add more data here if needed
};

Galv.Mstyle.refreshMessageWindows = function () {
  if (SceneManager._scene._messageWindow)
    SceneManager._scene._messageWindow.refreshGraphics();
  if (SceneManager._scene._nameWindow)
    SceneManager._scene._nameBoxWindow.refreshGraphics();
};

Galv.Mstyle.zoomOffset = function (v1, v2) {
  return v1 - v2 - (v1 - v2) * $gameScreen.zoomScale();
};

// GAME SYSTEM
//-----------------------------------------------------------------------------

Galv.Mstyle.Game_System_initialize = Game_System.prototype.initialize;
Game_System.prototype.initialize = function () {
  Galv.Mstyle.Game_System_initialize.call(this);
  this.buildMStyles();
};

Game_System.prototype.buildMStyles = function () {
  const windowskin = "Window";
  const arrow = Galv.Mstyle.arrow;
  this._mStyles = [
    // default message window settings [0]
    { windowskin: windowskin },
    // pop message settings [1]
    { windowskin: windowskin, arrowGraphic: arrow },
  ];
};

Game_System.prototype.updateMStyles = function (args) {
  // update the message style settings
  this._mStyles[args.index] = args;
};

// INTERPRETER
//-----------------------------------------------------------------------------

Galv.Mstyle.Game_Interpreter_command101 = Game_Interpreter.prototype.command101;
Game_Interpreter.prototype.command101 = function (params) {
  const ispop = this._list[this._index + 1].parameters[0].match(/\\pop/i);
  if (ispop) {
    // Is a pop message
    Galv.Mstyle.thisEvent = this._eventId;
    Galv.Mstyle.target = Galv.Mstyle.setTarget(
      Galv.Mstyle.checkTarget(this._list[this._index + 1].parameters[0])
    );

    if (Galv.Mstyle.target == false) {
      while (this.nextEventCode() === 401) {
        // Text data
        this._index++;
      }
      return false;
    }
  } else {
    // Not a pop message
    Galv.Mstyle.thisEvent = null;
    Galv.Mstyle.target = null;
  }
  return Galv.Mstyle.Game_Interpreter_command101.call(this, params);
};

// WINDOW MESSAGE
//-----------------------------------------------------------------------------

Galv.Mstyle.Window_Message_initialize = Window_Message.prototype.initialize;
Window_Message.prototype.initialize = function (rect) {
  Galv.Mstyle.Window_Message_initialize.call(this, rect);
  Galv.Mstyle.screenXOffset = (Graphics.width - Graphics.boxWidth) / 2;
  Galv.Mstyle.screenYOffset = (Graphics.height - Graphics.boxHeight) / 2;
  this.createWindowTail();
};

Window_Message.prototype.refreshGraphics = function () {
  this.loadWindowskin();
  this.contents.clear();
  this.updateTone();
  this.changeWindowDimensions();
  this.createContents();
  this.openness = 0;
  this.createWindowTail();
};

Window_Message.prototype.loadWindowskin = function () {
  Window_Base.prototype.loadPopMessageWindowskin.call(this);
};

Galv.Mstyle.Window_Message_updateClose = Window_Message.prototype.updateClose;
Window_Message.prototype.updateClose = function () {
  if (Galv.Mstyle.refreshOnClose && this.isClosed()) {
    Galv.Mstyle.refreshOnClose = false;
    Galv.Mstyle.refreshMessageWindows();
  }
  Galv.Mstyle.Window_Message_updateClose.call(this);
};

Window_Message.prototype.createWindowTail = function () {
  const arrowName = Galv.Mstyle.tempPopData.windowarrow
    ? Galv.Mstyle.tempPopData.windowarrow
    : $gameSystem._mStyles[1].arrowGraphic;
  if (this._tailSprite) {
    if (this._tailSprite.name != arrowName) {
      this.removeChild(this._tailSprite); // if arrow graphic has changed, remove the sprite to rebuild it.
    } else {
      return; // no need to rebuild the sprite below.
    }
  }
  this._tailSprite = new Sprite();
  this._tailSprite.bitmap = ImageManager.loadSystem(arrowName);
  this._tailSprite.opacity = 0;
  this._tailSprite.anchor.x = 0.5;
  this._tailSprite.name = arrowName;
  this.addChild(this._tailSprite);
};

Galv.Mstyle.Window_Message_startMessage = Window_Message.prototype.startMessage;
Window_Message.prototype.startMessage = function () {
  Galv.Mstyle.Window_Message_startMessage.call(this);
  this.startPopMessageStuff();
};

Window_Message.prototype.startPopMessageStuff = function () {
  this.loadWindowskin(); // load windowskin in case it was changed with plugin command
  this._nameBoxWindow.loadWindowskin();
  this.createWindowTail();
  this.changeWindowDimensions();
  this.refreshDimmerBitmap();
  this.setPopSettings();
  this.createWindowTail();
};

Galv.Mstyle.Window_Message_updatePlacement =
  Window_Message.prototype.updatePlacement;
Window_Message.prototype.updatePlacement = function () {
  if (Galv.Mstyle.target) {
    this.pTarget = Galv.Mstyle.target;
    this.updateFloatPlacement();
  } else {
    this.pTarget = null;
    this.changeWindowDimensions();
    Galv.Mstyle.Window_Message_updatePlacement.call(this);
  }
};

Galv.Mstyle.Window_Message_terminateMessage =
  Window_Message.prototype.terminateMessage;
Window_Message.prototype.terminateMessage = function () {
  Galv.Mstyle.Window_Message_terminateMessage.call(this);
  this.pTarget = null;
  Galv.Mstyle.target = null;
  Galv.Mstyle.thisEvent = null;
};

Galv.Mstyle.Window_Message_update = Window_Message.prototype.update;
Window_Message.prototype.update = function () {
  Galv.Mstyle.Window_Message_update.call(this);
  this.updateFloatPlacement();
};

Window_Message.prototype.setPopSettings = function () {
  // Invert bottom and top if setting is true
  if (Galv.Mstyle.invertPos) {
    if ($gameMessage._positionType == 2) {
      $gameMessage._positionType = 0;
    } else if ($gameMessage._positionType == 0) {
      $gameMessage._positionType = 2;
    }
  }

  // Initial yOffset value
  switch ($gameMessage._positionType) {
    case 1: // MIDDLE
      this.yOffset = -(this.height / 2);
      break;
    case 2: // BOTTOM
      this.yOffset = 15;
      break;
  }
};

Window_Message.prototype.updateFloatPlacement = function () {
  if (this.pTarget == null) return (this._tailSprite.opacity = 0); // If not a floating message, hide tailsprite and stop function
  if (this.openness < 255) this._tailSprite.opacity = 0; // hide tail sprite when not fully open

  // init pos X,Y
  let zx = this.pTarget.screenX() - Galv.Mstyle.screenXOffset;
  let zy = this.pTarget.screenY() - Galv.Mstyle.screenYOffset;

  // compensate for zoomed screen
  const zoomX = Galv.Mstyle.zoomOffset(Graphics.boxWidth / 2, zx);
  const zoomY = Galv.Mstyle.zoomOffset(Graphics.boxHeight / 2, zy);

  let posX = zx - this.width / 2 + zoomX;
  let posY = zy + this.yOffset + Galv.Mstyle.tempPopData.yo + zoomY;

  // set posX
  if (posX + this.width > Graphics.boxWidth) {
    posX = Graphics.boxWidth - this.width;
  } else if (posX < 0) {
    posX = 0;
  }
  this.x = posX;
  this._nameBoxWindow.x = this.x;

  // set posY
  const nameBoxOffset = this._nameBoxWindow._name
    ? this._nameBoxWindow.height
    : 0;

  if (posY + this.height > Graphics.height) {
    // If window would go off bottom of screen
    const maxY = Graphics.height - this.height;
    posY = Math.min(
      maxY,
      this.pTarget.screenY() - Galv.Mstyle.yOffset - this.height
    );
    this.tailPos = 0;
  } else if (posY - nameBoxOffset < 0) {
    // If window would go off top of screen
    posY = Math.max(this.pTarget.screenY() + 15, 0); // position box under when it hits top of screen
    this.tailPos = 2;
  } else {
    this.tailPos = $gameMessage._positionType;
  }

  if ($gameMessage._positionType == 1) this.tailPos = 1; // if set to middle, no tail.

  this.y = posY;
  this._nameBoxWindow.y = posY - nameBoxOffset;

  // Update other stuff
  this.updateOtherMsgWindows();
  this.updateTailSprite();
};

Window_Message.prototype.updateOtherMsgWindows = function () {
  this.updateFloatGoldWindow();
  this.updateFloatChoiceWindow();
};

Window_Message.prototype.updateFloatGoldWindow = function () {
  if (!this._goldWindow) return;
  this._goldWindow.y =
    this._nameBoxWindow.y < this._goldWindow.height
      ? Graphics.boxHeight - this._goldWindow.height
      : 0;
};

Window_Message.prototype.updateFloatChoiceWindow = function () {
  const positionType = $gameMessage.choicePositionType();
  const setY = this.y + this.height;
  if (setY + this._choiceListWindow.height > Graphics.height) {
    // If choice window goes off bottom of screen.
    this._choiceListWindow.y = this.y - this._choiceListWindow.height;
  } else {
    this._choiceListWindow.y = setY;
  }
  switch (positionType) {
    case 0: // left
      this._choiceListWindow.x = this.x;
      break;
    case 1: // middle
      this._choiceListWindow.x =
        this.x + this.width / 2 - this._choiceListWindow.width / 2;
      break;
    case 2: // right
      this._choiceListWindow.x =
        this.x + this.width - this._choiceListWindow.width;
      break;
  }
};

Window_Message.prototype.updateTailSprite = function () {
  if (this.openness > 200) {
    if (this.tailPos == 1) {
      // MID
      this._tailSprite.opacity = 0;
    } else if (this.tailPos == 2) {
      // BOT
      this._tailSprite.y = 2;
      this._tailSprite.scale.y = -1;
      this._tailSprite.opacity += 50;
    } else if (this.tailPos == 0) {
      // TOP
      this._tailSprite.scale.y = 1;
      this._tailSprite.y = this.height - 2;
      this._tailSprite.opacity += 50;
    }
  }

  // compensate for zoomed screen
  const screenX = this.pTarget.screenX() - Galv.Mstyle.screenXOffset;
  const zoomX = Galv.Mstyle.zoomOffset(Graphics.boxWidth / 2, screenX);
  this._tailSprite.x = screenX - this.x + zoomX;
};

Galv.Mstyle.Window_Message_newLineX = Window_Message.prototype.newLineX;
Window_Message.prototype.newLineX = function (textState) {
  const padding = !$gameMessage.faceName() ? Galv.Mstyle.padding[3] : 0;
  return Galv.Mstyle.Window_Message_newLineX.call(this, textState) + padding;
};

Galv.Mstyle.Window_Message_newPage = Window_Message.prototype.newPage;
Window_Message.prototype.newPage = function (textState) {
  Galv.Mstyle.Window_Message_newPage.call(this, textState);
  textState.y += Galv.Mstyle.padding[0];
};

Window_Message.prototype.galvExtraWidths = function () {
  return 0; // For compatibility
};

Window_Message.prototype.galvExtraHeights = function () {
  return 0; // For compatibility
};

Window_Message.prototype.changeWindowDimensions = function () {
  if (this.pTarget != null) {
    Galv.Mstyle.testActive = true;
    let w = 0;
    let h = 0;
    const faceoffset = $gameMessage.faceName()
      ? ImageManager.faceWidth + 25
      : 0;
    const xO = $gameMessage.faceName() ? faceoffset : 8;

    // Calc text width
    for (let i = 0; i < $gameMessage._texts.length; i++) {
      let lineWidth = this.testWidthEx($gameMessage._texts[i]);
      if (w < lineWidth) w = lineWidth;
    }
    w =
      w +
      $gameSystem.windowPadding() * 2 +
      xO +
      Galv.Mstyle.padding[3] +
      Galv.Mstyle.padding[1]; // padding!
    w += this.galvExtraWidths();
    this.width = Math.min(Graphics.boxWidth, w); // can't be wider than the screen!

    // Calc minimum lines
    let minFaceHeight = 0;
    if ($gameMessage._faceName)
      minFaceHeight = ImageManager.faceHeight + $gameSystem.windowPadding() * 2;

    // Calc text height
    let textState = { index: 0 };
    let extraFontHeight = 0;
    const lines = $gameMessage._texts;

    // Dodgy way to modify text line height if the \{ \} text codes are used.
    for (let i = 0; i < lines.length; i++) {
      let up = (lines[i].match(/\\{/g) || []).length;
      let down = (lines[i].match(/\\}/g) || []).length;

      // Height
      extraFontHeight += extraFontHeight + (up - down);
    }
    extraFontHeight *= 24;

    // Escape characters from text
    textState.text = this.convertEscapeCharacters($gameMessage.allText());

    // Build actual height from everything
    const allLineHeight = this.calcTextHeight(textState, true);
    const height =
      allLineHeight + $gameSystem.windowPadding() * 2 + extraFontHeight;
    const minHeight = this.fittingHeight($gameMessage._texts.length);
    this.height = Math.max(height, minHeight, minFaceHeight);
    this.height += Galv.Mstyle.padding[0] + Galv.Mstyle.padding[2];
    this.height += this.galvExtraHeights();
    this.yOffset = -Galv.Mstyle.yOffset - this.height;

    Galv.Mstyle.testActive = false;
    this.otherMStyleCommands(); // stop certain things happening when drawing the text that was used for determining size.
  } else {
    // if this.pTarget is null
    // normal message window
    this.yOffset = 0;
    this.width = this.windowWidth();
    this.height =
      this.fittingHeight(4) + Galv.Mstyle.padding[0] + Galv.Mstyle.padding[2];
    this.x = (Graphics.boxWidth - this.width) / 2;
  }
};

Galv.Mstyle.Window_Message_processEscapeCharacter =
  Window_Message.prototype.processEscapeCharacter;
Window_Message.prototype.processEscapeCharacter = function (code, textState) {
  // if only testing the text for sizes, don't process the characters that pause, etc.
  if (Galv.Mstyle.testActive)
    return Window_Base.prototype.processEscapeCharacter.call(
      this,
      code,
      textState
    );
  Galv.Mstyle.Window_Message_processEscapeCharacter.call(this, code, textState);
};

Window_Message.prototype.otherMStyleCommands = function () {};

Window_Message.prototype.windowWidth = function () {
  return Graphics.boxWidth;
};

Window_Message.prototype.testWidthEx = function (text) {
  return this.textSizeEx(text).width;
};

Galv.Mstyle.Window_Message__refreshPauseSign =
  Window_Message.prototype._refreshPauseSign;
Window_Message.prototype._refreshPauseSign = function () {
  Galv.Mstyle.Window_Message__refreshPauseSign.call(this);
  // indicator graphic to let user know they need to press a button
  let x = 0;
  let y = 0;
  const oX = Galv.Mstyle.indPos[1];
  const oY = Galv.Mstyle.indPos[2];

  this._pauseSignSprite.anchor.y = 0.5;
  this._pauseSignSprite.anchor.x = 0.5;

  const pos = Galv.Mstyle.indPos[0];

  switch (pos) {
    case 1:
      x = oX;
      y = this._height + oY;
      break;
    case 2:
      x = this._width / 2 + oX;
      y = this._height + oY;
      break;
    case 3:
      x = this.width + oX;
      y = this._height + oY;
      break;
    case 4:
      x = oX;
      y = this.height / 2 + oY;
      break;
    case 6:
      x = this.width + oX;
      y = this.height / 2 + oY;
      break;
    case 7:
      x = oX;
      y = oY;
      break;
    case 8:
      x = this._width / 2 + oX;
      y = oY;
      break;
    case 9:
      x = this.width + oX;
      y = oY;
      break;
  }
  this._pauseSignSprite.move(x, y);
};

Galv.Mstyle.Window_Message_convertEscapeCharacters =
  Window_Message.prototype.convertEscapeCharacters;
Window_Message.prototype.convertEscapeCharacters = function (text) {
  text = Galv.Mstyle.Window_Message_convertEscapeCharacters.call(this, text);
  text = text.replace(/\x1bpop\[[^\]]*\]/gi, ""); // Remove it if different characters are present!
  return text;
};

// WINDOW NAMEBOX
//-----------------------------------------------------------------------------

Window_NameBox.prototype.loadWindowskin = function () {
  Window_Base.prototype.loadPopMessageWindowskin.call(this);
};

// WINDOW BASE
//-----------------------------------------------------------------------------

Window_Base.prototype.loadPopMessageWindowskin = function () {
  if (Galv.Mstyle.target) {
    // use the pop settings
    const skin = Galv.Mstyle.tempPopData.windowskin
      ? Galv.Mstyle.tempPopData.windowskin
      : $gameSystem._mStyles[1].windowskin;
    return (this.windowskin = ImageManager.loadSystem(skin));
  } else {
    // use the default settings
    return (this.windowskin = ImageManager.loadSystem(
      $gameSystem._mStyles[0].windowskin
    ));
  }
};
