Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Jaber's Quest Log v2.1.3

This time I chose to use a book-like format, because it fits better with my new menu-in-the-works than the scroll thing does. The code's a lot cleaner, the quests are easier to manage and organize, and you have -complete- control over the placement of everything in the description.


Features
- Organize your quests into categories!
- Faster loading!
- Less save-bloating!
- Easier quest data organization!
- Multi-page descriptions!
- Quest-specific variables!
- Ability to change font size, color, and name!
- Ability to use icons and pictures in descriptions!
- Greater control over objectives!
- Message codes for displaying various data in your description!
- HOLY CRAP MORE CUSTOMIZATION THAN YOU'LL EVER NEED FOR ANYTHING EVER
- Probably some other stuff that I forgot!
- wakka wakka wakka
- I am a SALAD BOAT
- VROOM VROOOM
- pinecone

Changelog
v.2.1.3
Woops.
Bugfixes:
-Fixed a bug causing the quest display to refresh itself more than necessary.
-Fixed a bug where the category title would be drawn based on all categories in the list instead of based on only active categories.
-Fixed several other bugs caused by the above problem.

v.2.1.2
Bugfixes:
-Fixed a bug where the draw text instruction types would default to the window's default font/size/color instead of the category list's default font/size/color

New stuff:
-Added support for spaces in quest variable names and in the \\s message code
-Confirm button now closes quest window when called directly to a quest (So books and stuff will behave more like a message box)
-Updated demo


Scripts
Ruby:
class Game_System

  

  def load_quest_data

    $data_quests = {}

    #$data_quests["hash key"] = Quest_Data.new(

    # "name", [description code], [objective code], {initial quest variables(optional)})

    $data_quests["fishtalk"] = Quest_Data.new("Talk with Fish",

    [[0, [0, [4, 4], "Cat wants me to ask Fish if"]], [0, [0, [4, 24], "it's ok to eat him."]]],

    [[0, 1, [0, [4, 44], ["I need to get Fish's response.", "Fish said no."]]]])

    $data_quests["cat quest 2"] = Quest_Data.new("Cat's Query",

    [[0, [0, [4, 4], "Cat wants to know how Fish is"]], [0, [0, [4, 24], "breathing outside of water."]],

    [0, [0, [4, 60], "Being a cat, Cat is too damn lazy"]], [0, [0, [4, 80], "to ask Fish himself."]]],

    [])

    $data_quests["cat quest done"] = Quest_Data.new("Lazy Cat",

    [[0, [0, [4, 4], "Cat can ask his own stupid"]], [0, [0, [4, 24], "questions from now on."]]],

    [])

    $data_quests["trees"] = Quest_Data.new("Oh, nuts",

    [[0, [0, [4, 4], "This tree wants me to find"]], [0, [0, [4, 24], "its missing acorns."]],

    [2, [0, [290, 4], [1, 1]]], [0, [0, [310, 260], "A nice enough sort.", nil, 15]],

    [0, [0, [4, 100], "I have found \\qv[nuts found]/5 acorns."]]],

    [[0, 0, [0, [4, 120], ["I should return these to that tree."]]]], {"nuts found" => 0})

    $data_quests["trees done"] = Quest_Data.new("Oh, nuts",

    [[1, [0, [-80, 4], [1, "hat2"]]], [0, [0, [4, 232], "That tree gave me its"]],

    [0, [0, [4, 252], "old 'brocap'."]], [0, [0, [4, 270], "I think I look smashing in it."]]],

    [])

    $data_quests["sign1"] = Quest_Data.new("",

    [[0, [0, [4, 4], "You can call the script directly to a quest,"]],

    [0, [0, [4, 24], "like this sign does. This lets you create"]],

    [0, [0, [4, 44], "books and other media for your game..."]],

    [0, [0, [4, 74], "...such as this sign."]], [0, [0, [4, 120], "You can also skip the category list and"]],

    [0, [0, [4, 140], "jump directly to a category, if you wanted to."]]], [])

  end

  

end
Ruby:
class Quest_Data

  

  attr_accessor :description

  attr_accessor :objectives

  attr_accessor :name

  attr_accessor :data

  

  def initialize(name, description, objectives, data = {})

    @name = name

    @description = description

    @objectives = objectives

    @data = data

  end

  

end

 

class Quest_List_Data

  

  attr_accessor :data

  attr_accessor :stages

  attr_reader   :id

  

  def initialize(quest_id)

    @data = $data_quests[quest_id].data

    @stages = []

    for obj in $data_quests[quest_id].objectives

      @stages.push(obj[1])

    end

    @id = quest_id

  end

  

  def name

    return $data_quests[@id].name

  end

  

  def description

    return $data_quests[@id].description

  end

  

  def objectives

    return $data_quests[@id].objectives

  end

  

end

 

class Quest_List

  

  attr_accessor :quests

  attr_accessor :lists

  attr_accessor :order

  attr_accessor :settings

  

  def initialize

    @quests = {}

    @order = {}

    @lists = {}

    @settings = [1, 2] # Default inventory, default battlers

    @lists['wat'] = Category_List.new

    @lists['wat'].windowskin = "001-Blue01"

    @lists['wat'].categories = [["Not Finished", "list1"], ["Not Not Finished", "Finished"]]

    @lists["signboard"] = Category_List.new

    @lists["signboard"].windowskin = "001-Blue01"

    @lists["signboard"].background = ["terriblesign", -16, -24] # Remember that there's a 16x16 buffer on windows

  end

  

  def has_quest?(quest_id)

    return @quests.include?(quest_id)

  end

  

  def add(quest_id, list_name)

    return if $data_quests[quest_id].nil?

    if @order[list_name].nil?

      @order[list_name] = []

    end

    return if @order[list_name].include?(quest_id)

    @order[list_name].push(quest_id)

    add_quest(quest_id)

  end

  

  def remove(quest_id, list_name)

    return if $data_quests[quest_id].nil?

    return if @order[list_name].nil?

    return if @order[list_name].empty?

    return unless @order[list_name].include?(quest_id)

    @order[list_name].delete(quest_id)

  end

  

  def add_quest(quest_id)

    return if $data_quests[quest_id].nil?

    return if @quests.include?(quest_id)

    @quests[quest_id] = Quest_List_Data.new(quest_id)

  end

  

  def remove_quest(quest_id, erase = false)

    @quests.delete(quest_id) if erase

    for list in @order.keys

      @order[list].delete(quest_id)

    end

  end

  

  def reset_quest(quest_id, create = true)

    return unless @quests.include?(quest_id) if create == false

    @quests.delete(quest_id)

    add_quest(quest_id)

  end

  

  def replace(new_quest, rep_quest, list_name)

    return if new_quest == rep_quest # EASIEST REPLACEMENT EVER

    return if $data_quests[new_quest].nil? or $data_quests[rep_quest].nil?

    return if @order[list_name].nil?

    return if @order[list_name].empty?

    return if @order[list_name].include?(new_quest)

    return unless @order[list_name].include?(rep_quest)

    @order[list_name][@order[list_name].index(rep_quest)] = new_quest

    add_quest(new_quest)

  end

  

  def erase_list(list_name)

    @order.delete(list_name)

  end

  

  def create_list(list_name)

    return unless @order[list_name].nil?

    @order[list_name] = []

  end

  

end

 

class Category_List

  

  attr_accessor :categories

  attr_accessor :title

  attr_accessor :font

  attr_accessor :background

  attr_accessor :windowskin

  attr_accessor :ipp

  attr_accessor :animation

  attr_accessor :empty_text

  attr_accessor :audio

  attr_accessor :formatting

  attr_accessor :page_graphics

  

  def initialize

    # These are the defaults. You have to set them for the category list itself

    # if you want it to be different.

    @title = "Table of Contents"

    # Font [[Title Font, Size, Color], [Category Font, Size, Color]]

    @font = [[Font.default_name, 24, Color.new(0, 0, 0)], [Font.default_name, 20, Color.new(0, 0, 0)]]

    # Background [filename, x offset, y offset]

    @background = ["BookBack2.png", 5, 8]

    @windowskin = "Pengu Speech 1.png"

    # Items per page. Will require adjusting of @formatting if you change it.

    @ipp = 11

    # Animation ID (defined in script)

    @animation = -1

    # Text to display when there are no valid categories

    @empty_text = ""

    # Audio

    @audio = [["Audio/SE/046-Book01", 100, 100], ["Audio/SE/046-Book01", 100, 100],

              ["Audio/SE/046-Book01", 100, 90], ["Audio/SE/046-Book01", 100, 90],

              ["Audio/SE/" + $data_system.cursor_se.name, $data_system.cursor_se.volume, $data_system.cursor_se.pitch],

              ["Audio/SE/046-Book01", 100, 100]]

    # Formatting: [Distance from one page to the next, distance between list items, width of page, offset from top, cursor margin]

    @formatting = [261, 26, 235, 12, 8]

    # Page Graphics: [prevpage, nextpage]

    @page_graphics = ["prevpage.png", "nextpage.png"]

    # Same as before

    @categories = []

  end

  

end
Ruby:
class Quest_Window < Window_Base

  

  attr_reader :close_book

  

  def initialize(x, y, z, list_index, auto = false, mode = [0])

    super(x-16, y-16, 535, 386)

    self.contents = Bitmap.new(width-32, height-32)

    self.contents.font.color = normal_color

    self.z = z

    @list = $game_party.quests.lists[list_index]

    @background = Sprite.new

    @background.bitmap = RPG::Cache.picture(@list.background[0])

    @background.x = self.x + @list.background[1]

    @background.y = self.y + @list.background[2]

    @background.z = self.z - 10

    self.opacity = 0

    @cursor_coord = []

    @index = [0, 0, ""]

    @last_index = -2

    @last_page = 0

    @page = [0,0,0]

    @close_book = false

    @phase = 0

    @mode = mode

    setup_toc

    setup_toc_cursor

    check_mode

    refresh

    update_loop if auto

  end

  

  def update_loop

    loop do

      Graphics.update

      Input.update

      update

      break if @close_book

    end

    dispose

    Input.update

  end

  

  def check_mode

    se = @list.audio[2]

    Audio.se_play(se[0], se[1], se[2])

    case @mode[0]

    when 1 # Directly to category [1, category key, header text]

      @phase = 1

      setup_category_cursor

    when 2 # Directly to quest [2, quest key]

      @phase = 2

    end

  end

  

  def dispose

    @background.dispose

    super

  end

  

  def setup_toc

    @toc = [[]]

    @pagemax = []

    @indexmax = [-1, 0]

    i = 0

    count = 1

    val = -1

    for catg in @list.categories

      val += 1

      next if $game_party.quests.order[catg[1]].nil?

      next if $game_party.quests.order[catg[1]].empty?

      if count > @list.ipp * 2

        count = 0

        i += 1

        @toc.push([])

      end

      @toc[i].push(catg)

      count += 1

      @indexmax[0] += 1

    end

    if @indexmax[0] == -1

      @phase = -1

      @toc[0].push([@list.empty_text])

    end

    @pagemax[0] = i

  end

  

  def setup_questlist

    @indexmax[1] = $game_party.quests.order[@toc[@page[1]][@index[0]][1]].size - 1

    @pagemax[1] = $game_party.quests.order[@toc[@page[1]][@index[0]][1]].size / (@list.ipp * 2)

  end

  

  def update

    if [-1, 0].include?(@phase)

      indexnum = 0

    elsif @phase == 1

      indexnum = 1

    elsif @phase == 2

      indexnum = 2

    end

    if Input.repeat?(Input::DOWN)

      if [0, 1].include?(@phase)

        temp = @index[indexnum] / @list.ipp

        @index[indexnum] += 1

        if @index[indexnum] > @indexmax[indexnum]

          @index[indexnum] -= (@indexmax[indexnum] + 1) % @list.ipp

        elsif @index[indexnum] / @list.ipp != temp

          @index[indexnum] -= @list.ipp

        end

      end

    end

    if Input.repeat?(Input::UP)

      if [0, 1].include?(@phase)

        temp = @index[indexnum] / @list.ipp

        @index[indexnum] -= 1

        if @index[indexnum] < 0 or @index[indexnum] / @list.ipp != temp

          @index[indexnum] = [(@index[indexnum] + @list.ipp), @indexmax[indexnum]].min

        end

      end

    end

    if Input.repeat?(Input::RIGHT)

      if [0, 1].include?(@phase)

        if @index[indexnum] == @indexmax[indexnum]

          @index[indexnum] = 0

        else

          @index[indexnum] += @list.ipp

          @index[indexnum] = @indexmax[indexnum] if @index[indexnum] > @indexmax[indexnum]

        end

      elsif @phase == 2

        @page[2] += 1

        @page[2] = 0 if @page[2] > @pagemax[2]

      end

    end

    if Input.repeat?(Input::LEFT)

      if [0, 1].include?(@phase)

        if @index[indexnum] == 0

          @index[indexnum] = @indexmax[indexnum]

        else

          @index[indexnum] -= @list.ipp

          @index[indexnum] = 0 if @index[indexnum] < 0

        end

      elsif @phase == 2

        @page[2] -= 1

        @page[2] = @pagemax[2] if @page[2] < 0

      end

    end

    if [-1, 0, 1].include?(@phase)

      @page[indexnum] = (@index[indexnum] / (@list.ipp * 2))

    end

    if Input.trigger?(Input::C)

      if @phase == 0

        @phase = 1

        setup_questlist

        setup_category_cursor

        @last_index = -1

        @last_page = - 1

        se = @list.audio[0]

        Audio.se_play(se[0], se[1], se[2])

        return

      elsif @phase == 1

        @phase = 2

        @last_index = -1

        @last_page = - 1

        se = @list.audio[1]

        Audio.se_play(se[0], se[1], se[2])

        return

      elsif @phase == 2 and @mode[0] == 2

        @close_book = true

        se = @list.audio[2]

        Audio.se_play(se[0], se[1], se[2])

        return

      end

    end

    if Input.trigger?(Input::B)

      if [-1, 0].include?(@phase) or (@phase == 1 and @mode[0] == 1) or

                (@phase == 2 and @mode[0] == 2)

        @close_book = true

        se = @list.audio[2]

        Audio.se_play(se[0], se[1], se[2])

        return

      elsif [1, 2].include?(@phase)

        @index[1] = 0 if @phase == 1

        @phase -= 1

        @last_index = -1

        @last_page = - 1

        @page[2] = 0

        se = @list.audio[3]

        Audio.se_play(se[0], se[1], se[2])

        return

      end

    end

    if [0, 1].include?(@phase)

      if @index[indexnum] != @last_index

        unless @page[indexnum] != @last_page or @last_index == -2

          se = @list.audio[4]

          Audio.se_play(se[0], se[1], se[2])

        end

        @last_index = @index[indexnum]

        self.cursor_rect.set(@cursor_coord[indexnum][@index[indexnum]][0], @cursor_coord[indexnum][@index[indexnum]][1], @cursor_coord[indexnum][@index[indexnum]][2],30)

      end

    end

    if @page[indexnum] != @last_page

      unless @last_page == - 1

        se = @list.audio[5]

        Audio.se_play(se[0], se[1], se[2])

        if @page[indexnum] < @last_page

          if @page[indexnum] + 1 < @last_page

            page_left_many

          else

            page_left

          end

        else

          if @page[indexnum] - 1 > @last_page

            page_right_many

          else

            page_right

          end

        end

      end

      @last_page = @page[indexnum]

      refresh

    end

  end

  

  def refresh

    self.contents.clear

    if [-1, 0, 1].include?(@phase)

      if [-1, 0].include?(@phase)

        pagenum = 0

        pagemaxnum = 0

        headertext = @list.title

        loopvals = @toc[@page[0]]

      else

        pagenum = 1

        @pagemax[1] = 0

        pagemaxnum = 1

        if @mode[0] == 1

          headertext = @mode[2]

          loopvals = $game_party.quests.order[@mode[1]]

        else

          headertext = @toc[@page[1]][@index[0]][0]

          loopvals = $game_party.quests.order[@toc[@page[1]][@index[0]][1]]

        end

      end

      offset = @list.formatting[3]

      if @page[pagenum] == 0

        self.contents.font.name = @list.font[0][0]

        self.contents.font.size = @list.font[0][1]

        self.contents.font.color = @list.font[0][2]

        text = headertext.dup

        fontcheck = check_title_codes(text)

        self.contents.font.name = fontcheck[0] unless fontcheck[0].nil?

        self.contents.font.size = fontcheck[1] + 5 unless fontcheck[1].nil?

        self.contents.font.color = fontcheck[2] unless fontcheck[2].nil?

        self.contents.draw_text(0, 0, @list.formatting[2], 32, text, 1)

      end

      y = 0

      x = 0

      for asdf in loopvals

        self.contents.font.name = @list.font[1][0]

        self.contents.font.size = @list.font[1][1]

        self.contents.font.color = @list.font[1][2]

        if @phase == 1

          name = $game_party.quests.quests[asdf].name.dup

        else

          name = asdf[0].dup

        end

        fontcheck = check_title_codes(name)

        self.contents.font.name = fontcheck[0] unless fontcheck[0].nil?

        self.contents.font.size = fontcheck[1] unless fontcheck[1].nil?

        self.contents.font.color = fontcheck[2] unless fontcheck[2].nil?

        y += 1

        if y > @list.ipp

          y = 1

          x += 1

        end

        break if x >= 2

        self.contents.draw_text(x * @list.formatting[0], offset + (y * @list.formatting[1]), @list.formatting[2], 32, name, 1)

      end

      if @page[pagenum] + 1 <= @pagemax[pagemaxnum]

        bitmap = RPG::Cache.picture(@list.page_graphics[1])

        self.contents.blt(self.contents.width - bitmap.width, self.contents.height - bitmap.height, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height))

      end

      if @page[pagenum] > 0

        bitmap = RPG::Cache.picture(@list.page_graphics[0])

        self.contents.blt(0, self.contents.height - bitmap.height, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height))

      end

    elsif @phase == 2

      self.cursor_rect.empty

      draw_description

    end

  end

  

  def setup_toc_cursor

    duck = 0

    @cursor_coord[0] = []

    for cat in @toc

      x = 0

      y = 0

      for dog in cat

        y += 1

        if y > @list.ipp

          y = 1

          x += 1

        end

        if x >= 2

          x = 0

        end

        self.contents.font.name = @list.font[1][0]

        self.contents.font.size = @list.font[1][1]

        self.contents.font.color = @list.font[1][2]

        zebra = dog[0].dup

        fontcheck = check_title_codes(zebra)

        self.contents.font.name = fontcheck[0] unless fontcheck[0].nil?

        self.contents.font.size = fontcheck[1] unless fontcheck[1].nil?

        self.contents.font.color = fontcheck[2] unless fontcheck[2].nil?

        @cursor_coord[0][duck] = [x * @list.formatting[0] + (@list.formatting[2] / 2) - @list.formatting[4] - (self.contents.text_size(zebra).width / 2), @list.formatting[3] + (y * @list.formatting[1]), self.contents.text_size(zebra).width + (@list.formatting[4] * 2)]

        duck += 1

      end

    end

  end

  

  def setup_category_cursor

    x = 0

    y = 0

    moose = 0

    @cursor_coord[1] = []

    if @mode[0] == 1

      loopvals = $game_party.quests.order[@mode[1]]

    else

      loopvals = $game_party.quests.order[@toc[@page[0]][@index[0]][1]]

    end

    for cow in loopvals

      badger = $game_party.quests.quests[cow].name

      y += 1

      if y > @list.ipp

        y = 1

        x += 1

      end

      if x >= 2

        x = 0

      end

      self.contents.font.name = @list.font[1][0]

      self.contents.font.size = @list.font[1][1]

      self.contents.font.color = @list.font[1][2]

      mushroom = badger.dup

      fontcheck = check_title_codes(mushroom)

      self.contents.font.name = fontcheck[0] unless fontcheck[0].nil?

      self.contents.font.size = fontcheck[1] unless fontcheck[1].nil?

      self.contents.font.color = fontcheck[2] unless fontcheck[2].nil?

      @cursor_coord[1][moose] = [x * @list.formatting[0] + (@list.formatting[2] / 2) - @list.formatting[4] - (self.contents.text_size(mushroom).width / 2), @list.formatting[3] + (y * @list.formatting[1]), self.contents.text_size(mushroom).width + (@list.formatting[4] * 2)]

      moose += 1

    end

  end

  

  def check_title_codes(text)

    fn = nil

    fs = nil

    fc = nil

    text.gsub!(/\\[Ff][Nn]\[([0-9]+)\]/) do

      fn = title_fonts($1.to_i)

      ""

    end

    text.gsub!(/\\[Ff][Ss]\[([0-9]+)\]/) do

      fs = $1.to_i

      ""

    end

    text.gsub!(/\\[Ff][Cc]\[([0-9]+),([0-9]+),([0-9]+)\]/) do

      fc = Color.new($1.to_i, $2.to_i, $3.to_i)

      ""

    end

    return [fn, fs, fc]

  end

  

  

  

  def page_left

    

  end

  

  def page_right

    

  end

  

  def page_left_many

    

  end

  

  def page_right_many

    

  end

  

  def title_fonts(type)

    case type

    when 0

      return Font.default_name

    when 1

      return "Verdana"

    end

  end

  

end
Ruby:
class Quest_Window < Window_Base

  

  def draw_description

    case @mode[0]

    when 0

      @index[2] = $game_party.quests.order[@list.categories[@indexvals[@index[0]]][1]][@index[1]]

    when 1

      @index[2] = $game_party.quests.order[@mode[1]][@index[1]]

    when 2

      @index[2] = @mode[1]

    end

    quest = $game_party.quests.quests[@index[2]]

    pages = []

    page_graphics = @list.page_graphics.dup

    for line in quest.description

      pages.push(line[1][0])

      next unless @page[2] == line[1][0]

      case line[0]

      when 0 # Draw Text

        x = line[1][1][0]

        y = line[1][1][1]

        t1 = line[1][2].dup

        fc = line[1][3]

        fs = line[1][4]

        ft = line[1][5]

        fc = @list.font[1][2] if fc.nil?

        fs = @list.font[1][1] if fs.nil?

        ft = @list.font[1][0] if ft.nil?

        self.contents.font.color = fc

        self.contents.font.size = fs

        self.contents.font.name = ft

        t = check_codes(t1)

        h = self.contents.text_size(t).height

        self.contents.draw_text(x, y, 1000, h, t)

      when 1 # Draw Graphic

        x = line[1][1][0]

        y = line[1][1][1]

        w = line[1][1][2]

        h = line[1][1][3]

        o = line[1][1][4]

        w = 1.0 if w.nil?

        h = 1.0 if h.nil?

        o = 255 if o.nil?

        gt = line[1][2][0]

        gn = line[1][2][1]

        if gt == 0

          bitmap = RPG::Cache.icon(gn)

        elsif gt == 1

          bitmap = RPG::Cache.picture(gn)

        end

        self.contents.stretch_blt(Rect.new(x, y, bitmap.width * w, bitmap.height * h), bitmap, Rect.new(0, 0, bitmap.width, bitmap.height), o)

      when 2 # Draw battler

        x = line[1][1][0]

        y = line[1][1][1]

        o = line[1][1][2]

        o = 255 if o.nil?

        if line[1][2][0] == 0

          actor = $game_actors[line[1][2][1]]

        elsif line[1][2][0] == 1

          actor = $data_enemies[line[1][2][1]]

        end

        case $game_party.quests.settings[1]

        when 0 # Jaber's animation system [page, [x, y, opacity], [actor/enemy, id], pose, frame]

          graphic = actor.battle_graphic + actor.stance + line[1][3]

          bitmap = RPG::Cache.battler(graphic, 0)

          self.contents.blt(x - ((bitmap.width / $game_temp.pose_frames(graphic)) / 2), y - bitmap.height, bitmap,

                  Rect.new(((bitmap.width / $game_temp.pose_frames(graphic)) * line[1][4]), 0, bitmap.width / $game_temp.pose_frames(graphic), bitmap.height), o)

          if line[1][2][0] == 0

            equip_graphics = []

            eqind = -1

            for equip in actor.slot_data

              eqind += 1

              equip_data = $game_temp.get_data(actor.equipment[eqind])

              next if equip_data == nil or equip_data.battle_graphic == nil

              hand = eqind == 0 ? "_R" : eqind == 1 ? "_L" : "_"

              equip_pic = actor.battle_graphic + actor.stance + hand + equip_data.battle_graphic + line[1][3]

              equip_graphics.push([equip_data.priority, equip_pic])

            end

            equip_graphics.sort!

            for equip in equip_graphics

              bitmap = RPG::Cache.battler(equip[1], 0)

              if bitmap.nil?

                p equip[1]

                next

              end

              self.contents.blt(x - ((bitmap.width / $game_temp.pose_frames(graphic)) / 2), y - bitmap.height, bitmap,

                  Rect.new(((bitmap.width / $game_temp.pose_frames(graphic)) * line[1][4]), 0, bitmap.width / $game_temp.pose_frames(graphic), bitmap.height), o)

            end

          end

        when 1 # Minkoff's animation system [page, [x, y], [actor/enemy, id], pose#, frame#]

          if line[1][2][0] == 0

            bitmap = RPG::Cache.battlers(actor.battler_name, actor.battler_hue)

            o = MNK_TRANSLUCENCY if MNK_TRANSLUCENT_ACTOR.include?(actor.id)

            if DEFAULT_ACTOR or DEFAULT_ACTOR_ID.include?(actor.id)

              x_div = 1

              y_div = 1

              pose = 0

              frame = 0

            else

              x_div = MNK_FRAMES

              y_div = MNK_POSES

              if MNK_FRAMES_ACTOR != nil and MNK_FRAMES_ACTOR[actor.id] != nil

                x_div = MNK_FRAMES_ACTOR[actor.id]

              end

              if MNK_POSES_ACTOR != nil and MNK_POSES_ACTOR[actor.id] != nil

                y_div = MNK_POSES_ACTOR[actor.id]

              end

              # WHY COULDN'T YOU MAKE THE POSE CRAP EASIER DVV D:

              pose = line[1][3]

              frame = line[1][4]

              case line[1][3]

              when 0

                pose = MNK_APOSE1[actor.id] if MNK_APOSE1[actor.id] != nil

              when 1

                pose = MNK_APOSE2[actor.id] if MNK_APOSE2[actor.id] != nil

              when 2

                pose = MNK_APOSE3[actor.id] if MNK_APOSE3[actor.id] != nil

              when 3

                pose = MNK_APOSE4[actor.id] if MNK_APOSE4[actor.id] != nil

              when 4

                pose = MNK_APOSE5[actor.id] if MNK_APOSE5[actor.id] != nil

              when 5

                pose = MNK_APOSE6[actor.id] if MNK_APOSE6[actor.id] != nil

              when 6

                pose = MNK_APOSE7[actor.id] if MNK_APOSE7[actor.id] != nil

              when 7

                pose = MNK_APOSE8[actor.id] if MNK_APOSE8[actor.id] != nil

              when 8

                pose = MNK_APOSE9[actor.id] if MNK_APOSE9[actor.id] != nil

              when 9

                pose = MNK_APOSE10[actor.id] if MNK_APOSE10[actor.id] != nil

              when 10

                pose = MNK_APOSE11[actor.id] if MNK_APOSE11[actor.id] != nil

              end

              if MNK_FRAMES_PER_POSE[pose] != nil

                x_div = MNK_FRAMES_PER_POSE[pose]

              end

              # I DON'T KNOW HOW THE MNK_POSES_FR_ THING WORKS SORRY

            end

          elsif line[1][2][0] == 1

            bitmap = RPG::Cache.battlers(actor.battler_name, actor.battler_hue)

            o = MNK_TRANSLUCENCY if MNK_TRANSLUCENT_ENEMY.include?(actor.id)

            if DEFAULT_ENEMY or DEFAULT_ENEMY_ID.include?(actor.id)

              x_div = 1

              y_div = 1

              pose = 0

              frame = 0

            else

              x_div = MNK_FRAMES

              y_div = MNK_POSES

              if MNK_FRAMES_ENEMY != nil and MNK_FRAMES_ENEMY[actor.id] != nil

                x_div = MNK_FRAMES_ENEMY[actor.id]

              end

              if MNK_POSES_ENEMY != nil and MNK_POSES_ENEMY[actor.id] != nil

                y_div = MNK_POSES_ENEMY[actor.id]

              end

              pose = line[1][3]

              frame = line[1][4]

              case line[1][3]

              when 0

                pose = MNK_EPOSE1[actor.id] if MNK_EPOSE1[actor.id] != nil

              when 1

                pose = MNK_EPOSE2[actor.id] if MNK_EPOSE2[actor.id] != nil

              when 2

                pose = MNK_EPOSE3[actor.id] if MNK_EPOSE3[actor.id] != nil

              when 3

                pose = MNK_EPOSE4[actor.id] if MNK_EPOSE4[actor.id] != nil

              when 4

                pose = MNK_EPOSE5[actor.id] if MNK_EPOSE5[actor.id] != nil

              when 5

                pose = MNK_EPOSE6[actor.id] if MNK_EPOSE6[actor.id] != nil

              when 6

                pose = MNK_EPOSE7[actor.id] if MNK_EPOSE7[actor.id] != nil

              when 7

                pose = MNK_EPOSE8[actor.id] if MNK_EPOSE8[actor.id] != nil

              when 8

                pose = MNK_EPOSE9[actor.id] if MNK_EPOSE9[actor.id] != nil

              when 9

                pose = MNK_EPOSE10[actor.id] if MNK_EPOSE10[actor.id] != nil

              when 10

                pose = MNK_EPOSE11[actor.id] if MNK_EPOSE11[actor.id] != nil

              end

            end

          end

          self.contents.blt(x, y, bitmap, Rect.new((bitmap.width / x_div) * frame, (bitmap.height / y_div) * pose, bitmap.width / x_div, bitmap.height / y_div), o)

        when 2 # Default battlers [page, [x, y, opacity], [actor/enemy, id]]

          bitmap = RPG::Cache.battler(actor.battler_name, actor.battler_hue)

          self.contents.blt(x, y, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height), o)

        end

      when 3 # Draw Characterset [page, [x, y, opacity], [type, data], [#frames, #directions, facing, frame]]

        case line[1][2][0] # For type:

        when 0 # Use actor ID, [0, actor id]

          cn = $game_actors[line[1][2][1]].character_name

          ch = $game_actors[line[1][2][1]].character_hue

        when 1 # Use filename, [1, filename, hue number]

          cn = line[1][2][1]

          ch = line[1][2][2]

        end

        x = line[1][1][0]

        y = line[1][1][1]

        o = line[1][1][2]

        o = 255 if o.nil?

        w = line[3][0]

        h = line[3][1]

        d = line[3][2]

        f = line[3][3]

        bitmap = RPG::Cache.character(cn, ch)

        self.contents.blt(x, y, bitmap, Rect.new(x + ((bitmap.width / w) * f), y + ((bitmap.height / h) * d),

                                                  bitmap.width / w, bitmap.height / h), o)

      #

      end

    end

    count = -1

    for line in quest.objectives

      count += 1

      obj = quest.stages[count]

      next if obj == 0

      pages.push(line[2][0])

      next unless @page[2] == line[2][0]

      case line[0]

      when 0 # Draw Text

        x = line[2][1][0]

        y = line[2][1][1]

        t1 = line[2][2][obj-1].dup

        fc = line[2][3]

        fs = line[2][4]

        ft = line[2][5]

        fc = @list.font[1][2] if fc.nil?

        fs = @list.font[1][1] if fs.nil?

        ft = @list.font[1][0] if ft.nil?

        self.contents.font.color = fc

        self.contents.font.size = fs

        self.contents.font.name = ft

        t = check_codes(t1)

        h = self.contents.text_size(t).height

        self.contents.draw_text(x, y, 1000, h, t)

      when 1 # Draw Graphic

        x = line[2][1][0]

        y = line[2][1][1]

        w = line[2][1][2]

        h = line[2][1][3]

        o = line[2][1][4]

        w = 1.0 if w.nil?

        h = 1.0 if h.nil?

        o = 255 if o.nil?

        gt = line[2][2][obj-1][0]

        gn = line[2][2][obj-1][1]

        if gt == 0

          bitmap = RPG::Cache.icon(gn)

        elsif gt == 1

          bitmap = RPG::Cache.picture(gn)

        end

        self.contents.stretch_blt(Rect.new(x, y, bitmap.width * w, bitmap.height * h), bitmap, Rect.new(0, 0, bitmap.width, bitmap.height), o)

      when 2 # Draw battler

        x = line[2][1][0]

        y = line[2][1][1]

        o = line[1][1][2]

        o = 255 if o.nil?

        if line[2][2][obj-1][0] == 0

          actor = $game_actors[line[2][2][obj-1][1]]

        elsif line[2][2][obj-1][0] == 1

          actor = $data_enemies[line[2][2][obj-1][1]]

        end

        case $game_party.quests.settings[1]

        when 0 # Jaber's animation system

          graphic = actor.battle_graphic + actor.stance + line[2][3][obj-1]

          bitmap = RPG::Cache.battler(graphic, 0)

          self.contents.blt(x - ((bitmap.width / $game_temp.pose_frames(graphic)) / 2), y - bitmap.height, bitmap,

                Rect.new(((bitmap.width / $game_temp.pose_frames(graphic)) * line[2][4][obj-1]), 0, bitmap.width / $game_temp.pose_frames(graphic), bitmap.height), o)

          if line[1][1][obj-1][0] == 0

            equip_graphics = []

            eqind = -1

            for equip in actor.slot_data

              eqind += 1

              equip_data = $game_temp.get_data(actor.equipment[eqind])

              next if equip_data == nil or equip_data.battle_graphic == nil

              hand = eqind == 0 ? "_R" : eqind == 1 ? "_L" : "_"

              equip_pic = actor.battle_graphic + actor.stance + hand + equip_data.battle_graphic + line[2][3][obj-1]

              equip_graphics.push([equip_data.priority, equip_pic])

            end

            equip_graphics.sort!

            for equip in equip_graphics

              bitmap = RPG::Cache.battler(equip[1], 0)

              if bitmap.nil?

                p equip[1]

                next

              end

              self.contents.blt(x - ((bitmap.width / $game_temp.pose_frames(graphic)) / 2), y - bitmap.height, bitmap,

                  Rect.new(((bitmap.width / $game_temp.pose_frames(graphic)) * line[2][4][obj-1]), 0, bitmap.width / $game_temp.pose_frames(graphic), bitmap.height), o)

            end

          end

        when 1 # Minkoff's animation system [page, [x, y], [actor/enemy, id], pose#, frame#]

          if line[1][2][obj-1][0] == 0

            bitmap = RPG::Cache.battlers(actor.battler_name, actor.battler_hue)

            o = MNK_TRANSLUCENCY if MNK_TRANSLUCENT_ACTOR.include?(actor.id)

            if DEFAULT_ACTOR or DEFAULT_ACTOR_ID.include?(actor.id)

              x_div = 1

              y_div = 1

              pose = 0

              frame = 0

            else

              x_div = MNK_FRAMES

              y_div = MNK_POSES

              if MNK_FRAMES_ACTOR != nil and MNK_FRAMES_ACTOR[actor.id] != nil

                x_div = MNK_FRAMES_ACTOR[actor.id]

              end

              if MNK_POSES_ACTOR != nil and MNK_POSES_ACTOR[actor.id] != nil

                y_div = MNK_POSES_ACTOR[actor.id]

              end

              pose = line[1][3][obj-1]

              frame = line[1][4][obj-1]

              case line[1][3]

              when 0

                pose = MNK_APOSE1[actor.id] if MNK_APOSE1[actor.id] != nil

              when 1

                pose = MNK_APOSE2[actor.id] if MNK_APOSE2[actor.id] != nil

              when 2

                pose = MNK_APOSE3[actor.id] if MNK_APOSE3[actor.id] != nil

              when 3

                pose = MNK_APOSE4[actor.id] if MNK_APOSE4[actor.id] != nil

              when 4

                pose = MNK_APOSE5[actor.id] if MNK_APOSE5[actor.id] != nil

              when 5

                pose = MNK_APOSE6[actor.id] if MNK_APOSE6[actor.id] != nil

              when 6

                pose = MNK_APOSE7[actor.id] if MNK_APOSE7[actor.id] != nil

              when 7

                pose = MNK_APOSE8[actor.id] if MNK_APOSE8[actor.id] != nil

              when 8

                pose = MNK_APOSE9[actor.id] if MNK_APOSE9[actor.id] != nil

              when 9

                pose = MNK_APOSE10[actor.id] if MNK_APOSE10[actor.id] != nil

              when 10

                pose = MNK_APOSE11[actor.id] if MNK_APOSE11[actor.id] != nil

              end

              if MNK_FRAMES_PER_POSE[pose] != nil

                x_div = MNK_FRAMES_PER_POSE[pose]

              end

            end

          elsif line[1][2][obj-1][0] == 1

            bitmap = RPG::Cache.battlers(actor.battler_name, actor.battler_hue)

            o = MNK_TRANSLUCENCY if MNK_TRANSLUCENT_ENEMY.include?(actor.id)

            if DEFAULT_ENEMY or DEFAULT_ENEMY_ID.include?(actor.id)

              x_div = 1

              y_div = 1

              pose = 0

              frame = 0

            else

              x_div = MNK_FRAMES

              y_div = MNK_POSES

              if MNK_FRAMES_ENEMY != nil and MNK_FRAMES_ENEMY[actor.id] != nil

                x_div = MNK_FRAMES_ENEMY[actor.id]

              end

              if MNK_POSES_ENEMY != nil and MNK_POSES_ENEMY[actor.id] != nil

                y_div = MNK_POSES_ENEMY[actor.id]

              end

              pose = line[1][3][obj-1]

              frame = line[1][4][obj-1]

              case line[1][3][obj-1]

              when 0

                pose = MNK_EPOSE1[actor.id] if MNK_EPOSE1[actor.id] != nil

              when 1

                pose = MNK_EPOSE2[actor.id] if MNK_EPOSE2[actor.id] != nil

              when 2

                pose = MNK_EPOSE3[actor.id] if MNK_EPOSE3[actor.id] != nil

              when 3

                pose = MNK_EPOSE4[actor.id] if MNK_EPOSE4[actor.id] != nil

              when 4

                pose = MNK_EPOSE5[actor.id] if MNK_EPOSE5[actor.id] != nil

              when 5

                pose = MNK_EPOSE6[actor.id] if MNK_EPOSE6[actor.id] != nil

              when 6

                pose = MNK_EPOSE7[actor.id] if MNK_EPOSE7[actor.id] != nil

              when 7

                pose = MNK_EPOSE8[actor.id] if MNK_EPOSE8[actor.id] != nil

              when 8

                pose = MNK_EPOSE9[actor.id] if MNK_EPOSE9[actor.id] != nil

              when 9

                pose = MNK_EPOSE10[actor.id] if MNK_EPOSE10[actor.id] != nil

              when 10

                pose = MNK_EPOSE11[actor.id] if MNK_EPOSE11[actor.id] != nil

              end

            end

          end

          self.contents.blt(x, y, bitmap, Rect.new((bitmap.width / x_div) * frame, (bitmap.height / y_div) * pose, bitmap.width / x_div, bitmap.height / y_div), o)          

        when 2 # Default battlers

          bitmap = RPG::Cache.battler(actor.battler_name, actor.battler_hue)

          self.contents.blt(x, y, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height), o)

        end

      when 3 # Draw Characterset

        case line[1][2][obj-1][0]

        when 0 # Use actor ID

          cn = $game_actors[line[1][2][obj-1][1]].character_name

          ch = $game_actors[line[1][2][obj-1][1]].character_hue

        when 1 # Use filename

          cn = line[1][2][obj-1][1]

          ch = line[1][2][obj-1][2]

        end

        x = line[1][1][0]

        y = line[1][1][1]

        o = line[1][1][2]

        o = 255 if o.nil?

        w = line[3][0][obj-1]

        h = line[3][1][obj-1]

        d = line[3][2][obj-1]

        f = line[3][3][obj-1]

        bitmap = RPG::Cache.character(cn, ch)

        self.contents.blt(x, y, bitmap, Rect.new(x + ((bitmap.width / w) * f), y + ((bitmap.height / h) * d),

                                                  bitmap.width / w, bitmap.height / h), o)

      #

      end

    end

    @pagemax[2] = pages.max

    if @page[2] + 1 <= @pagemax[2]

      bitmap = RPG::Cache.picture(page_graphics[1])

      self.contents.blt(self.contents.width - bitmap.width, self.contents.height - bitmap.height, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height))

    end

    if @page[2] > 0

      bitmap = RPG::Cache.picture(page_graphics[0])

      self.contents.blt(0, self.contents.height - bitmap.height, bitmap, Rect.new(0, 0, bitmap.width, bitmap.height))

    end

  end

  

  def check_codes(text)

    text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }

    text.gsub!(/\\[Ss]\[([0-9]+),([\w\s]*),([\w\s]*)\]/) { $game_switches[$1.to_i] == true ? $2 : $3 }

    text.gsub!(/\\[Gg]/) { $game_party.gold }

    text.gsub!(/\\[Qq][Vv]\[([\w\s]*)\]/) { $game_party.quests.quests[@index[2]].data[$1] }

    text.gsub!(/\\[Ii][Tt][Ee][Mm]\[([0-9]+)\]/) { $data_items[$1.to_i].name }

    text.gsub!(/\\[Ww][Ee][Aa][Pp][Oo][Nn]\[([0-9]+)\]/) { $data_weapons[$1.to_i].name }

    text.gsub!(/\\[Aa][Rr][Mm][Oo][Rr]\[([0-9]+)\]/) { $data_armors[$1.to_i].name }

    text.gsub!(/\\[Ss][Kk][Ii][Ll][Ll]\[([0-9]+)\]/) { $data_skills[$1.to_i].name }

    text.gsub!(/\\[Aa][Cc][Tt][Oo][Rr]\[([0-9]+)\]/) { $data_actors[$1.to_i].name }

    text.gsub!(/\\[Ee][Nn][Ee][Mm][Yy]\[([0-9]+)\]/) { $data_enemies[$1.to_i].name }

    text.gsub!(/\\[Cc][Ll][Aa][Ss][Ss]\[([0-9]+)\]/) { $data_classes[$1.to_i].name }

    text.gsub!(/\\[Aa][Cc][Ll][Aa][Ss][Ss]\[([0-9]+)\]/) { $data_classes[$game_actors[$1.to_i].class_id].name }

    case $game_party.quests.settings[0]

    when 0 # For my inventory grid [mode, bag index, type, id]

      text.gsub!(/\\[Hh][Ee][Ll][Dd]\[([01]),([0-9]+),([0-9]+),([0-9]+)\]/) do

        if $1.to_i == 0 # Use $game_party

          case $2.to_i

          when 0 # Party item bag

            $game_party.item_bag.item_amount([$3.to_i, $4.to_i]).to_s

          else

            $game_party.actors[$2.to_i].item_bag.item_amount([$3.to_i, $4.to_i]).to_s

          end

        elsif $1.to_i == 1 # Use $game_actors

          $game_actors[$2.to_i].item_bag.item_amount([$3.to_i, $4.to_i]).to_s

        end

      end

    when 1 # For everyone else's less insane inventory systems [type, id]

      text.gsub!(/\\[Ii][Hh][Ee][Ll][Dd]\[([012]),([0-9]+)\]/) do

        case $1.to_i

        when 0 # Items

          $game_party.item_number($2.to_i).to_s

        when 1 # Weapons

          $game_party.weapon_number($2.to_i).to_s

        when 2 # Armor

          $game_party.armor_number($2.to_i).to_s

        end

      end

    end

    text.gsub!(/\\[Ss][Tt][Aa][Tt]\[([012]),([0-9]+),(\w*)\]/) do

      case $1.to_i

      when 0

        chara = $game_party.actors[$2.to_i]

      when 1

        chara = $game_actors[$2.to_i]

      when 2

        chara = $data_enemies[$2.to_i]

      end

      case $3

      when "hp"

        chara.hp.to_s

      when "maxhp"

        chara.maxhp.to_s

      when "sp"

        chara.sp.to_s

      when "maxsp"

        chara.maxsp.to_s

      when "bmaxhp"

        chara.base_maxhp.to_s

      when "bmaxsp"

        chara.base_maxsp.to_s

      when "atk"

        chara.base_atk.to_s

      when "str"

        chara.base_str.to_s

      when "int"

        chara.base_int.to_s

      when "dex"

        chara.base_dex.to_s

      when "agi"

        chara.base_agi.to_s

      when "pdef"

        chara.base_pdef.to_s

      when "mdef"

        chara.base_mdef.to_s

      when "eva"

        chara.base_eva.to_s

      # Don't use any of the following or your game will asplode.

      when "tp"

        chara.tp.to_s

      when "atk0"

        chara.base_atk(0).to_s

      when "atk1"

        chara.base_atk(1).to_s

      when "dmg0"

        chara.basedmg(0).to_s

      when "dmg1"

        chara.basedmg(1).to_s

      when "mdmg0"

        chara.magdmg(0).to_s

      when "mdmg1"

        chara.magdmg(1).to_s

      when "acc"

        chara.base_acc.to_s

      when "altdmg0"

        chara.altbasedmg(0).to_s

      when "altdmg1"

        chara.altbasedmg(1).to_s

      when "delay"

        chara.delay.to_s

      when "matk0"

        chara.base_matk(0).to_s

      when "matk1"

        chara.base_matk(1).to_s

      when "macc"

        chara.base_macc.to_s

      else

        ""

      end

    end

    

    return text

  end

  

end

Setup
Here's a few pictures for you to use for the background:
Book graphic
First version of the book graphic in blinding white (Size is off by like 1 pixel)

And here's some crappy next/previous page pictures:
25gqkuw.png
20semnq.png


Alright, onto the setup.
In Scene_Title, locate the following line:
$game_system = Game_System.new
In the default title, it should be on line 32.
Add this line right below it:
$game_system.load_quest_data

Next, stick the following anywhere below Game_Party:
Code:
class Game_Party

  

  attr_accessor :quests

  

  alias eveningguvnr initialize

  def initialize

    eveningguvnr

    @quests = Quest_List.new

  end

  

end

To call the quest window, simply use
Quest_Window.new(x, y, z, list key, selfupdate, mode)
x, y, and z are the coordinates, obviously.
Don't know what a list key is? Read the instructions below.
selfupdate and mode are optional.
If selfupdate is set to true, the window will function as it's own scene of sorts, meaning you could, say, call it from an event on the map without interrupting Scene_Map. If you don't know what that means, you'll probably want to have this set to true all the time.
mode is an array that lets you... 'skip' sections of the quest window.
Here's the various settings for it:
[0]
This is the default setting for the mode. It'll open up to the specified list.

[1, category key, headertext]
This will skip the category list and open up a category directly. 'headertext' is what will be displayed at the top of the first page. You still need to specify a list key, as it'll use that for formatting. Useful if you, say... don't want to use the category seperation feature. You'd be able to use a category as the entire quest log, if you wanted.

[2, quest key]
This will skip everything and jump right to a quest. Usefor for things like books or notes laying around.

Instructions
And this is the part where your head explodes. There's a whole crapload of stuff you can do with this, so I'll just go over the features and how to use them.
This is done in the Quest Data script. You can see an example of what the data for a quest will look like. You have complete control over everything displayed on the page when the quest is opened. It doesn't even need to be a quest, you could make some text for books, or put together a wanted poster on a wall, or really anything you can think of.
First, to create your quest, you need to pick out a unique key for it. The example quest uses "test quest". No other quest can have the same key, and you can name it whatever you want so it's more intuitive than just giving them numbers. For this example, let's use "wumpus" as the quest key. You'd start by adding the following line to the load_quest_data method:
$data_quests["wumpus"] = Quest_Data.new()

Now you can begin entering the data for your quest. The first thing to enter is the quest's name. This is what will be displayed ingame. We'll call this quest "Hunt the Wumpus":
$data_quests["wumpus"] = Quest_Data.new("Hunt the Wumpus",

The next two things to enter will be instructions for how the quest will look. See the "Instruction Types" section for detailed info.
The first of the two is the description section. The second of the two is the objective section. You don't need to put description only in the description section, and the objective section doesn't need to be used for objectives. Essentially, the two sections are identical, with one difference: The objective section has a 'stage' variable that you can change in-game to hide the objective or change what it does.
For our wumpus quest, we'll keep it simple and just use the first instruction type to write some text, and leave the objectives section blank:
$data_quests["wumpus"] = Quest_Data.new("Hunt the Wumpus", [[0, [0, [4, 4], "YOU MUST KILL THE WUMPUS"]]], []

The next part is for the quest variables. They don't need to be set up here, and you don't even need add this part. This section exists only to set what variables will start at when the quest is started. We'll leave it blank:
$data_quests["wumpus"] = Quest_Data.new("Hunt the Wumpus", [[0, [0, [4, 4], "YOU MUST KILL THE WUMPUS"]]], [])

And there you go, you've got the data for a simple wumpus-hunting quest set up. Or maybe it's just a note, or a flyer, who knows? You can use this for pretty much any kind of visual media in your game, whether you use the quest log functions or not.
Quests are added to categories, and categories are added to category lists. You call the quest window and tell it what list to use, and it will display any categories in that list that have quests in them.
Even if you decide not to use the quest log functions, you'll still need to set up a list. They contain all the formatting information required by the script.
Here's how to set one up:

First, go to the quest handling script, and scroll down to the Quest_List class. See the '@lists[0] = Category_List.new' line? That's how you make a category list. There's more to it than that, though. That 0 is the list key. Like the quest key, it's a unique identifier for this particular list.
Now you have a number of different things you can customize for the list, the first of which being the categories it contains.
@lists[0].categories.push(["Category Name", category key])
Will add a category to the list. Category name would, of course, be the name of the category. Category key, just like the quest and list keys, is a unique identifier for a category. However, the categories themselves are not created just by adding them to a list. The list.categories just points towards the categories themselves. Don't worry too much about it, though, because the categories themselves are created automatically when quests are added to them. Any categories without quests in them won't show up, so add whatever categories you'll want to use in the future.

Onto the actual customization portion:
All of the following are accessed the same way, with @lists[key].xxxxxxx, where xxxxx would be the name of the option. So if you wanted to change the title of the list '0' above, you'd use @lists[0].title = ______. Let's begin.
title
This is what shows up at the top of the page where "Table of Contents" is in the screenshots. It's just a string.

font
This contains the default fonts, sizes, and colors for the list. It's set up as
[[Title Font, Size, Color], [List Font, Size, Color]]

background
An array holding the filename of the picture to use, and the x/y offsets for positioning it relative to the text. It's set up as
[filename, x offset, y offset]

windowskin
This is what windowskin the list will use. This pretty much just affects what the cursor will look like. It's just a string.

ipp
This is how many items will appear on each page of the list. If you muck with this, you'll likely have to change the formatting part below. It's an integer.

animation
This will control the page turning animations whenever I get around to making them. Currently it does nothing.

empty_text
This is what will be displayed if you have no categories with quests on the list. It's just a string.

audio
This is an array containing arrays containing the data on what sound effects to play for various things like flipping pages and moving the cursor. I forget how it's set up, but each element of the array is set up as ["Audio/SE/Filename", volume, pitch].
I know audio[2] is for the opening and closing of the list, but I forget the rest. Experiment with it a bit, you'll figure it out.

formatting
This controls the positioning and spacing of the items on the list. It's set up as
[distance between pages, distance between list items, width of one page, offset from top of page, cursor margin]

page_graphics
This is an array holding the filenames of the little arrows in the corner. It's set up as [filename for left arrow, filename for right arrow]



You can check the Category_List class if you need help with how it should be set up. Changing the settings in the actual class will change them for all lists that don't have the options set individually. In other words, they're the defaults.
Alright, you've got some quests set up and a category list set up. So how do you start adding quests and all that stuff?
It's really rather easy once you get the hang of it.
First, I'll explain how the data is handled.
The entries in $data_quests don't contain the actual quest data, they're basically just cookie cutters that display the quest. When you add a quest to a category, it creates an actual data entry for the quest in $game_party.quests.quests. This is where the objective stages and quest variables are stored. You can access them any time in-game by using $game_party.quests.quests[quest key].stages[objective index]
and
$game_party.quests.quests[quest key].data[variable key]

You're probably confused at this point, but it's important to understand that before a quest has an entry in $game_party.quests.quests, it essentially does not exist in your saved data, which means you can't do anything with its objective stages or quest variables until it's been added. There's two ways to do this: You can use the 'add' method to add it to a category, or the 'add_quest' function to create just the quest data. More on that later.

Other than objectives and variables, you won't be able to view any quest that doesn't have an entry in $game_party.quests.quests. If you try to open the quest window directly to such a quest, it will explode.

While you're here, there is one more thing you need to do. See that '@settings = [0, 0]' line? That controls the settings for the message codes and instruction types. Specifically, for the drawing of battlers and the displaying of item quantities.
The first number is for item quantities. 0 is for my item grid system. You'll need to set this to 1 so it'll use the default inventory system. Otherwise, youre game will explode.
The second number is for the type of battlers you're using. 0 is for my animation system, and will make your game explode. Set this to 1 for minkoff's animated battlers, or 2 for the default battlers. Currently there is no code for the display of minkoff battlers, so don't be alarmed if it doesn't do anything yet. It'll be added in the next update.

Back to objectives and variables...
The 'objective index' above points to an objective. 0 would be the first objective, 1 would be the second, and so on.
The variable key is, like all the other keys, an identifier for a variable of the quest. You can only use alphanumeric characters for variable keys. If you use anything else, you won't be able to show the variable in the quest description using the message codes. These variables can be whatever you want, you could have say... a "cats ridden" variable that tracks how many cats you've ridden, for example.

It's really simple once you get the hang of it. Not so simple to explain. You'll get the hang of it. Probably.

Anyways, with that out of the way, let's go back to the basics: how to control the quests. There's a number of commands I've made to make it easier, and they handle a lot of the checks and data creation for you.
All are accessed with $game_party.quests._________
Let's begin:
has_quest(quest key)
This will return true if the quest has a data entry. You can use this to check if a quest has been accepted, or to prevent the aforementioned explosion from trying to view a quest with no data entry.

add(quest key, category key)
This will add a quest to a category. It will also create a data entry for the quest if it doesn't already have one. The quest will be viewable from any lists that have the category key in their categories setting.

add_quest(quest key)
This will create a data entry for a quest if it doesn't already have one.

remove(quest key, category key)
This will remove a quest from a category. It will not remove the quest's data entry.

remove_quest(quest key, erase)
This will remove a quest from ALL categories. It will not remove the quest's data entry unless 'erase' is set to true. 'erase' is entirely optional, and not including it is the same as setting it to false.

reset_quest(quest key, create)
This will blank out a quest's variables and objectives, returning them to the default values. It will not remove it from any categories. If 'create' is set to true, this command will create a data entry if called on a quest that doesn't have one. 'create' is optional, and not including it is the same as calling it as true.

replace(new quest, old quest, category key)
This will replace one quest with another on a category. It will take the old quest's spot on the list, so the order will stay the same. It does not touch the quest data at all. Useful for when a quest requires a large update, and you want it to look like the same quest.

erase_list(category key)
This will erase a category. It will not erase any quest data for the quests within. Almost entirely useless, you can use this to veeeeery slightly lower the size of your savefiles by erasing lists that are no longer needed.

create_list(category key)
This will create a category. Entirely useless since this is done automatically whenever it's needed.
For quest layout, that is. Descriptions and objectives use a list of these to put together the quest. For the most part, they're pretty much the same for descriptions and objectives. Objectives just have an added stage variable and a some parts are turned into arrays.
The basic layout for an instruction is as follows:
[type, [data]]
For objectives, there's an added stage variable:
[type, stage, [data]]
'stage' would be whatever you want the stage to start at. 0 is hidden, 1 displays the first entry, 2 displays the second, and so on. Objectives can have as many stages as you want.

And with that, here's the type numbers and data format:
Any options marked with a * are optional.
'page' refers to the pair of pages it will appear on, i.e. 1 would refer to page 3 and 4. This means you can have thigns spanning multiple pages, so you could use it for books and whatnot.
Type 0 - Draw Text
This draws text, obviously.
Descriptions:
[0, [page, [x, y], text, alignment*, color*, size*, font*]]
Objectives:
[0, stage, [page, [x, y], [stage1 text, stage2 text, etc.], alignment*, color*, size*, font*]]
Pretty self-explanatory. The text can make use of message codes, detailed in the 'message codes' section.

Type 1 - Graphic
This displays either an icon or a picture.
Descriptions:
[1, [page, [x, y, zoom_x*, zoom_y*, opacity*], [type, filename]]]
Objectives:
[1, stage, [page, [x, y, zoom_x*, zoom_y*, opacity*], [[stage1 type, stage1 filename], [stage2 type, stage2 filename], [etc., etc.]]]]
'type' is either 0 or 1. 0 will load an icon, 1 will load a picture. zoom_x and zoom_y are multipliers, i.e. a zoom_x of 1.2 will make the image 20% wider.

Type 2 - Draw Battler
This will draw an actor's battler.
For default battlers:
Descriptions:
[2, [page, [x, y, opacity*], [type, id]]]
Objectives:
[2, stage, [page, [x, y, opacity*], [[stage1 type, stage1 id], [stage2 type, stage2 id], etc.]]]
'type' is either 0 or 1. 0 will load actors, 1 will load enemies. ID is the database id.

For Minkoff battlers:
Descriptions:
[2, [page, [x, y, opacity*], [type, id], pose#, frame]]
Objectives:
[2, stage, [page, [x, y, opacity*], [[stage1 type, stage1 id], [stage2 type, stage2 id], etc.], [stage1 pose#, stage2 pose#, etc.], [stage1 frame, stage2 frame, etc.]]]
'type' is either 0 or 1. 0 will load actors, 1 will load enemies. ID is the database id.
If the battler is set up to use a default battler, pose and frame can be skipped.
You can enter an opacity to use, but if the battler is added to MNK_TRANSLUCENT_WHATEVER, then it'll use the MNK_TRANSLUCENCY thingy setting.

Type 3 - Draw Characterset
This will draw a specified character, or an actor's characterset.
Descriptions:
[3, [page, [x, y, opacity*], [type, data], [frames, directions, facing, frame#]]]
Objectives:
[3, stage, [page, [x, y, opacity*], [[stage1 type, stage1 data], [stage2 type, stage2 data], [etc., etc.]], [[stage1 frames, directions, facing, frame#], [stage 2 frames, directions, facing, frame#], etc.]]]
'type' is either 0 or 1. 'data' depends on which type you use:
For type 0, it will use an actor's characterset, formatted like so: [0, actor id]
For type 1, it will use the specified characterset, formatted like so: [1, "filename", hue number]
frames is how many animation frames the characterset has (typically 4)
directions is how many directions the characterset has (typically 4 or 8)
facing is which direction will be displayed. It does not correspond to the actual directions, but to how far down the characterset it is, i.e. on a default 4dir characterset (dirs = [2, 4, 6, 8]), you'd enter 0 for down, 1 for left, 2 for right, and 3 for up.
frame# is what frame of the walking animation will be displayed.
There's three codes for use in quest and category names, and a bunch others for description and objective text. All you do is include the code in the text, and it'll replace it with various things or change various settings.

Quest/Category Name Codes
These control the font for quest and category names. They'll be used in place of the list's default settings. You can use this to, say, use a handwriting-ish font to make it look like a note was scrawled in, or something.
\\fn[number]
This will change the font. You'll have to set up what number goes with what font in the 'title_fonts' method at the very bottom of the Quest Window script.

\\fs[number]
This will change the size of the font.

\\fc[r,g,b]
This will change the color of the font. r, g, b corresponds to red, green, and blue levels.

Description/Objective Codes
These can be used to display a wide variety of data.
\\v[n]
This will display $game_variables[n]

\\s[n,on,off]
This will display the state of $game_switches[n].
If the switch is true, it will display the 'on' text. Otherwise, it will display the 'off' text.
Example: "The gate is \\s[3,open,closed]."
Alphanumerics only, by the way.

\\g
This will display the amount of gold the party has.

\\qv[key]
This will display one of the quest's variables. 'key' would be the variable key, obviously. This is why I suggested only using alphanumerics in the variable keys, as you won't be able to display any that use other characters.

\\item[n]
\\weapon[n]
\\armor[n]
\\skill[n]
\\actor[n]
\\enemy[n]
\\class[n]
These will display the item/skill/class/etc. names. n would be the id.

\\aclass[id]
This will display the name of $game_actor[id]'s class.

\\held[type,id]
This will display the quantity of an item/weapon/armor.
type is 0 for items, 1 for weapons, and 2 for armors. id is, of course, the id.

\\stat[type,id,stat]
This will display an actor/enemy's stats.
For type, enter one of the following:
0: Will use $game_party.actors[id]
1: Will use $game_actors[id]
2: Will use $data_enemies[id]
For id, enter the party index (if you're using type 0), or the database ID.
For stat, you can use any of the following:
hp, maxhp, sp, maxsp, bmaxhp, bmaxsp, atk, str, int, dex, agi, pdef, mdef, eva
It's typed in exactly like that.
For example, \\stat[1,2,bmaxhp] would display Basil's base max hp.
If you look at the code, you'll notice a whole bunch more stats listed. Don't use them or your game will explode.
Also, hp, maxhp, sp, and maxsp will likely not work with enemies.
WELL THAT ONLY TOOK THREE HOURS TO WRITE
...
It's really easy to use, but really hard to understand at first.

If anyone feels like writing a better set of instructions, go for it.

Screenshots
16k9s9w.jpg
Yeah, with 1 quest.
27xdk0p.png
I was testing various things, okay?
t0nwrd.jpg
Battlers, item quantities, and ability to be called from any scene.
vcxonc.png


Demo
Now with several examples of the various things you can do!
(And it still doesn't cover everything possible!)
http://www.mediafire.com/download.php?zj0lm3nj3fk


Terms of Use
You can use it or repost it wherever you want, just make sure to credit me.
If you complain about the images, I will punch you in the face.
If you refuse to try it because you don't like the images and don't feel like making your own, I will punch you again, only harder.
Lastly, I would love to see the kinds of ideas people come up with for this.

Special thanks to DerVVulfman for support, suggestions, and encouraging me to make something that runs outside of Ninja Penguin.
 
I love the look and implentation of this. It's a lot nicer than other quest scripts I've seen (although there aren't that many out there). If I still used RMXP and other people's scripts I'd probably use this.
 
Miss Jaber, this Quest Log of yours can also be converted into a "bestiary"-type or [[Resident Evil-ish File stuff]]. Of course, a few tweaks will make conversion easier ^_^

Good job by the way!

About your old Quest System, I also liked it, almost perfect if the game you're working is on modern to futuristic setting such that instead of books, we have blogs!
 
Wait, I'm actually referring to your old one when the quest background is still a scroll. I wonder if you can still refine it, so that it can be perfectly suitable for games set in modern times.

:boo:
 
That looks pretty neat, actually o_o
Maybe I'll make a verson that uses the new quest formatting with the old layout.
A bestiary is also a pretty neat idea o_o Guess I'll have to go add in an option to display an enemy's battler, too.
 
...what?
The only part of the windowskin it uses is the cursor, and it already supports different windowskins for different category lists >.>
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top