[XP] Book Scene

Started by ForeverZer0, September 01, 2010, 12:20:14 pm

Previous topic - Next topic

ForeverZer0

September 01, 2010, 12:20:14 pm Last Edit: September 28, 2010, 12:11:43 pm by ForeverZer0
Book/Library Scene
Authors: ForeverZer0
Version: 1.2
Type: Misc Add-on
Key Term: Misc Add-on



Introduction

Calls a scene that will allow the player to read/view books they have collected.


Features


  • Easy to configure, text is read from an external text document
  • Text is automatically sized for each page



Screenshots

None.


Demo

http://www.mediafire.com/?yvgzdoa32uahh7n


Script
Spoiler: ShowHide

#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
# Book/Library Scene
# Author: ForeverZer0
# Version: 1.2
# Date: 9.1.2010
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
#
# Version History:
#   v. 1.0  9.1.2010
#     - Original version
#   v. 1.1  9.3.2010
#     - Added option for full-screen text
#     - Made the page number window slightly wider
#   v. 1.2  9.25.2010
#     - Added option to simply call scene with the book ID argument and have
#       that book already displayed.
#
# Introduction:
#   Calls a scene that will allow player to read through books that they have
#   collected.
#
# Features:
#   - Easy to configure, text is read from an external text document
#   - Text will automatically fit itself into the proper size for the window
#     width and pages, regardless of font or font size.

# Instructions:
#   1. Fill in the configuration below.
#   2. Create a new folder within the "Data" folder, and name it "Books".
#   3. Within this folder, create simple text documents (.txt).
#   4. Name them EXACTLY as you did for its respective title (below).
#   5. Turn word-wrap OFF.
#   6. Create as large as document as you would like, but only break to a new
#      line in between paragraphs, not when the text reaches the edge of the
#      window. Every time a new line is started, it guarantees that the current
#      line will start on a new line in the scene, regardless of the font size.
#
#   Use the following Script Calls:
#     Books.unlock(BOOK_ID)     
#       - Unlocks the book with BOOK_ID
#     $scene = Scene_Book.new   
#       - Calls the Book scene.
#     $scene = Scene_Book.new(BOOK_ID)
#       - Calls the book scene. The book with BOOK_ID will already be displayed.
#         This will also disable the book list feature. The book does not have
#         to be unlocked to call this way.
#
# Credits/Thanks:
#   ForeverZer0, for the script
#   Blizzard, for the "slice_text" method
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=

module Books
 
#===============================================================================
#                           BEGIN CONFIGURATION   
#===============================================================================
 
  RETURN_SCENE = Scene_Map
  # Class of the scene that the game return to after you exit the book scene.
  SORT_BY_ID = true
  # If true, the books will be listed in order of their Book ID, else they will
  # be listed in the order they were aquired.
  PAGE_TURN_SE = ['046-Book01', 80, 100]
  # Set to the name of the SE that will be played when a player turns a page.
  # Set to nil to disable this feature. [FILENAME, VOLUME, PITCH]
  FULLSCREEN_TEXT = false
  # If true, the text window will extend over the book list and take up the
  # entire screen (minus the header).
 
  def self.title(book_id)
    # Here is where you define the labels used for the books. The titles will
    # be used as the filename to be loaded as well.
    # when BOOK_ID then 'TITLE'
    return case book_id
    when 0 then 'Genesis'
    when 1 then 'Exodus'
    when 2 then 'Leviticus'
    when 3 then 'Numbers'
    when 4 then 'Deuteronomy'
    end
  end
 
#===============================================================================
#                            END CONFIGURATION   
#===============================================================================
 
  def self.unlock(book_id)
    # Adds the Book ID to the array.
    unless $game_system.books.include?(book_id)
      $game_system.books.push(book_id)
      # Sorts the array by the Book IDs if so configured.
      if SORT_BY_ID
        $game_system.books.sort!
      end
    end
  end
 
  def self.get_text(book_id)
    # Opens a text document, makes an array whose elements consist of the lines
    # of the document, and returns it.
    filename = 'Data/Books/' + title(book_id) + '.txt'
    begin
      file = File.open(filename, 'r')
    rescue
      raise("Error occured while attempting to open the following file:\n\n" +
            "\t#{filename}\n\n" +
            "Please make sure that the file exist before you continue.")
    end
    book = []
    file.each_line {|line| book.push(line)}
    file.close
    return book
  end
end

#===============================================================================
# ** Game_System   
#===============================================================================

class Game_System
 
  attr_accessor :books     # Array: Stores the IDs of all unlocked books.
 
  alias zer0_book_init initialize
  def initialize
    zer0_book_init
    @books = []
  end   
end

#===============================================================================
# ** Scene_Book
#===============================================================================

class Scene_Book
 
  def initialize(book_id = nil)
    @book_id = book_id
    @no_list = @book_id != nil
  end
 
  def main
    # Create a variable that is set to the window width (depending on config)
    @window_width = Books::FULLSCREEN_TEXT ? 640 : 512
    @window_width = 640 if @no_list
    # Create a blank dummy window.
    @dummy_window = Window_Base.new(128, 64, 512, 416)
    # Create Help_Window to display the book titles.
    @help_window = Window_Base.new(0, 0, 448, 64)
    @help_window.contents = Bitmap.new(416, 32)
    # Create the page number window
    @page_window = Window_Base.new(448, 0, 192, 64)
    @page_window.contents = Bitmap.new(160, 32)
    # Create the window that text will be displayed on.
    x = @window_width == 640 ? 0 : 128
    @text_window = Window_Base.new(x, 64, @window_width, 416)
    @text_window.contents = Bitmap.new(@window_width - 32, 384)
    @text_window.z = @help_window.z + 20
    @text_window.visible = false
    # Make a copy of the Books array.
    @books = $game_system.books.clone
    # Create instance variable for updating the text window.
    @update_text = false
    # Make list of all books, if possible, else make list empty.
    if @books.empty?
      help_string = 'No books are currently available.'
      @command_window = Window_Base.new(0, 64, 128, 416)
    else
      help_string = 'Whick book would you like to read?'
      @titles = []
      @books.each {|book_id| @titles.push(Books.title(book_id))}
      @command_window = Window_Command.new(128, @titles)
      @command_window.height, @command_window.y = 416, 64
    end
    # Display text on the help screen
    @help_window.contents.draw_text(0, 0, 416, 32, help_string, 1)
    # Create array that holds all the windows
    @windows = [@dummy_window, @help_window, @text_window,
                @command_window, @page_window]
               
    if @no_list
      @page_number = 1
      $game_system.se_play($data_system.decision_se)
      @help_window.contents.clear
      @help_window.contents.draw_text(0, 0, 416, 32, Books.title(@book_id), 1)
      @command_window.active, @update_text = false, true
      compile_text
      @text_window.visible = true
    end
   
    Graphics.transition
    # Main loop
    loop {Graphics.update; Input.update; update; break if $scene != self}
    Graphics.freeze
    @windows.each {|window| window.dispose}
  end
 
  def update
    # Update windows.
    @windows.each {|window| window.update}
    if @command_window.is_a?(Window_Command) && @command_window.active
      update_command_window
      return
    elsif @update_text
      update_text_window
      return
    end
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Books::RETURN_SCENE.new
    end
  end
 
  def update_command_window
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Books::RETURN_SCENE.new
    elsif Input.trigger?(Input::C)
      @page_number = 1
      $game_system.se_play($data_system.decision_se)
      @book_id = @books[@command_window.index]
      @help_window.contents.clear
      @help_window.contents.draw_text(0, 0, 416, 32, Books.title(@book_id), 1)
      @command_window.active, @update_text = false, true
      compile_text
      @text_window.visible = true
    end
  end
 
  def update_text_window
    if Input.trigger?(Input::LEFT) || Input.trigger?(Input::RIGHT)
      old_page = @page_number
      @page_number += Input.trigger?(Input::LEFT) ? -1 : 1
      @page_number = [[@page_number, @pages.size].min, 1].max
      # Play SE if configured as such.
      if old_page != @page_number && Books::PAGE_TURN_SE != nil
        se = Books::PAGE_TURN_SE
        audio = RPG::AudioFile.new(se[0], se[1], se[2])
        $game_system.se_play(audio)
      end
      # Refresh the window
      refresh_text
    elsif Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      if @no_list
        $scene = Books::RETURN_SCENE.new
      else
        @update_text, @command_window.active = false, true
        @text_window.visible = false
      end
    end
  end
 
  def compile_text
    # Gets an array whose elements are the lines of the text document.
    text = Books.get_text(@book_id)
    # Iterate over each line of the text. Break each line up into segments that
    # will fit into the window, then add them all together.
    @pages, lines = [], []
    text.each {|paragraph|
      segment = @text_window.contents.slice_text(paragraph, @window_width - 32)
      segment.each {|line| lines.push(line)}
    }
    # Organizes the lines (12 per page) into pages.
    page_numbers = (lines.size / 12) + 1
    (0...page_numbers).each {|i| @pages[i] = lines[i*12, 12]}
    refresh_text
  end
   
  def refresh_text
    [@text_window.contents, @page_window.contents].each {|bitmap| bitmap.clear}
    # Displays the lines of the current page onto the window.
    page = @pages[@page_number - 1]
    page.each_index {|i|
      @text_window.contents.draw_text(0, i*32, @window_width - 32, 32, page[i])}
    # Set the proper text to the page screen.
    string = "Page #{@page_number}/#{@pages.size}"
    @page_window.contents.draw_text(0, 0, 160, 32, string, 1)
  end
end

class Bitmap
 
  # The slice_text method was created by Blizzard. I take no credit for it.
  def slice_text(text, width)
    words = text.split(' ')
    return words if words.size == 1
    result, current_text = [], words.shift
    words.each_index {|i|
    if self.text_size("#{current_text} #{words[i]}").width > width
      result.push(current_text)
      current_text = words[i]
    else
      current_text = "#{current_text} #{words[i]}"
    end
    result.push(current_text) if i >= words.size - 1}
    return result
  end
end



Instructions

See script.


Compatibility

No known issues.


Credits and Thanks


  • ForeverZer0, for the script
  • Blizzard, for the "slice_text" method
  • Taiine , for requesting it




Author's Notes
Please let me know if any bug/issues are found.
Enjoy!
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Taiine

Oh my god this is fantastic! <3 No mess, no hassle, so easy to use! Best of no NO ANNOYING FORMATTING OF THE TEXT FILES!  <3 <3 <3 <3 <3 <3 <3 <3 <3 <3 <3 <3 <3 <3

One little little extra request? An added option to select a book to read, with out the little side menu? Like find a book, pick it up and you read, with just the title, pages, and the text? Then can have it as it currently is as a list to go back to reread past books you already found.

Oh and.. is the text size thing really part of it? :P I made the mistake of going SIZE 6 and like holy molly that's tinny, and changing all the game text. It was very much so silly XD

ForeverZer0

I can make a quick mod for you to change the display.

As for the text size thing, that was just to show how the page will format to whatever the font and size are. I wouldn't use size 6 either. This will make it so that the text always is formatted correctly, even if the player has control of the font and font size. The only drawback is that the text cannot be pre-formatted and stored, which causes that half a second of lag when you first select a book and it needs to open the text document, etc.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Jragyn

A bit off topic, but Zer0, you should make all the list of scripts in your signature actual links to said scripts.
Dats convenient.
I think all scripters should have that! (cept maybe Blizzard, cuz he's got...a LOT.)

  :^_^':
A bright light can either illuminate or blind, but how will you know which until you open your eyes?

Blizzard

Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

Good idea about the sig. I think it needs updated anyway.  ;)
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Taiine

That mod will be swell. :3

So fare I have seen no bugs even when tossed in my script computability testing game, it works fine with everything I use.

ForeverZer0

* Updates to Version 1.1 *
Okay try that out. It now has the option of how you want the text window to be displayed.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Taiine

September 03, 2010, 06:31:16 pm #8 Last Edit: September 04, 2010, 05:02:37 am by Taiine
Nice once again! However don't think you fully grasped what I asked.  :^_^':

Like to be able to read a book with out going through the list. Like going to a library, picking a book and instantly going to the book text and reading. Then (for me anyway) the list could be of books you've already read to reread again... or not use the list scene at all and go back to each book in game to reread it.

Taiine


Taiine

I think this was forgotten about.  :hm:

ForeverZer0

Quote from: Taiine on September 20, 2010, 01:04:10 pm
I think this was forgotten about.  :hm:


Patience, grasshopper. This is not on my list of high priorities.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ravenith

Very, very nice one! Thanks! Maybe port it to VX too? There's no book scripts for VX if I'm not mistaken, and I sure could use one..

(Why do I use VX? Long story... :/ )

ForeverZer0

Okay, I updated to 1.2
You can now just call the scene with an argument that will have the desired book all ready to go, without having any book list. The other option is still there,

Use this to call the scene:
$scene - Scene_Book.new(BOOK_INDEX)


Or just ignore the argument and it will open with the list displayed.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Karltheking4

Hey, this is a really epic script!
But, I was wondering if there was something in the script I could edit to make a picture display at the bottom of the page, that varies from each book, any ideas?
It should be simple I think :)

something like:
if 0 then $game_screen.pictures[3].show(1, 1, 1, 1, 1, 1, 1, 1)


But I dunno...

Taiine

Hey FZ0, Can I make a small added request with this?
I'd like to be able to change the font color of the text as well as the font used. I tried it myself, but each time I try it throws back an error.
Rather with
@text_window.font.color
@self.contents.font.color
same with font type.
yet
@text_window.windowskin
worked just fine to change the window skin O.o;;;

ForeverZer0

The correct syntax would be :

@text_window.contents.font.name = 'FONTNAME'
@text_window.contents.font.size = SIZE
@text_window.contents.font.color = Color.new(R, G, B, ALPHA)


The window is a sprite, which has no methods for font, but "contents" refers the sprite's bitmap, which does.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ryex

oh look, more lazy mods :V
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

I just went through the script section and found more than 10 script topics that haven't been moved. O_o
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

December 05, 2010, 05:46:04 am #19 Last Edit: December 05, 2010, 05:47:09 am by Ryex
they are all topics that don't have the template applied I take it? because I couldn't find these topics.


Zer0, I'm sorry were gonna hijack your thread and discuses moderation of the RGSS section now :V:
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

LMAO!

Actually only 2 of them. The rest had a proper template applied. There were even a couple of F0's topics. xD
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

Hijack away. I'm easy going and don't mind.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Elemental Crisis

Hello,

Thanks for creating this script, spent quite a bit of time looking for such a script before stumbling onto this one. Just got a few questions.

A couple of my book titles are pretty long and such the text becomes pretty scrunched up, I've thought of 2 possible solutions but seeing how I'm pretty new at scripting haven't been able to incorporate them. 

Method 1: If the book name is longer then X characters then a "..." is added.
Method 2: Creating a similar function as FULLSCREEN_ENTRY but for the book names.

In a future version could you add the ability to include chapters? Where when you click the desired book a sub-menu opens allowing you to select which chapter? Also if your able to name the chapters that would be great as well.

Again, thanks for the script.

Xuroth

Yes, thank you ForeverZer0 for this awesome script. I agree with Elemental Crisis about the chapters addition with the ability to name chapters. I may try to tweak this script (I am still learning RGSS lol) to add that function for my own use. Thanks again!