Mobius's Quest Journal

Discussion in 'RGSS Scripts (RMXP)' started by MobiusXVI, Oct 18, 2013.

  1. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Mobius's Quest Journal 2.1

    by


    MobiusXVI

    Release Notes
    v. 1.0 Initial Release
    v. 1.1 Added Quest Maker functionality
    v. 1.15 Improved Quest Maker to be more user friendly
    v. 1.2 Minor script compatibility improvement
    v. 2.0 Added optional switch/variable usage, improved debugging
    v. 2.1 Added additional debugging for file loading

    Introduction
    I wanted to create a plain looking, but robust quest/journal system that was akin to the one found in Skyrim. I also wanted to make it as user friendly as possible while still giving you control over implementation. I hope you enjoy it!

    Features
    - Quests can have as many steps or phases as you'd like
    - Each phase can have up to 20 lines of information displayed in the journal
    - Can store virtually unlimited number of quests
    - Sorts quests by current/completed; current quests show up in normal text while completed quests are grayed out
    - Keeps completed quests around for player review
    - Quest data created from .txt file; no need to put it all in the script window.
    - Quest data can also be made using a custom windows program - Mobius's Quest Journal Maker!
    - Quest data can be converted to .rxdata for security
    - Journal is called using simple script. Access it from an event, item, or even a key press! (Custom menus can call it up as well!)
    - Quests can be modified using standard switches/variables
    - Can automatically update switch/variable names both in-game and in the editor
    - Easily call the Quest Journal from the menu using my Menu Command Manager

    Screenshots
    The journal in game
    [​IMG]
    The Windows Quest Maker program
    [​IMG]

    How to Use
    Script is standard plug and play. Just put it below everything else but above main. The demo contains an example on how to format your .txt file for the quest data, but it essentially follows this pattern:

    Quest Name

    Phase 0 info

    Phase 1 info

    mobius_quest_break

    And that's all there is to it! You just repeat that pattern for each quest, and save it somewhere in the project folder. But if you don't feel like making in all in NotePad, then you can use my Quest Maker.

    Download here: Mobius's Quest Journal Maker

    If you're still not sure, then check out the video tutorial here: Video Tutorial
    You can also check out a second video tutorial covering the v2.0 updates: Video Tutorial 2

    Once you've got everything imported, you can use the following script calls from anywhere.

    $scene = Scene_Quest.new
    - Calls the quest journal scene

    $game_quests.discover_quest("quest_name")
    - Adds the named quest to the player's journal in the default state
    - You can also use the quest's ID rather than its name if you prefer

    $game_quests.dq("quest_name")
    - Same as above - just a shorthand version
    - Ditto about IDs

    $game_quests.set_phase("quest_name", phase_number)
    - Changes the named quest's phase to the specified phase number
    - Again, you can also use the quest's ID rather than its name if you prefer

    $game_quests.sp("quest_name", phase_number)
    - Same as above - just a shorthand version
    - Ditto about IDs

    $game_quests.complete_quest("quest_name")
    - Changes the named quest to completed status
    - Once more, you can also use the quest's ID rather than its name if you prefer

    $game_quests.cq("quest_name")
    - Same as above - just a shorthand version
    - Ditto about IDs

    Demo
    Download here: demo

    Script

    Code:
    #===============================================================================
    # Mobius' Quest Journal
    # Author: Mobius XVI
    # Version: 2.1
    # Date: 2 APR 2019
    #===============================================================================
    #
    # Introduction:
    #
    #   I wanted to create a plain looking, but robust quest/journal system that 
    #   was akin to the one found in Skyrim. I also wanted to make it as user 
    #   friendly as possible while still giving you control over implementation. 
    #   I hope you enjoy it!
    #
    # Instructions:
    #
    #  - Place this script below all the default scripts but above main.
    #
    #  - Visit the forums for detailed instructions as well as two video tutorials
    #    https://forums.rpgmakerweb.com/index.php?threads/mobiuss-quest-journal.19144/
    #
    # Issues/Bugs/Possible Bugs:
    #
    #   - Q. Why don't the changes I made to my quests show up during playtesting?
    #   - A. Simply put, the script is not save game compatible. This is - 
    #     unfortunately - the biggest current limitation of the script. If you start 
    #     a playtest, save your game, and exit, and then make changes to the quests 
    #     when you load up the save game it will not have any of your changes to the 
    #     quests. But any changes you make should display correctly as long as you 
    #     start a new game. My recommendation for getting around this problem is 
    #     utilizing the debug (F9) menu to set quests to the desired state for testing, 
    #     and always starting a new game.
    
    #
    #  Credits/Thanks:
    #    - Mobius XVI, author
    #
    #  License
    #   
    #    This script is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported license. 
    #    A human readable summary is available here: http://creativecommons.org/licenses/by-sa/3.0/deed.en_US
    #    The full license is availble here: http://creativecommons.org/licenses/by-sa/3.0/legalcode
    #    In addition, this script is only authorized to be posted to the forums on RPGMakerWeb.com.
    #    Further, if you do decide to use this script in a commercial product, 
    #    I'd ask that you let me know via a post here or a PM. Thanks.
    #
    #==============================================================================
    # CUSTOMIZATION START
    #==============================================================================
    module Mobius
      module Quests
        #--------------------------------------------------------------------------
        # * Module constants
        #--------------------------------------------------------------------------
          CREATE_ENCRYPTED = false              # Determines encrypted file creation
          USE_ENCRYPTED = false                 # Sets use of encrypted file
          QUEST_FILENAME = "Data/QuestData.txt" # Sets unencrypted filename
          USE_SWITCHES_VARIABLES = true         # Sets use of switches/variables
          FIRST_SWITCH_ID = 2                   # Sets the first switch ID
          FIRST_VARIABLE_ID = 2                 # Sets the first variable ID
          RENAME_SWITCHES_VARIABLES = true      # Determines renaming of switches/variables
          SHOW_ALL_QUESTS = false               # DEBUGGING FEATURE - Always shows all quests 
      end
    end
    #==============================================================================
    # CUSTOMIZATION END -- DON'T EDIT BELOW THIS LINE!!!
    #==============================================================================
    
    #==============================================================================
    # ** Game Quest -- Mobius
    #------------------------------------------------------------------------------
    #  The class that holds quests. Each instance of Game Quest is used to hold
    #  one quest.
    #==============================================================================
    
    class Game_Quest
      #--------------------------------------------------------------------------
      # * Class Variables
      #--------------------------------------------------------------------------
        @@total_quests = 0           # Used to track number of quest objects
    
      #--------------------------------------------------------------------------
      # * Public Instance Variables
      #--------------------------------------------------------------------------
        attr_reader   :id            # ID
        attr_reader   :name          # Name
        #attr_accessor :phase         # Phase
        attr_reader   :known         # Known status (true / false)
        attr_reader   :completed     # Completed status (true / false)
      #--------------------------------------------------------------------------
      # * Object Initialization
      #--------------------------------------------------------------------------
      def initialize(name = "", info_array = [] )
        @id = @@total_quests
        @@total_quests += 1
        @name = name
        @phase = 0
        @phase_variable = @id + Mobius::Quests::FIRST_VARIABLE_ID
        @known = false
        @known_switch = ( (@id * 2) + Mobius::Quests::FIRST_SWITCH_ID )
        @completed = false
        @completed_switch = ( (@id * 2) + 1 + Mobius::Quests::FIRST_SWITCH_ID )
        # The info array contains text that corresponds to the current phase
        # of the quest. So, you simply need to get the info in the i-th position
        # of the array for the i-th phase
        @info_array = info_array
        # Call rename if set in customization
        rename if (Mobius::Quests::RENAME_SWITCHES_VARIABLES and Mobius::Quests::USE_SWITCHES_VARIABLES)
      end
      #--------------------------------------------------------------------------
      # * Get Current Info
      # Returns text info for the current phase
      #--------------------------------------------------------------------------
      def get_current_info
        @info_array.fetch(@phase, [])
      end
      #--------------------------------------------------------------------------
      # * Phase=
      # Sets the quest phase 
      #--------------------------------------------------------------------------
      def phase=(value)
        # Set phase
        @phase = value
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          # Set phase variable
          $game_variables[@phase_variable] = value
          # Refresh map
          $game_map.need_refresh = true
        end
      end
      #--------------------------------------------------------------------------
      # * Discover
      # Changes quest state known to true 
      #--------------------------------------------------------------------------
      def discover
        # Set known flag
        @known = true
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          # Set known switch
          $game_switches[@known_switch] = true
          # Refresh map
          $game_map.need_refresh = true
        end
      end
      #--------------------------------------------------------------------------
      # * Complete
      # Changes quest state completed to true 
      #--------------------------------------------------------------------------
      def complete
        # Set completed flag
        @completed = true
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          # Set completed switch
          $game_switches[@completed_switch] = true
          # Refresh map
          $game_map.need_refresh = true
        end
      end
      #--------------------------------------------------------------------------
      # * Data Check
      # Updates quest phase, known, and completed with switch/variable 
      #--------------------------------------------------------------------------
      def data_check
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          @phase = $game_variables[@phase_variable]
          @known = $game_switches[@known_switch]
          @completed = $game_switches[@completed_switch]
        end
      end
      #--------------------------------------------------------------------------
      # * Rename
      # Renames associated switches and variables 
      #--------------------------------------------------------------------------
      def rename
        str = @name + " Phase"
        $data_system.variables[@phase_variable] = str
        str = @name + " Known"
        $data_system.switches[@known_switch] = str
        str = @name + " Completed"
        $data_system.switches[@completed_switch] = str
        save_data($data_system, "Data/System.rxdata")
      rescue
        print(self.to_s)
        raise
      end
      #--------------------------------------------------------------------------
      # * to_s
      # Returns quest object data as string
      # Mostly used for debugging purposes
      #--------------------------------------------------------------------------
      def to_s
        "Quest ID: #{@id}\n" +
        "Quest Name: #{@name}\n" +
        "Quest Info:\n" +
        @info_array.join("\n")
      end
    end
    
    #==============================================================================
    # ** Game_Quests
    #------------------------------------------------------------------------------
    #  This class handles the Game Quest arrays. Refer to "$game_quests" for the
    #  instance of this class.
    #==============================================================================
    
    class Game_Quests
      #--------------------------------------------------------------------------
      # * Public Instance Variables
      #--------------------------------------------------------------------------
        attr_accessor :all_quests           # Array of all quest objects
        attr_accessor :current_quests       # Array of all current quest objects
        attr_accessor :completed_quests     # Array of all completed quest objects
      #--------------------------------------------------------------------------
      # * Object Initialization
      #--------------------------------------------------------------------------
      def initialize
        @all_quests = []
        @current_quests = []
        @completed_quests = []
        setup
      end
      #--------------------------------------------------------------------------
      # * Add Quest - adds a quest object to the all_quests array
      #--------------------------------------------------------------------------
      def add_quest(quest)
        @all_quests.push(quest)
      end
      #--------------------------------------------------------------------------
      # * Sort Quests
      # Refreshes the current_quests and completed_quests arrays
      # Also sorts them as well as the all quests array by ID's
      #--------------------------------------------------------------------------
      def sort_quests
        # Sort the all_quests array by ID
        @all_quests.sort {|a,b| a.id <=> b.id }
        # Reset the current and completed quest arrays
        @current_quests = []
        @completed_quests = []
        # Push known and completed quests to their appropiate arrays
        for quest in @all_quests
          if quest.known and quest.completed
            @completed_quests.push(quest)
          elsif quest.known
            @current_quests.push(quest)
          end
        end
      end
      #--------------------------------------------------------------------------
      # * Discover Quest - uses quest name or id to change state of quest to known
      #--------------------------------------------------------------------------
      def discover_quest(name_or_id)
        # Check if passed value is ID
        if name_or_id.is_a?(Integer)
          # Check if ID is valid
          if @all_quests[name_or_id].is_a?(Game_Quest)
            # Set quest to known
            @all_quests[name_or_id].discover
          else # If ID is invalid
            # Print debug message
            print("The quest ID provided (#{name_or_id}) is not valid.")
          end
        elsif name_or_id.is_a?(String)
          # Look up quest using name
          quest_to_change = @all_quests.find {|quest| quest.name == name_or_id}
          # Check if quest is valid
          if quest_to_change.is_a?(Game_Quest)
            # Set quest to known
            quest_to_change.discover
          else # If quest is invalid
            # Print debug message
            print("The quest name '#{name_or_id}' was not found.\n" +
                  "Check that the quest exists and that the spelling\n" +
                  "is correct." )
          end
        else # If input is invalid
          # Print debug message
          print("Unrecognized input provided to method 'discover_quest'.\n" +
                "Input should be either an integer for the quest ID or\n" +
                "a string representing the quest name." )
        end
        sort_quests
      end
      # Create shorthand name for eventing scripts
      alias dq discover_quest
      #--------------------------------------------------------------------------
      # * Set Phase - uses quest name or id to change phase
      #--------------------------------------------------------------------------
      def set_phase(name_or_id, phase)
        # Check if passed value is ID
        if name_or_id.is_a?(Integer)
          # Set quest to known
          @all_quests[name_or_id].phase = phase
        else
          # Look up quest using name
          quest_to_change = @all_quests.find {|quest| quest.name == name_or_id}
          # Set quest to known
          quest_to_change.phase = phase
        end
        sort_quests
      end
      # Create shorthand name for eventing scripts
      alias sp set_phase
      #--------------------------------------------------------------------------
      # * Complete Quest
      # Uses quest name or id to change state of quest to complete
      #--------------------------------------------------------------------------
      def complete_quest(name_or_id)
        # Check if passed value is ID
        if name_or_id.is_a?(Integer)
          # Check if ID is valid
          if @all_quests[name_or_id].is_a?(Game_Quest)
            # Set quest to known
            @all_quests[name_or_id].complete
          else # If ID is invalid
            # Print debug message
            print("The quest ID provided (#{name_or_id}) is not valid." +
                  "Check that the quest exists and that the id is correct." )
          end
        elsif name_or_id.is_a?(String)
          # Look up quest using name
          quest_to_change = @all_quests.find {|quest| quest.name == name_or_id}
          # Check if quest is valid
          if quest_to_change.is_a?(Game_Quest)
            # Set quest to known
            quest_to_change.complete
          else # If quest is invalid
            # Print debug message
            print("The quest name '#{name_or_id}' was not found.\n" +
                  "Check that the quest exists and that the spelling\n" +
                  "is correct." )
          end
        else # If input is invalid
          # Print debug message
          print("Unrecognized input provided to method 'discover_quest'.\n" +
                "Input should be either an integer for the quest ID or\n" +
                "a string representing the quest name." )
        end
        sort_quests
      end
      # Create shorthand name for eventing scripts
      alias cq complete_quest
      #--------------------------------------------------------------------------
      # * Data Check
      # Performs a data check on the specified quest
      #--------------------------------------------------------------------------
      def data_check(id)
        @all_quests[id].data_check if @all_quests[id]
      end
      #--------------------------------------------------------------------------
      # * Data Check All
      # Performs a data check on all quests
      #--------------------------------------------------------------------------
      def data_check_all
        for quest in @all_quests
          quest.data_check
        end
      end
      #--------------------------------------------------------------------------
      # * Setup - Performs first time setup of quest data
      #--------------------------------------------------------------------------
      def setup
        # begin block for error handling
        begin
          # if true
          if Mobius::Quests::CREATE_ENCRYPTED
            # Load unencrypted data
            Game_Quests.normal_setup
            # Create encrypted .rxdata
            Game_Quests.create_encrypted
          # elsif true
          elsif Mobius::Quests::USE_ENCRYPTED
            # Load encrypted data
            Game_Quests.encrypted_setup
          else
            # Load unencrypted data
            Game_Quests.normal_setup
          end
          # initialize Game_Quest object data from $data_quests array
          for quest in $data_quests
            self.add_quest(quest)
          end
          # Set Main Quest to known
          discover_quest(0)
        # rescue when no file is found   
        rescue Errno::ENOENT => e 
          Game_Quests.on_no_file(e)
          raise SystemExit
        end
      end
      #--------------------------------------------------------------------------
      # * GQs - Normal Setup
      # Class method that intializes normal quest data 
      #--------------------------------------------------------------------------
      def Game_Quests.normal_setup
        # Create array of quest data from file
        quest_array = File.open(Mobius::Quests::QUEST_FILENAME) {|f| 
                    f.readlines("mobius_quest_break\n\n")}
        # Remove empty last element if necessary
        if quest_array.last.rstrip == ""
          quest_array.pop
        end
        # Initialize $data_quests array
        $data_quests = Array.new
        # Create Game_Quest objects from data
        for quest_data in quest_array
          # Split quest data by paragraph
          quest_data_array = quest_data.split("\n\n")
          # Remove file delimiter "mobius_quest_break\n\n"
          quest_data_array.pop
          # Set and remove name
          name = quest_data_array.shift
          # Initialize info array
          info_array = []
          # Organize phase info into useable line lengths
          for quest_data_line in quest_data_array
            new_arr = []
            # Split phase info into words
            temp_arr = quest_data_line.split
            temp_str = ""
            for word in temp_arr
              # Rejoin words together
              temp_str.concat(word + " ")
              # When line length is useable, push to new_arr
              if temp_str.size >= 35
                new_arr.push(temp_str.strip)
                temp_str = ""
              end
            end
            # Push leftover string
            new_arr.push(temp_str.strip) unless temp_str == ""
            # Push phase info to info_array
            info_array.push(new_arr)
          end
          # Push new Game_Quest object to $data_quests array
          $data_quests.push(Game_Quest.new(name, info_array))
        end
      end
      #--------------------------------------------------------------------------
      # * GQs - Encrypted Setup
      # Class method that intializes encrypted quest data 
      #--------------------------------------------------------------------------
      def Game_Quests.encrypted_setup
        # load encrypted data
        $data_quests = load_data("Data/Quests.rxdata")
      end
      #--------------------------------------------------------------------------
      # * GQs - Create Setup
      # Class method that creates encrypted quest data 
      #--------------------------------------------------------------------------
      def Game_Quests.create_encrypted
        # save encrypted data
        save_data($data_quests, "Data/Quests.rxdata")
      end
      #--------------------------------------------------------------------------
      # * GQs - File Search
      # Class method that runs a search looking for similarly named files 
      #--------------------------------------------------------------------------
      def Game_Quests.file_search(dir, search_string)
        matches = []
        Dir.foreach(dir) do |entry|
          next if ((entry == ".") or (entry == ".."))
          if File.directory?(entry)
            # search sub directory
            sub_dir = File.expand_path(entry, dir)
            matches += Game_Quests.file_search(sub_dir, search_string)
          else
            # run comparison
            if entry.match(Regexp.new(search_string, true))
              full_path = File.expand_path(entry, dir)
              matches.push(full_path)
            end
          end
        end
        return matches
      end
      #--------------------------------------------------------------------------
      # * GQs - On No File
      # Class method that handles a no file error 
      #--------------------------------------------------------------------------
      def Game_Quests.on_no_file(error)
        # Construct filenames
        user_filename = error.message.sub("No such file or directory - ", "")
        user_basename = File.basename(user_filename, ".*")
        full_path = File.expand_path(user_filename)
        # Run search using given filename   
        matches = Game_Quests.file_search(Dir.pwd, user_basename)
        # Construct error message to user
        message = "##Mobius' Quest Journal Script Says##\n"
        message += "I was unable to find the file named: "
        message += "\n\"" + full_path + "\"\n\n"
        message += "I searched this folder: \n\"" + Dir.pwd + "\"\n"
        message += "and its subfolders for similar file names"
        unless matches.empty?
          message += " and I found these. Maybe they're what you want?\n\n\""
          message += matches.join("\"\n\n")
        else
          message += " but I couldn't find anything."
        end
        # display error message to user
        print(message)
      end
    end
    
    #==============================================================================
    # ** Window Quest Info
    #------------------------------------------------------------------------------
    #  This window lists the info for the quests
    #==============================================================================
    
    class Window_QuestInfo < Window_Selectable
      #--------------------------------------------------------------------------
      # * Object Initialization
      #--------------------------------------------------------------------------
      def initialize()
        super(200, 0, 440, 480)
        self.active = false
        self.contents = Bitmap.new(width - 32, height - 32)
        self.index = -1
        refresh([""])
      end
      #--------------------------------------------------------------------------
      # * Refresh
      #--------------------------------------------------------------------------
      def refresh(text_array)
        # Clear old contents
        if self.contents != nil
          self.contents.clear
        end
        # Set font color
        self.contents.font.color = normal_color
        # Break if text_array is nil
        return unless text_array
        # Draw info
        for i in 0...text_array.size
          line = text_array[i]
          self.contents.draw_text(0, i * 22, 408, 22, line)
        end
      end
    end
    
    #==============================================================================
    # ** Window Quest List
    #------------------------------------------------------------------------------
    #  This window lists all currently active/completed quests
    #==============================================================================
    
    class Window_QuestList < Window_Selectable 
      #--------------------------------------------------------------------------
      # * Object Initialization
      #--------------------------------------------------------------------------
      def initialize()
        super(0, 0, 200, 480)
        @current_quests = []        # Array of current quests
        @completed_quests = []      # Array of completed quests
        @top_half_size = 0          # Number of rows of current quests
        @bottom_half_size = 0       # Number of rows of completed quests
        self.active = true
        self.index = 0
        refresh
      end
      #--------------------------------------------------------------------------
      # * Refresh
      #--------------------------------------------------------------------------
      def refresh
        # Determine total number of rows
        @item_max = [@top_half_size + @bottom_half_size, 1].max
        if self.contents != nil
          self.contents.dispose
        end
        # Draw bitmap
        self.contents = Bitmap.new(200 - 32, row_max * 32)
        self.contents.font.color = normal_color
        # Draw current quests
        for i in 0...@top_half_size
          quest_name = @current_quests[i].name
          self.contents.draw_text(8, i * 32, 160, 32, quest_name)
        end
        self.contents.font.color = disabled_color
        # Draw completed quests
        for i in 0...@bottom_half_size
          quest_name = @completed_quests[i].name
          self.contents.draw_text(8, i * 32 + @top_half_size * 
          32, 160, 32, quest_name)
        end
      end
      #--------------------------------------------------------------------------
      # * Set Quests
      #--------------------------------------------------------------------------
      def set_quests(new_current_quests, new_completed_quests)
        if @current_quests != new_current_quests or
           @completed_quests != new_completed_quests
           #set new quests
           @current_quests = new_current_quests
           @completed_quests = new_completed_quests
           @top_half_size = @current_quests.size
           @bottom_half_size = @completed_quests.size
           #call update
           refresh
        end
      end
      #--------------------------------------------------------------------------
      # * Get Index Info
      #   Returns the text info from which ever quest is currently highlighted
      #--------------------------------------------------------------------------
      def get_index_info
        # Unless there are no quests
        unless @current_quests.empty? and @completed_quests.empty?
          # Determine cursor location
         if self.index < @top_half_size
            # Get selected quest info
            @current_quests[self.index].get_current_info 
          else
            # Get selected quest info
            @completed_quests[self.index - @top_half_size].get_current_info
          end
        end
      end
    end
    
    #==============================================================================
    # ** Scene_Quest
    #------------------------------------------------------------------------------
    #  This class performs quest screen processing.
    #==============================================================================
    
    class Scene_Quest
      #--------------------------------------------------------------------------
      # * Object Initialization
      #--------------------------------------------------------------------------
      def initialize(return_scene = $scene.type)
        @return_scene = return_scene
      end
      #--------------------------------------------------------------------------
      # * Main Processing
      #--------------------------------------------------------------------------
      def main
        # Make QuestList Window
        @quest_list_window = Window_QuestList.new
        # Make QuestInfo Window
        @quest_info_window = Window_QuestInfo.new
        # Create memory variable
        @list_index = @quest_list_window.index
        # Update Game Quests
        $game_quests.data_check_all if Mobius::Quests::USE_SWITCHES_VARIABLES
        $game_quests.sort_quests
        # Refresh QuestList
        unless Mobius::Quests::SHOW_ALL_QUESTS
          # Normal refresh
          @quest_list_window.set_quests($game_quests.current_quests, 
                                        $game_quests.completed_quests)
        else
          # DEBUG refresh
          @quest_list_window.set_quests($game_quests.all_quests, [] )
        end
        # Redraw info window
        new_text = @quest_list_window.get_index_info
        @quest_info_window.refresh(new_text)
        # 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
        @quest_list_window.dispose
        @quest_info_window.dispose
     
      end
      #--------------------------------------------------------------------------
      # * Frame Update
      #--------------------------------------------------------------------------
      def update
        # Update windows
        @quest_list_window.update
        # If index has changed
        if @list_index != @quest_list_window.index
          # Redraw info window
          new_text = @quest_list_window.get_index_info
          @quest_info_window.refresh(new_text)
          # Set index memory
          @list_index = @quest_list_window.index
        end
        # When cancel
        if Input.trigger?(Input::B)
          # Play cancel SE
          $game_system.se_play($data_system.cancel_se)
          # Return to menu
          $scene = @return_scene.new
        end
      end
    end
    
    # Changes to Scene_Title
    class Scene_Title
     
      # Alias old method
      alias mobius_command_new_game command_new_game
      def command_new_game
        # Call old method
        mobius_command_new_game
        # Initialize Game_Quests object
        $game_quests = Game_Quests.new
      end
    end
    
    # Changes to Scene_Save
    class Scene_Save
     
      # Alias old method
      alias mobius_write_save_data write_save_data
      def write_save_data(file)
        # Call old method
        mobius_write_save_data(file)
        # Dump Game_Quests object state to the save file
        Marshal.dump($game_quests, file)
      end
    end
    
    # Changes to Scene_Load
    class Scene_Load
     
      # Alias old method
      alias mobius_read_save_data read_save_data
      def read_save_data(file)
        # Call old method
        mobius_read_save_data(file)
        # Load Game_Quests object state from the save file
        $game_quests = Marshal.load(file) 
      end
     
    end
    
    # Changes to Interpreter
    class Interpreter
      # Create alias
      alias mobius_command_121 command_121
      #--------------------------------------------------------------------------
      # * Control Switches
      #--------------------------------------------------------------------------
      def command_121
        mobius_command_121
        # Only do this is using switches/variables
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          # Get first quest switch id
          first = Mobius::Quests::FIRST_SWITCH_ID
          # Loop for group control
          for i in @parameters[0] .. @parameters[1]       
            # If first id and chosen id have same parity
            if (first % 2) == ( i % 2 )
              # Determine corresponding quest id
              id = ( i - first ) / 2
            # If first id and chosen id have different parity
            else
              # Determine corresponding quest id
              id = ( i - first - 1 ) / 2
            end
            $game_quests.data_check(id)     
          end
        end
        # Continue
        return true
      end
      # Create alias
      alias mobius_command_122 command_122
      #--------------------------------------------------------------------------
      # * Control Variables
      #--------------------------------------------------------------------------
      def command_122
        mobius_command_122
        # Only do this is using switches/variables
        if Mobius::Quests::USE_SWITCHES_VARIABLES
          # Get first quest switch id
          first = Mobius::Quests::FIRST_VARIABLE_ID
          # Loop for group control
          for i in @parameters[0] .. @parameters[1]       
            # Determine corresponding quest id
            id = ( i - first )
            $game_quests.data_check(id)
          end
        end
        # Continue
        return true
      end
     
    end
    
    

    FAQ
    Q. Why don't the changes I made to my quests show up during playtesting?
    A. Simply put, the script is not save game compatible. This is - unfortunately - the biggest current limitation of the script. If you start a playtest, save your game, and exit, and then make changes to the quests when you load up the save game it will not have
    any of your changes to the quests. But any changes you make should display correctly as long as you start a new game. My
    recommendation for getting around this problem is utilizing the debug (F9) menu to set quests to the desired state for testing, and
    always starting a new game.

    Credit and Thanks
    Special thanks to Zeriab. I borrowed the name for two of my classes from the Quest Book script, and overall I'd say it influenced my design.

    Author's Notes
    This script is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported license.
    A human readable summary is available here: http://creativecommons.org/licenses/by-sa/3.0/deed.en_US
    The full license is availble here: http://creativecommons.org/licenses/by-sa/3.0/legalcode
    In addition, this script is only authorized to be posted to the forums on RPGMakerWeb.com.
    Further, if you do decide to use this script in a commercial product, I'd ask that you let me know via a post here or a PM. Thanks.

     
    Last edited: Apr 3, 2019
    #1
    Zeriab, Hunewearl, Neko Mizu and 8 others like this.
  2. The Dragon God

    The Dragon God Indie Game Dev, Concept Artist Veteran

    Messages:
    246
    Likes Received:
    6
    Location:
    RMW, RMN, Forums
    First Language:
    English
    I need a Youtube video of you doing this step by step. I'm a visual learner. Other that that this looks awesome!
     
    #2
  3. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Per your request, I've added a video tutorial. Hope it helps!
     
    #3
  4. F117Landers

    F117Landers Veteran Veteran

    Messages:
    63
    Likes Received:
    5
    First Language:
    English
    Forgive my Ignorance, I am new to RPG Maker and Scripting. If I am understanding correctly:

    $scene = Scene_Quest.new runs the script so that the other functions can be used

    B key opens the journal for players

    Is this correct?
     
    #4
  5. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Not quite. So $scene = Scene_Quest.new will open the journal for players. Then if you wanted to, you could make a common event in the database that would call $scene = Scene_Quest.new  when the B button is pressed (or any other button for that matter). The rest of the functions allow you to change the quests and can be called anywhere/anytime.
     
    #5
  6. F117Landers

    F117Landers Veteran Veteran

    Messages:
    63
    Likes Received:
    5
    First Language:
    English
    Ah, that makes more sense; Thanks. The reason I ask about B in particular is because in your common event Script Scene_Quest (in the demo) you indicate B to cancel.

    Edit: I have now discovered that Scripts and Common Events are different things. Also found the Common Events in your demo.
     
    Last edited by a moderator: Jun 19, 2014
    #6
  7. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Glad you're getting things figured out!  If you haven't seen it yet, there's a tutorials forum on here that'll teach you how to do lots of nifty things, and you can also find guides on just the basic functions as well.
     
    #7
  8. F117Landers

    F117Landers Veteran Veteran

    Messages:
    63
    Likes Received:
    5
    First Language:
    English
    Thanks!. Though to be honest, I always have trouble sticking to tutorials. I've been going through various demo's that people have of their scripts to see how it works and how it relates to ruby.

    Speaking of scripts, I did have a question about the Quest Log.  I didn't see any references, but I just wanted to double-check: Are any of the variables or switches used by your quest log?
     
    #8
  9. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Nope. My script uses it's own internal data to track things, so it doesn't use any variables or switches. I've considered adding in the option to use them instead of the built-in data, but have yet to actually do that.
     
    #9
  10. F117Landers

    F117Landers Veteran Veteran

    Messages:
    63
    Likes Received:
    5
    First Language:
    English
    Thanks!
     
    #10
  11. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Version 2.0 of the script is live! The script now offers integration with switches/variables, and a few other things. Check out the video tutorial here
     
    #11
  12. GraveBusta

    GraveBusta Vengful Veteran

    Messages:
    150
    Likes Received:
    13
    Location:
    USA
    First Language:
    English
    This is a pretty neat tool thanks a ton :) I am new here yet I am liking it more and more by the day finding new cool stuff all the time.
     
    #12
    MobiusXVI likes this.
  13. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    You're welcome, and thanks! It's always nice to hear that people are using and enjoying my work. And since you're new, let me say welcome! This is a great community with a lot of helpful people so if you ever have any questions or specific requests for things, don't hesitate to ask.
     
    #13
    GraveBusta likes this.
  14. SuperMasterSword

    SuperMasterSword That Guy You Dont Know Veteran

    Messages:
    117
    Likes Received:
    48
    Location:
    Awesomeville
    First Language:
    Javascript
    Primarily Uses:
    RMMV
    Is there a way to use variables but not switches? I haven't used it in a real game yet but I plan to and I was fine using the script calls but I thought I could use the variables to check how far they are and not let them pass if they aren't. in short, well the first sentence :D . Thanks!
     
    #14
  15. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Short answer: yes :thumbsup-right:  Long answer: when using switches and variables, the script will keep everything self consistent, meaning you can use any combination of script calls/events. As an example, let's say Quest #1 uses the switches 1 and 2, and the variable 1. The following would all then be equivalent:

    $game_quests.discover_quest(1) == Set Game Switch #1 to true (via event)

    $game_quests.complete_quest(1) == Set Game Switch #2 to true (via event)

    $game_quests.set_phase(1, 3) == Set Game Variable #1 to 3 (via event)

    It doesn't matter which you use. I did this on purpose so that previous users of my script could upgrade to the new version and use switches/variables without breaking their projects and making them have to go back and re-do a bunch of work.
     
    Last edited by a moderator: Aug 22, 2014
    #15
  16. SuperMasterSword

    SuperMasterSword That Guy You Dont Know Veteran

    Messages:
    117
    Likes Received:
    48
    Location:
    Awesomeville
    First Language:
    Javascript
    Primarily Uses:
    RMMV
    Ah, ok. to be honest when I first saw this script I was first reminded of the Jak and Daxter series, which if you haven't played it doesn't have phases, but only missions which are either in progress or completed. (although there also weren't any side quests, but personally I still thought it was a good game)

    EDIT: and the point is that's how I thought I could use it. although partly because I might miss if I can't ever see what it said before when it switches to a new phase. (don't ask why, I don't know) (though to be honest [again] I could just copy and paste and add on to the previous phase)
     
    Last edited by a moderator: Aug 22, 2014
    #16
  17. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Man, it's been years since I played Jak and Daxter, and yeah I thought it was good too. But I actually thought about including previous phase info; like letting the player go back and read previous phases. I ended up deciding against it because - for my own project - I wanted to have some branching side quests. So by not showing old phases, I was able to set up the quest like phase 1->2->3->branch to either 4 or 5, and take that same concept even further if I wanted to. And you're right, if you really want the player to have the old phase info, then you can always just copy/paste.
     
    #17
  18. SuperMasterSword

    SuperMasterSword That Guy You Dont Know Veteran

    Messages:
    117
    Likes Received:
    48
    Location:
    Awesomeville
    First Language:
    Javascript
    Primarily Uses:
    RMMV
    just to be sure, when I use $game_quests.set_phase would it also change the variable automatically? (and similarly change the corresponding switch if I used .discover_quest or .complete_quest?)
     
    #18
  19. MobiusXVI

    MobiusXVI Game Maker Veteran

    Messages:
    359
    Likes Received:
    84
    First Language:
    English
    Yep! Give it a try sometime. Just set up an event with a script call and then verify the change was made to the corresponding variable/switch with the F9 debug menu.
     
    #19
  20. Mesajia

    Mesajia Veteran Veteran

    Messages:
    80
    Likes Received:
    47
    First Language:
    German
    Primarily Uses:
    RMMV
    Hello Mobius,

    what a nice work. The Quest Maker is perfect for people like me who are very bad in scripting and remembering scriptlines :) And I also have a very nice overview about the quests I m planning.

    But I have a question: Is it possible to show icons or smaller pictures in the Journal?
     
    #20

Share This Page