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.

HBGames

Ok, I knew my quest log needed improvement, so a couple days ago I went to fix it up.

HOLY. FUCKING. SHIT.
This thing was the worst piece of coding I had ever friggin seen. I had the description window as a Window_Selectable with the index at -1. I don't know why it had an update_cursor_rect method. The method used to draw the descriptions was long and laggy and stupid, as was the method for making descriptions. I have no idea how this thing didn't time out every time it was called.

So, I basically rewrote the entire thing. It's much cleaner and easier to use, has no limitations for lines of description or anything, much less lag, much easier to setup quests and objectives.
Code:
#-------------------------------------------------------------------------------

# Jaberwocky's Quest Log

#

#  

#   FGSDF

#-------------------------------------------------------------------------------

class Bitmap

  # Draws an outline around the text,

  # both the outline color and the color of the

  # text inside can be anything.

  def draw_text_outline_custom(x, y, wid, hei, text, align, outlinecolor, insidecolor)

    if $qdata.useoutlines == true

      self.font.color = outlinecolor

        draw_text(x + 1,y + 1,wid,hei,text, align)

        draw_text(x + 1,y - 1,wid,hei,text, align)

        draw_text(x - 1,y - 1,wid,hei,text, align)

        draw_text(x - 1,y + 1,wid,hei,text, align)

    end

    self.font.color = insidecolor

    draw_text(x,y,wid,hei,text, align)

  end

end

 

class Scene_Quests

  attr_accessor  :questids

  attr_accessor  :command_window

  attr_accessor  :questswitches

  # QSETUP This is the initialize method.

  # It's where you set up which list will load:

  def initialize(list = 1)

      @quest_index = 0

    @currentlist = list

    # Right here. The format is:

    # when A

    #   $qdata = B.new

    #   @questswitches = $game_temp.C

    #

    # A is the number called in $scene = Scene_Quests.new(Number)

    # B is the class name for the list.

    # C is the variable name for the quest list. Don't put the @ part with it here.

    case list

    when 1

        $qdata = Quest_Data.new

      @questswitches = $game_temp.qupdate

    when 2

      $qdata = Quest_Data2.new

      @questswitches = $game_temp.qupdate2

    end

  end

  

  def main

      # Displays the background pictures:

      @backpic = Sprite.new

      @backpic.bitmap = RPG::Cache.picture("Menuback")

    @backpic.z = 990

    @questback = Sprite.new

      @questback.bitmap = RPG::Cache.picture($qdata.backpicture)

      @questback.z = 991

      # Creates the quest list based on how many quests are active on that list:

      questwin = []

    @questids = []

            # QSETUP This is one of the for branches that will need changing once your game is complete.

            # More about that later.

    for i in 1...10000

      if @questswitches[i][0] == true

        questwin.push($qdata.questname[i])

        @questids.push(i)

      end

    end

    if questwin.size == 0

      questwin.push($qdata.questname[0])

      @questids.push(0)

    end

    @command_window = Window_Qmand.new(182, questwin)

      @command_window.index = @quest_index

      @command_window.opacity = 0

    @command_window.z = 1100

    # This makes the window for the description text and objectives:

      @status_window = Quest.new

      @status_window.x = 160

      @status_window.y = 75

    @status_window.z = 1100

      @status_window.opacity = 0

      Graphics.transition

      loop do

        Graphics.update

        Input.update

        update_command

        if $scene != self

            break

        end

      end

      Graphics.freeze

    @command_window.contents.clear

      @command_window.dispose

    @status_window.contents.clear

      @status_window.dispose

      @backpic.dispose

      @questback.dispose

  end

 

  end

#-------------------------------------------------------------------------------

# Updates the quest data, and switches between lists:

#-------------------------------------------------------------------------------

  def update_command

    if Input.repeat?(Input::UP)

      if @command_window.index == 0

        @command_window.index = @questids.size - 1

      else

        @command_window.index -= 1

      end

      unless @questids.size == 1

        $game_system.se_play($data_system.cursor_se) unless @questids.size == 1

        @status_window.refresh

      end

      end

      if Input.repeat?(Input::DOWN)

      if @command_window.index == @questids.size - 1

        @command_window.index = 0

      else

        @command_window.index += 1

      end

      unless @questids.size == 1

        $game_system.se_play($data_system.cursor_se)

        @status_window.refresh

      end

      end

    if Input.trigger?(Input::B)

      $game_system.se_play($data_system.cancel_se)

      $scene = Scene_Menu.new(4)

      return

    end

  # QSETUP This is where you set up how it switches between lists.

  # If you want to have say, 2 parties, each with different lists,

  # this is where you would set up how it switches between lists.

  # The format is simple:

  # when listnumber

  #   $scene = Scene_Quests.new(list number to switch to)

  #

  # So if lists 1/2 are for the first party, and you want lists 3/4 to be for the second party,

  # You'd just set up list 3 to switch to list 4 and list 4 to switch to list 3.

    if Input.trigger?(Input::LEFT)

    $game_system.se_play($data_system.cursor_se)

    case @currentlist

    when 1

        $scene = Scene_Quests.new(2)

    when 2

      $scene = Scene_Quests.new(1)

    end

    end

    if Input.trigger?(Input::RIGHT)

    $game_system.se_play($data_system.cursor_se)

      case @currentlist

    when 1

        $scene = Scene_Quests.new(2)

    when 2

      $scene = Scene_Quests.new(1)

    end

    end

end

#-------------------------------------------------------------------------------

# This creates the description text and the objectives

# for the the quests in progress. Objectives change colors

# and have an icon next to them.

#-------------------------------------------------------------------------------

class Quest < Window_Base

  def initialize

    super(0, 0, 480, 480)

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

      refresh

  end

 

  def refresh

    self.contents.clear

    y = 0

    for i in 0...$qdata.description[$scene.questids[$scene.command_window.index]].size

      self.contents.draw_text_outline_custom(2, 24 * y, 480, 32, $qdata.description[$scene.questids[$scene.command_window.index]][i],0, $qdata.descoutline, $qdata.desctext)

      y += 1

    end

    for i in 0...$qdata.objectives[$scene.questids[$scene.command_window.index]].size

      y += 1

      if $scene.questswitches[$scene.questids[$scene.command_window.index]][i + 1] == true

        bitmap = RPG::Cache.icon("CompletedIcon")

        self.contents.blt(0, 4 + ( y * 24) , bitmap, Rect.new(0, 0, 18, 18))

        self.contents.draw_text_outline_custom(24, 0 + (y * 24), 456, 24, $qdata.objectives[$scene.questids[$scene.command_window.index]][i], 0, $qdata.compoutline, $qdata.comptext)

      else

        bitmap = RPG::Cache.icon("InProgressIcon")

        self.contents.blt(0, 4 + ( y * 24) , bitmap, Rect.new(0, 0, 18, 18))

        self.contents.draw_text_outline_custom(24, 0 + (y * 24), 456, 24, $qdata.objectives[$scene.questids[$scene.command_window.index]][i], 0, $qdata.incompoutline, $qdata.incomptext)

      end

    end

  end

  

end

 

#-------------------------------------------------------------------------------

# This is for the list of quests on the left:

#-------------------------------------------------------------------------------

class Window_Qmand < Window_Selectable

  def initialize(width, commands)

      super(-10, 50, width, 380)

    self.contents = Bitmap.new(width - 32, commands.size * 32)

      @commands = commands

    @item_max = @commands.size

    self.index = 0

      refresh

  end

  

  def refresh

      self.contents.clear

      for i in [email=0...@commands.size]0...@commands.size[/email]

        self.contents.draw_text_outline_custom(0, 32 * i, self.contents.width, 32,@commands[i],1, $qdata.menuoutline, $qdata.menutext)

      end

  end

  

end

 

class Game_Temp

  # QSETUP This is where you add the variables that control the quests on the lists.

  attr_accessor :qupdate

  attr_accessor :qupdate2

  # You'll need one of these for every list. The script is setup by default to

  # use qupdate for the first list and qupdate2 for the second.

  #You can change these if you want.

  alias asdfghjkl initialize

  def initialize

    asdfghjkl

    # You'll need to add any new quest variables here, like this:

    @qupdate = []

    @qupdate2 = []

    for i in 0...10000

      # And here, too, like this:

      @qupdate[i] = []

      @qupdate2[i] = []

    end

    # That 10000 there is the maximum number of quests per list.

    # Once your game is completely finished, count the number of quests on each list.

    # There'll be a for loop like this in each of the quest lists.

    # Replace the 10000 there with the number of quests on the list.

    # This will lower the amount of time it takes to read the list.

    # Do the same to the 10000 both here and in the main method up at the top,

            # with the highest number of quests your lists have.

  end

 

end

 

class Scene_Save < Scene_File

  

  alias qwertyuiop write_save_data

  def write_save_data(file)

    qwertyuiop(file)

    # QSETUP You'll need to add any new quest variables here, too, like this:

    Marshal.dump($game_temp.qupdate, file)

    Marshal.dump($game_temp.qupdate2, file)

  end

 

end

 

class Scene_Load < Scene_File

 

  alias zxcvbnm read_save_data

  def read_save_data(file)

    zxcvbnm(file)

    # QSETUP Also need to add any new quest variable here, like this:

    $game_temp.qupdate = Marshal.load(file)

    $game_temp.qupdate2 = Marshal.load(file)

  end

 

end
You'll need to set the script up to display the lists. Press CTRL+F and search for QSETUP.

Code:
#-------------------------------------------------------------------------------

# This class holds all the data for the quests.

# If you want a new quest, add it in here.

# This is the class name. If you add another list, you need a different class name.

# It's a good idea to just use Quest_Data2/3/4/5/6/etc...

class Quest_Data

  attr_accessor :description, :questname, :objectives,

                :useoutlines, :descoutline, :desctext, :incompoutline, 

                :incomptext, :compoutline, :comptext, :menuoutline,

                :menutext, :backpicture

  def initialize

    @questname = []

    @description = []

    @objectives = []

    for i in 0...10000

      @description[i] = []

      @objectives[i] = []

    end

# These are options you can change:

# These control the colors of the text.

# The code for this is:

# Color.new(Amount of Red, Amount of Green, Amount of Blue, Opacity)

# Each of these can be set from 0-255, 255 being the highest.

@useoutlines = true# Set to false if you don't want the text to have an outline

@descoutline = Color.new (0, 0, 0, 255)# Outline color for description text

@desctext = Color.new (255, 255, 255, 255)# Text color for description text

@incompoutline = Color.new(0, 0, 0, 255)# Outline color for incomplete objectives

@incomptext = Color.new(255, 0, 0, 255)# Text color for incomplete objectives

@compoutline = Color.new(0, 0, 0, 255)# Outline color for completed objectives

@comptext = Color.new(0, 255, 0, 255)# Text color for completed objectives

@menuoutline = Color.new(0, 0, 0, 255)# Outline color the in progress list

@menutext = Color.new(255, 255, 255, 255)# Text color for the in progress list

#-------------------------------------------------------------------------------

# This is the filename of the background picture for quests in progress:

@backpicture = "InProgressQuestScroll"

# It needs to be placed in the Graphics/Pictures folder.

#-------------------------------------------------------------------------------

# This is the data that is displayed when there are no quests active.

# I'll be using it to explain how to set up a quest, too:

    @questname[0] = "No Quests" # This will be the name of your quest.

#   This is the description for the quest. The format is:

#   @description[quest number] = ["line 1", "line 2", "line 3", "etc..."]

#   Note that if you have too many lines of description you can run out of room

#   for objectives.

    @description[0] = ["I am not currently on any quests."]

#   The format is the same for @objectives if the quest has any.

#-------------------------------------------------------------------------------

    # Quest 1

    @questname[1] = "Get some rest!"

    @description[1] = ["Even with 2 years of training,",

                       "I was unable to best Pengzoda...",

                       "Why has he shown himself after all this time?",

                       "What are these 'things at work' he spoke of?",

                       "Why did he spare my life a second time?",

                       "...Not that I'm complaining about that one...", " ",

                       "These are questions for another time.",

                       "Right now I need to make it back to my house",

                       "and rest so I can recover from this injury."]

    @objectives[1] = ["-Make it back to  your house",

                      "-Rest so that your wound can recover"]

    

  end

end
The way quests work now is much, MUCH easier.
@questname[Quest Number] = "Name of Quest"
@description[Quest Number] = ["line 1", "line 2", "line 3", "etc"]
The description needs to be in an array, even if it's just 1 line. Same goes for objectives.
@objectives[Quest Number] = ["objective 1", "objective2", "etc"]

...Wait, that's it? Yep. No desclines/objlines/BREAKLINE/line limits/having to add a blank description line/etc.
You don't need to add any objectives, either. Note that this is just one list. To make the completed quest list, just copy/paste this again, change the class name to Quest_Data2, and set it up accordingly.

Activating quests is easier, too. qupdate is set up differently now.
$game_temp.qupdate[Quest Number][Objective Number] = true
For objective number, setting 0 to true will show the quest on the list. 1 and up are the objectives for the quest.


You'll notice I only included the script for the first list.
This is your test. The script is set by default to use Quest_Data2 for the completed quest lists.
If you follow the instructions, you'll have no problem here. If you don't, you're too stupid to be using scripts.



DerVVulfman made this small edit of the default menu that adds in a Quest Log option:
Code:
#-------------------------------------------------------------------------------

# This rewrite of Scene_Main just adds the Quests option into the menu, and it

# makes the number of menu features longer.

#

# I did not edit any other window in the system, so you will see the QUIT option

# print overtop of the Game Time window in the screen.  I merely wanted to show

# how to call the Quest Window from a menu or script.

#-------------------------------------------------------------------------------

 

 

#==============================================================================

# ** Scene_Menu

#------------------------------------------------------------------------------

#  This class performs menu screen processing.

#==============================================================================

 

class Scene_Menu

  #--------------------------------------------------------------------------

  # * Main Processing

  #--------------------------------------------------------------------------

  def main

    # Make command window

    s1 = $data_system.words.item

    s2 = $data_system.words.skill

    s3 = $data_system.words.equip

    s4 = "Status"

    # Changed the s5 from Save to Quests, added an s7 to make the list longer

    s5 = "Quests"

    s6 = "Save"

    s7 = "End Game"

    # Added the s7 to the command window

    @command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6, s7])

    @command_window.index = @menu_index

    # If number of party members is 0

    if $game_party.actors.size == 0

      # Disable items, skills, equipment, and status

      @command_window.disable_item(0)

      @command_window.disable_item(1)

      @command_window.disable_item(2)

      @command_window.disable_item(3)

    end

    # Make play time window

    @playtime_window = Window_PlayTime.new

    @playtime_window.x = 0

    @playtime_window.y = 224

    # Make steps window

    @steps_window = Window_Steps.new

    @steps_window.x = 0

    @steps_window.y = 320

    # Make gold window

    @gold_window = Window_Gold.new

    @gold_window.x = 0

    @gold_window.y = 416

    # Make status window

    @status_window = Window_MenuStatus.new

    @status_window.x = 160

    @status_window.y = 0

    # Execute transition

    Graphics.transition

    # Main loop

    loop do

      # Update game screen

      Graphics.update

      # Update input information

      Input.update

      # Frame update

      update

      # Abort loop if screen is changed

      if $scene != self

        break

      end

    end

    # Prepare for transition

    Graphics.freeze

    # Dispose of windows

    @command_window.dispose

    @playtime_window.dispose

    @steps_window.dispose

    @gold_window.dispose

    @status_window.dispose

  end

  #--------------------------------------------------------------------------

  # * Frame Update (when command window is active)

  #--------------------------------------------------------------------------

  def update_command

    # If B button was pressed

    if Input.trigger?(Input::B)

      # Play cancel SE

      $game_system.se_play($data_system.cancel_se)

      # Switch to map screen

      $scene = Scene_Map.new

      return

    end

    # If C button was pressed

    if Input.trigger?(Input::C)

      # If command other than save or end game, and party members = 0

      if $game_party.actors.size == 0 and @command_window.index < 4

        # Play buzzer SE

        $game_system.se_play($data_system.buzzer_se)

        return

      end

      # Branch by command window cursor position

      case @command_window.index

      when 0  # item

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Switch to item screen

        $scene = Scene_Item.new

      when 1  # skill

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Make status window active

        @command_window.active = false

        @status_window.active = true

        @status_window.index = 0

      when 2  # equipment

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Make status window active

        @command_window.active = false

        @status_window.active = true

        @status_window.index = 0

      when 3  # status

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Make status window active

        @command_window.active = false

        @status_window.active = true

        @status_window.index = 0

      # Changed #4 to the Quest menu (instead of save)  

      when 4  # quest

        # This is for quests now:

        $scene = Scene_Quests.new

      # Changed 5 on down to keep save and quit in the menu...

      when 5  # save

        # If saving is forbidden

        if $game_system.save_disabled

          # Play buzzer SE

          $game_system.se_play($data_system.buzzer_se)

          return

        end

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Switch to save screen

        $scene = Scene_Save.new

      when 6  # end game

        # Play decision SE

        $game_system.se_play($data_system.decision_se)

        # Switch to end game screen

        $scene = Scene_End.new

      end

      return

    end

  end

end
There's also a few pictures you need to.
You can make your own using them as a template,
so your quest log can look however you like.

Example for an in progress list:

Example for a completed list:

Example for a background image:
In Graphics/Icons:
Needs to be named 'InProgressIcon'
Needs to be named 'CompletedIcon'

To call it, put '$scene = Scene_Quests.new' in a slot in your menu. You can call different lists using Scene_Quests.new(list number).
This needs to be set up in the Quest Window script.
If it's being called from the map, find '$scene = Scene_Menu.new' in both lists and
change it to '$scene = Scene_Map.new'.

Up/Down arrows scroll through the list, Left/Right changes lists.

Credit Jaberwocky if you use this.
I've explained very clearly how to set this up. I'm not gonna type the same thing twice because you couldn't be bothered to read this post. If you have questions that are answered here, go run your face into a cinder block.

A Quests In Progress list, showing the description, and different colored objectives with their icons

Yes, I know Franz is a stupid name o_O;
What the list looks like when you have no quests active

A Completed Quests list

You can have a near endless amount of quests

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