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.

Making a Scene for my quest window

Since current quest window scripts don't meet with my needs (still have bugs or difficult to use), I decided to make my own quest window. So far, constructing the quest window itself was not a problem.

The problem is, now I want to integrate my quest window within the menu, requiring me to make a new Scene. I don't know how to make my own Scene. What methods should be inside my new Scene class? I tried to mimic some Scenes (such as Scene_Menu) but all failed. Could anyone explain to me how to make a good Scene?

Oh, by the way, how to make a selectable window automatically scrolls when there are more options than available height? I tried it and the window didn't scroll, though I heard it should've automatically scrolled. I want to have one more option in my menu for displaying the quest status.

This is my script so far, excluding the Scene I made (it was a big mess):

Code:
#access this class using $quest
class MainQuest
  attr_accessor :steps_completed
  attr_accessor :main_quest
  attr_accessor :quest_id
  attr_accessor :current_step
  def initialize(quest_id)
    @steps_completed = Array.new(10)
    for i in 0 ... 10
      @steps_completed[i] = false
    end
    @quest_id = quest_id
    pick_quest(@quest_id)
  end
  def pick_quest(quest_id)
    #open file
    f = File.open("Data/MainQuest.rxdata")
    #read file
    quest = f.readlines
    #pick only quest_id
    @main_quest = quest[11 * (quest_id - 1), 11]
    #slice unneeded characters
    #quest header
    @main_quest[0].slice!("#" + quest_id.to_s + " ")
    @main_quest[0].slice!("\n")
    #line 1 to 10, remove "\n"
    for i in 1 .. 10
      @main_quest[i].slice!("\n")
    end
    p @main_quest
  end
end

class Window_Quest < Window_Base
  def initialize
    super(0, 0, 640, 416)
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end
  def refresh
    p $quest.current_step
    #draw each line to the window
    self.contents.draw_text(0, 0, 640, 32, $quest.main_quest[0])
    for i in 1 .. 10
      if $quest.steps_completed[i - 1]
        self.contents.font.color = disabled_color
      else
        if i == $quest.current_step
          self.contents.font.color = Color.new(0, 255, 0, 255)
        else
          self.contents.font.color = normal_color
        end
      end
      if $quest.main_quest[i] != ""
        self.contents.draw_text(0, 32 * i, 640, 32, i.to_s + ". " + $quest.main_quest[i])
      end
    end
  end
end

class Scene_Save < Scene_File
  alias quest_save write_save_data
  def write_save_data(file)
    quest_save(file)
    Marshal.dump($quest, file) if $quest != nil
  end
end

class Scene_Load < Scene_File
  alias quest_load read_save_data
  def read_save_data(file)
    quest_load(file)
    $quest = Marshal.load(file)
  end
end

Note that this script doesn't handle side quests yet (I'm planning to make side quests) and doesn't specify the rewards (my game doesn't have rewards so far). Also, it doesn't save any previous quests that are already completed. Maybe I'll improve to solve these issues (though I don't need them right now).

As you can see, instead of editing quests within script editor, I decided to use a file so I no longer need enter the script editor. I name it MainQuest.rxdata and should reside in Data directory. The MainQuest.rxdata uses 11 lines each quest. The first line will be quest's main objective while the remaining lines are used to describe actions to accomplish the quest (up to 10 actions). For example...

Code:
#1 Calm the boy.
Find Gloria.
Ask her for 100 golds.
Buy some candies from the store.
Give the candies to the boy.





#2 Find Gloria's ribbon.
Calm Gloria down.
Ask the girl what happened.
Find Nicholas and ask for the ribbon.
Find an old tree for a bird nest.
Fight the bird.
Return the ribbon to Gloria.
Fix Gloria's ribbon.
Return the fixed ribbon to Gloria.
Wash Gloria's ribbon and dry it.
Return the ribbon to Gloria.

I'm planning to extend this file so I can hold as many actions as I like.

Oh, by the way, is there a method in RGSS that allows me to read some lines (not all) from specific location? For example, to pick quest #2, instead of reading all the files, I'd like to read only line 12 to 22, so less memory will be used.

Any suggestions for improvement? Thank you.
 
In your scene have def main, def update, and maybe def initialize. Copy and paste something like Scene_End then edit it. And to make the window scroll, you have to set the height.
 
OK, now that I have made some changes to my script, could anyone please look at it and give suggestions for improvement?

My script now handles variable lines of quest steps (since I decided not to include side quests, now I will refer to "main quests" as "quests"), so I can add as many quest steps as I wish (as long as they will fit in the window). For example, you'd like to see my current MainQuest.rxdata (sorry it's not in English):

Code:
#1
Pergi ke Vandhuln.
Bicara ke Panglima Sézhan.
Tidur.
Siap-siap.
Briefing.
Lewati Gunung Örc.
Lewati Durk Faran.
Masuki Vandhuln dan investigasi.
Kembali ke Monas Matria.
#2
Makan.
Ke ruang makan.
Makan.
#3
Main.
Ke luar.
Main lari.
#14
Ketemu Sapi.
Tanya Situ.
Ke taman.
Cari Sapi.
Ngobrol.

To accomplish this, I have altered my script as following:

MainQuest class:
Code:
class MainQuest
  attr_accessor :steps_completed
  attr_accessor :main_quest
  attr_accessor :quest_id
  attr_accessor :current_step
  
  def initialize(quest_id)
    @quest_id = quest_id
    pick_quest(@quest_id)
    @steps_completed = Array.new(10)
    for i in 0 ... 10
      @steps_completed[i] = false
    end
  end
  def pick_quest(quest_id)
    #open file
    f = File.open("Data/MainQuest.rxdata")
    #read file
    quest = f.readlines
    #pick current quest only
    #find starting index of current quest
    #only if quest_id == 1
    if quest_id == 1
      pos_start = 0
    else
      pos_start = quest.index("#" + quest_id.to_s + "\n")
    end
    #find ending index of current quest
    pos_end = quest.index("#" + (quest_id + 1).to_s + "\n")
    if pos_end == nil
      pos_end = quest.size
    end
    #exclude quest header to count quest steps
    steps = pos_end - pos_start
    #pick only lines between pos_start and pos_end unless first line (quest #)
    @main_quest = quest[pos_start, steps]
    #remove first element
    @main_quest.shift
    #remove "\n"
    for i in 0 ... @main_quest.size
      @main_quest[i].slice!("\n")
    end
    #p @main_quest
  end
  def quest_completed?
    if @current_step == @main_quest.size - 1
      return true
    end
    return false
  end
end

Scene_Quest class:
Code:
class Scene_Quest
  def main
    #@quest_window.pick_quest(@quest_id)
    @quest_window = Window_Quest.new
    Graphics.transition
#    @quest_window.update
    loop do
      Graphics.update
      Input.update
      update
      if $scene != self
        break
      end
    end
    Graphics.freeze
    @quest_window.dispose
  end
  def update
    @quest_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Menu.new(3)
      return
    end
  end
end

Now here are my problems:

1. As you might notice in MainQuest class, there is an anomaly if the quest ID is 1. I can't get the starting position of quest #1 block in MainQuest.rxdata file (which line starts with #1). The other quest IDs work fine. How could this happen only to quest ID 1? Is it because I save my MainQuest.rxdata in UTF-8 format? (I need those special English characters by the way, so it's impossible to save the file in ANSI format.)

2. I alter my Scene_Menu class so that a small window appear if I choose Status. When a player chooses Status from the menu, a new window will appear, consisting of Quest and Actors. Quest will bring up my Scene_Quest while Actors will require the player to choose an actor to see his/her stats. Here's a bunch of my current Scene_Menu class:
Code:
class Scene_Menu
  alias quest_main main
  alias quest_update update
  def main
    #for quest window
    @statuswindow_select = Window_Command.new(96, ["Quest", "Tokoh"])
    @statuswindow_select.x = 160
    @statuswindow_select.y = 100
    @statuswindow_select.z = 200
    @statuswindow_select.visible = false
    @statuswindow_select.active = false
#    @quest_window = Window_Quest.new
#    @quest_window.visible = false
#    @quest_window.z = 300
    quest_main
    @statuswindow_select.dispose
#    @quest_window.dispose
  end
  def update
    @statuswindow_select.update
    quest_update
#    @quest_window.update
    if @statuswindow_select.active
      #p "Update status window"
      update_status_select
      return
    end
#    if @quest_window.active
#      update_quest
#      return
#    end
  end
  #status select (quest or actors status)
  def update_status_select
    #cancel
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @statuswindow_select.active = false
      @statuswindow_select.visible = false
      @statuswindow_select.index = -1
      @command_window.active = true
      return
    end
    if Input.trigger?(Input::C)
      #p "Hi!"
      $game_system.se_play($data_system.decision_se)
      @statuswindow_select.active = false
      @statuswindow_select.visible = false
      case @statuswindow_select.index
      when 0 #quest
        $scene = Scene_Quest.new
        #@quest_window.active = true
        #@quest_window.visible = true
      when 1 #status
        @status_window.active = true
        @status_window.index = 0
      end
      return
    end
  end
def update_command
#let me cut this part since I didn't alter anything, but here comes the "tricky" part:
case @command_window.index
#still same here...
      when 3  #status
        $game_system.se_play($data_system.decision_se)
        @command_window.active = false
        @statuswindow_select.active = true
        @statuswindow_select.index = 0
        @statuswindow_select.visible = true
#if @statuswindow_select.active then p "true" else p "false" end
#the remaining lines remain the same

Theoritically, it would work. In reality, when I choose Status from menu, my Scene_Quest appears instead of my tiny little window asking Quest or Actors. It seems that RGSS translate my C button twice, so my update_status_select method is triggered first even before I can notice it. But, when I pause at specific point (see the "if" line at the end of when 3?), it worked as I wish: a little window appear asking either Quest or Actors and if I choose Quest my Scene_Quest appears.
Anybody know how to fix this? It's the only problem that I can't solve myself and is pretty weird I think (it doesn't happen to any other window).

Thank you.
 
Well, seems no one responded, so I decided to throw away the menu and assigning it to a button instead.

Although this topic may be declared as [RESOLVED], I'd still like to know how to make a proper submenu (as my problem #2 above), if someone is kind enough to explain.

Thanks.
 

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