# CC Face Anime, a script for changing face images in the middle of a message
# by automatic cycling or controlled by message escape codes.
#
# When automatic cycling, images are changed using the same face set in
# a sequence starting from the image chosen in the message.
#
# Example using default settings:
# 0 1 2 3
# 4 5 6 7
#
# 0 = mouth closed
# 1 = mouth open
# 2 = mouth closed again
# 3 = mouth open and blinking
# 4-7 = images for another animation
#
# You can use up to 8 images (a complete face set) in a single loop
#
# Please configure the script to your liking by adjusting the constants
# in CC_FACE_ANIME.
#
# Use these message codes:
# \mc<frames,interval> - Set the number of frames in this animated face loop
#                        and the interval in frames for auto cycling
# \mc<frames>          - Set the number of frames in this animated face loop
# \md                  - Disable auto cycling of face images
# \me                  - Enable auto cycling of face images
# \mf<name,index>      - Change the faceset image to a different file and index
#                        (Note: may lag if the image isn't cached)
# \mf<index>           - Change the faceset image index within the current file
# \m+                  - advance to the next image in the loop
# \m-                  - retard to the previous image in the loop
# \mi[index]           - jump to the index in the loop
#
# The \mc code is normally used at the start of a message to configure the
# faceset animation, but you may use it mid-message to reconfigure on the fly

module CC_FACE_ANIME
  # default number of frames to wait between auto cycling of face images.
  # Use this to adjust the animation speed to suit your image assets.
  # Override with the \mc escape code
  FRAME_INTERVAL = 9
  # default frames per loop, up to 8 (a full face set)
  # Override with the \mc escape code
  FRAMES_PER_LOOP = 4
  # automatically animate all messages with a face image? (true/false)
  # Override with the \md and \me escape codes
  AUTO = true
  # escape code prefix, if you want to replace \m with something else to
  # get around conflicts with other message system scripts.
  ESC_CODE = 'M'
end

class Window_Message < Window_Base
  alias cc_clear_flags clear_flags
  def clear_flags
    cc_clear_flags
    @cc_face_index_offset = 0
    @cc_frame_count = 0
    @cc_face_anime_enabled = CC_FACE_ANIME::AUTO
    @cc_frames_per_loop = CC_FACE_ANIME::FRAMES_PER_LOOP
    @cc_frame_interval = CC_FACE_ANIME::FRAME_INTERVAL
  end
  
  def redraw_face
    contents.clear_rect(0,0,96,96)
    draw_face($game_message.face_name,
      ($game_message.face_index + @cc_face_index_offset) % 8, 0, 0)
  end
  
  alias cc_wait_for_one_character wait_for_one_character
  def wait_for_one_character
    cc_wait_for_one_character
    if @cc_face_anime_enabled and not $game_message.face_name.empty?
      @cc_frame_count += 1
      return unless @cc_frame_count >= @cc_frame_interval
      @cc_frame_count = 0
      @cc_face_index_offset = (@cc_face_index_offset + 1) % @cc_frames_per_loop
      redraw_face
    end
  end
  
  # Escape codes processed as the message is drawn
  alias cc_process_escape_character process_escape_character
  def process_escape_character(code, text, pos)
    if code.upcase == "CCFA"
      function = obtain_escape_param(text)
      # printf("Process escape function %d\n", function)
      case function
      when 0
        # \md - disable auto cycling
        @cc_face_anime_enabled = false
      when 1
        # \me - enable auto cycling
        @cc_face_anime_enabled = true
      when 2
        # \mf - change face image
        text.slice!(/^<([^>]+)>/)
        process_escape_face_anime_change_face($1)
      when 3
        # \mr - reconfigure
        text.slice!(/^<([^>]+)>/)
        process_escape_face_anime_config($1)
        @cc_face_index_offset %= @cc_frames_per_loop
        redraw_face
      when 4
        # \mi - change index
        @cc_face_index_offset = obtain_escape_param(text)
        @cc_frame_count = 0
        redraw_face
      when 5
        # \m+ - next index
        @cc_face_index_offset = (@cc_face_index_offset + 1) % @cc_frames_per_loop
        @cc_frame_count = 0
        redraw_face
      when 6
        # \m- - previous index
        @cc_face_index_offset = (@cc_face_index_offset + @cc_frames_per_loop - 1) % @cc_frames_per_loop
        @cc_frame_count = 0
        redraw_face
      end
    else
      cc_process_escape_character(code, text, pos)
    end
  end

  # Escape codes processed at the start
  alias cc_convert_escape_characters convert_escape_characters
  def convert_escape_characters(text)
    result = cc_convert_escape_characters(text)
    # change friendly sequences for standardised
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}D/i,
                 "\eCCFA[0]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}E/i,
                 "\eCCFA[1]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}F/i,
                 "\eCCFA[2]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}C/i,
                 "\eCCFA[3]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}I/i,
                 "\eCCFA[4]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}\+/i,
                 "\eCCFA[5]")
    result.gsub!(/\e#{CC_FACE_ANIME::ESC_CODE}\-/i,
                 "\eCCFA[6]")
    # print(result)
    return result
  end
  
  def process_escape_face_anime_config(config)
    if config =~ /^\s*(\d+)\s*(,\s*(\d+)\s*)?/
      @cc_frames_per_loop = $1.to_i rescue CC_FACE_ANIME::FRAMES_PER_LOOP
      @cc_frame_interval = $3.to_i rescue CC_FACE_ANIME::FRAME_INTERVAL
    elsif config
      # printf("Unrecognised face animation config '%s'\n", config)
    end
    return "" # consume sequence
  end
  
  def process_escape_face_anime_change_face(config)
    if config =~ /^\s*([^,\s]+)\s*,\s*(\d+)\s*$/
      $game_message.face_name = $1
      $game_message.face_index = $2.to_i
      @cc_face_index_offset = 0
      @cc_frame_count = 0
      redraw_face
    elsif config =~ /^\s*(\d+)\s*$/
      $game_message.face_index = $1.to_i
      @cc_face_index_offset = 0
      @cc_frame_count = 0
      redraw_face
    end
  end
end
[code]