Enelvon

SES: Window_Book

Nov 29th, 2012
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 36.59 KB | None | 0 0
  1. ###############################################################################
  2. # SES: Window_Book
  3. #   ***Scripter's Resource (Minimal scripting knowledge required!)***
  4. # v1.4
  5. # 11.20.2012
  6. # Compatibility: VXAce/RGSS3
  7. # Author: Enelvon
  8. #===============================================================================
  9. # Terms of Use:
  10. #
  11. # This script may be used for free in any game, whether it's commercial or not.
  12. # The only requirement is that I be credited in some visible manner. You may not
  13. # claim this script as your own work. You are free to modify this script, but
  14. # may not redistribute it except for in a thread that I have started that relates
  15. # to it in some way.
  16. #===============================================================================
  17. # Changelog:
  18. # 11.18.2012: v1.0 - Script written.
  19. # 11.19.2012: v1.1 - Fixed a bug with escape characters where only the first one
  20. #                    would be processed for each word.
  21. # 11.19.2012: v1.2 - Fixed a second escape character bug where they were not
  22. #                    being applied correctly.
  23. # 11.19.2012: v1.3 - Added in [Scene_Book] to allow simple books to be displayed
  24. #                    a little more easily.
  25. # 11.20.2012: v1.4 - Modified [write_page_text] to be able to take parameters.
  26. #===============================================================================                          
  27. # This script is my darling. It's a versatile way to create multi-page windows -
  28. # and it is definitely NOT plug-and-play. You need to at (at the very least)
  29. # read the instructions to get any use out of it, but after that even a
  30. # non-scripter should be able to create wonderful books.
  31. #
  32. # *clears her throat* Now that I have that out of the way, this script is
  33. # essentially a scripter's resource. It provides a parent class for multi-page
  34. # windows, with a focus on those used to display information (though it is also
  35. # possible, with some additions, to include pages with selectable areas). Its
  36. # write_page_text method draws text with the draw_text_ex method, allowing
  37. # you to use any control character that you would normally use in game text.
  38. # Further down, I have included a tutorial on creating a basic game controls
  39. # guide as an example of a simple use of the script.
  40. #===============================================================================
  41. # Required Scripts: None
  42. # Known Incompatibilities: None, and as this is a new class (and thus contains
  43. #     no redefinitions of the base scripts), it should never have any.
  44. #===============================================================================
  45. # Installation: Place below Materials and above all other custom scripts, or
  46. #     with the Window_* classes if you want to keep things organized.
  47. #===============================================================================
  48. # Instructions:
  49. #
  50. #   This script serves as a resource to create multi-page windows. I will use
  51. #   this space to give an example of how to make and display a simple book that
  52. #   contains the controls for the game.
  53. #
  54. #   The first thing that we have to do is create a new window class. Let's call
  55. #   it Guide.
  56. #
  57. #     class Guide < Window_Book
  58. #
  59. #   Okay, so we've opened our class. Now we need to define our initialize method.
  60. #   It will contain our definition of @pagetext.
  61. #
  62. #     class Guide < Window_Book
  63. #
  64. #       def initialize
  65. #         @pagetext = {
  66. #           2 => ["In this mini guide you will be given a basic introduction to playing the game. I hope it proves informative."],
  67. #           3 => ["\\c[16]Button Controls:", "", "\\c[16]Movement:",
  68. #                 "Use the direction keys to move your character on the map, and your cursor when in menus. Hold down Shift to run. When you are in a character-related menu, you can use Q, W, PgDn, and PgUp to move between characters.",
  69. #                 "", "\\c[16]Opening the Menu:",
  70. #                 "Press X, 0 on the number pad, or Esc to open the menu when you are on the map.",
  71. #                 "", "\\c[16]Selection:",
  72. #                 "Press Z, Space or Enter to interact with characters and items on the map, or to make a selection when in a menu.",
  73. #                 "", "\\c[16]Cancelling:",
  74. #                 "Press X, 0 on the number pad, or Esc to go back in a menu or cancel a choice."],
  75. #           4 => ["\\c[16]File Operations:", "", "\\c[16]Saving Your Game:",
  76. #                 "Select \\c[16]Save \\c[0]from the in-game menu and choose a slot in which to save your game.",
  77. #                 "", "\\c[16]Loading Your Game:",
  78. #                 "If you are currently in the game, return to the title screen. Select \\c[16]Load Game \\c[0]and choose the slot you want to load."],
  79. #           5 => ["Have fun, and good luck!"]
  80. #         }
  81. #         super
  82. #       end
  83. #
  84. #   Sorry about how long those text lines are, but going down to a new line and
  85. #   having indentations causes the formatting to be hideous when the text is
  86. #   drawn. Anyway, as you can see, we're able to use control characters from
  87. #   the game's message windows in our text. Always make sure to use two (rather
  88. #   than one) backslashes for the control character, and that it is attached to
  89. #   the first word/character that it is intended to affect. I skipped page 1
  90. #   because we'll do that a little differently - we're going to center the text
  91. #   for it and place it near the top of the page, as it's the cover of the book.
  92. #
  93. #       def initialize
  94. #         @pagetext = {
  95. #           2 => ["In this mini guide you will be given a basic introduction to playing the game. I hope it proves informative."],
  96. #           3 => ["\\c[16]Button Controls:", "", "\\c[16]Movement:",
  97. #                 "Use the direction keys to move your character on the map, and your cursor when in menus. Hold down Shift to run. When you are in a character-related menu, you can use Q, W, PgDn, and PgUp to move between characters.",
  98. #                 "", "\\c[16]Opening the Menu:",
  99. #                 "Press X, 0 on the number pad, or Esc to open the menu when you are on the map.",
  100. #                 "", "\\c[16]Selection:",
  101. #                 "Press Z, Space or Enter to interact with characters and items on the map, or to make a selection when in a menu.",
  102. #                 "", "\\c[16]Cancelling:",
  103. #                 "Press X, 0 on the number pad, or Esc to go back in a menu or cancel a choice."],
  104. #           4 => ["\\c[16]File Operations:", "", "\\c[16]Saving Your Game:",
  105. #                 "Select \\c[16]Save \\c[0]from the in-game menu and choose a slot in which to save your game.",
  106. #                 "", "\\c[16]Loading Your Game:",
  107. #                 "If you are currently in the game, return to the title screen. Select \\c[16]Load Game \\c[0]and choose the slot you want to load."],
  108. #           5 => ["Have fun, and good luck!"]
  109. #         }
  110. #         super
  111. #       end
  112. #
  113. #       def draw_page1
  114. #         x = (contents_width - text_size("Game Guide").width) / 2
  115. #         y = (contents_height - line_height) / 4
  116. #         draw_text_ex(x, y, "\\c[14]Game Guide")
  117. #       end
  118. #
  119. #   Here we find the center of the book page horizontally and 1/4 of the page
  120. #   vertically, then draw the text there. Now, we have five pages in our
  121. #   @pagetext hash, so the next thing we should do is define max_pages.
  122. #
  123. #       def initialize
  124. #         @pagetext = {
  125. #           2 => ["In this mini guide you will be given a basic introduction to playing the game. I hope it proves informative."],
  126. #           3 => ["\\c[16]Button Controls:", "", "\\c[16]Movement:",
  127. #                 "Use the direction keys to move your character on the map, and your cursor when in menus. Hold down Shift to run. When you are in a character-related menu, you can use Q, W, PgDn, and PgUp to move between characters.",
  128. #                 "", "\\c[16]Opening the Menu:",
  129. #                 "Press X, 0 on the number pad, or Esc to open the menu when you are on the map.",
  130. #                 "", "\\c[16]Selection:",
  131. #                 "Press Z, Space or Enter to interact with characters and items on the map, or to make a selection when in a menu.",
  132. #                 "", "\\c[16]Cancelling:",
  133. #                 "Press X, 0 on the number pad, or Esc to go back in a menu or cancel a choice."],
  134. #           4 => ["\\c[16]File Operations:", "", "\\c[16]Saving Your Game:",
  135. #                 "Select \\c[16]Save \\c[0]from the in-game menu and choose a slot in which to save your game.",
  136. #                 "", "\\c[16]Loading Your Game:",
  137. #                 "If you are currently in the game, return to the title screen. Select \\c[16]Load Game \\c[0]and choose the slot you want to load."],
  138. #           5 => ["Have fun, and good luck!"]
  139. #         }
  140. #         super
  141. #       end
  142. #
  143. #       def draw_page1
  144. #         x = (contents_width - text_size("Game Guide").width) / 2
  145. #         y = (contents_height - line_height) / 4
  146. #         draw_text_ex(x, y, "\\c[14]Game Guide")
  147. #       end
  148. #
  149. #       def max_pages; 5; end
  150. #     end
  151. #
  152. #   There we go! As you can see, I ended the Guide class after defining
  153. #   max_pages. Why? Because it's done! We created a five-page book in 20 lines,
  154. #   and 7 of those were used to define the contents of the pages! Isn't that
  155. #   easy?
  156. #
  157. #   We're not quite done, though. We have one more task ahead of us: calling the
  158. #   window for display. Prior to version 1.3, this had to be done by creating
  159. #   a new class and calling that. 1.3 introduced the Scene_Book class, which
  160. #   simplified this for basic users - advanced books will still need their own
  161. #   classes if they're going to be used for anything but simple reading. To call
  162. #   the default book scene with the guide, put this in an event:
  163. #
  164. #     show_book(Guide)
  165. #
  166. #   That will display the book, as I've added the show_book command to the Game
  167. #   Interpreter class. You could also use this:
  168. #
  169. #     SceneManager.goto(Scene_Book)
  170. #     SceneManager.scene.set_book(Guide)
  171. #
  172. #   show_book is a little faster, though. You can replace Guide with the name of
  173. #   your book to show whatever you'd like - let's say we have a book window
  174. #   named Biology_Textbook. We would use this:
  175. #
  176. #   show_book(Biology_Textbook)
  177. #
  178. #   Note that show_book will return to the scene it was called from when the
  179. #   book is closed.
  180. #
  181. #   That's it! Congratulations, you've created a guide! Your players will never
  182. #   have to puzzle over the controls again!
  183. #
  184. #   Anyway, I hope you can see how easy it is to use this as a base to make your
  185. #   own books. I can't wait to see what you come up with - make sure to let me
  186. #   know if you use it! Feel free to read over the rest of the script - it's
  187. #   my most thoroughly commented to date, and I am very proud of it. Let me
  188. #   know if anything is unclear, and I will do my best to help you understand.
  189. #
  190. ################################################################################
  191.  
  192. $imported = {} if $imported.nil?
  193. $imported["SES - Window_Book"] = 1.4
  194.  
  195.  
  196. #==============================================================================
  197. #   Window_Book
  198. #   This is a parent class for multi-page windows of various kinds. The most
  199. #   basic use for it is to make books.
  200. #==============================================================================
  201. class Window_Book < Window_Base
  202.   #=============================================================================
  203.   #   Local Variables
  204.   #     The most important one of these, as well as the only one that is
  205.   #     initialized here, is @pagetext. @pagetext is a hash of arrays, one per
  206.   #     page of the book. The arrays contain stringss that represent the text
  207.   #     on the page. The text will automatically wrap to avoid going off of the
  208.   #     screen. Each separate string moves down to a new line - \n will not work
  209.   #     in the text strings. Any of the standard control characters for a VXAce
  210.   #     message window will, however. When write_page_text is called, the text
  211.   #     for the current page will be drawn onto the window.
  212.   #=============================================================================
  213.   attr_accessor :pagetext
  214.   #=============================================================================
  215.   #   Initialize - sets up the window.
  216.   #     Takes an x-coordinate, a y-coordinate, the width of the window,
  217.   #     the height of the window, the wrap type, and the name of the windowskin
  218.   #     you want the book to use (optional, must be a Bitmap [the class, not the
  219.   #     file type]). The wrap type can be either :word or :char. :word wrapping
  220.   #     will wrap text to a new line at word boundaries, while :letter wrapping
  221.   #     will wrap it at character boundaries, which can avoid issues with
  222.   #     absurdly long words - though it is unlikely to ever be necessary, as not
  223.   #     many (real) words would be wider than the game window. It is only likely
  224.   #     to be an issue if your child window is very small. By default, the
  225.   #     window will cover the entire game screen. Please also note that escape
  226.   #     characters are not available in :letter wrap mode, which should be
  227.   #     obvious as it processes letter-by-letter. I may include handling to
  228.   #     alter that later, but for now stick to word wrap mode if you're using
  229.   #     escape characters.
  230.   #=============================================================================
  231.   def initialize(x = 0, y = 0, width = 544, height = 416, wrap_type = :word, skin = nil)
  232.     #===========================================================================
  233.     #   Here we set the windowskin for the book. It can be provided in the
  234.     #   constructor of your window when it calls super, or you can rely on this
  235.     #   default setting which will, if my Window Swap script is active, cause
  236.     #   it to use a file called "Book Window" found in the Graphics/Windows
  237.     #   folder. If you are not using the aforementioned script, it will use the
  238.     #   default windowskin. You may modify this section to change the default
  239.     #   setting if you wish, but I would leave in the "skin ||" part so that
  240.     #   children of this class can still provide their own windows.
  241.     #
  242.     #   If you choose to provide a windowskin from a child class, it must be as
  243.     #   a Bitmap rather than a file name, so remember to load it up. A child
  244.     #   window's call to this method that provides a windowskin would look
  245.     #   something like this:
  246.     #   super(0, 0, 544, 416, Cache.windows("Child Window"))
  247.     #
  248.     #   We also set @wrap to our desired wrap type and initialize @pagetext to
  249.     #   an empty hash with an empty array as its default value, though if
  250.     #   @pagetext has already been initialized (which it should have in a child
  251.     #   class) it will only set the default, not empty the hash.
  252.     #===========================================================================
  253.     @skin = skin || ($imported["SES - Window Swap"] ? Cache.windows("Book Window") : Cache.system("Window"))
  254.     @wrap = wrap_type; @pagetext ||= {}; @pagetext.default = []
  255.     super(x, y, width, height)
  256.     #===========================================================================
  257.     #   This sets the Z-value of the window to 255, to make sure
  258.     #   that it displays on top of everything else, and defaults @page (a local
  259.     #   variable that holds an integer that determines the current page) to 1.
  260.     #   It then builds the window's contents and sets it as the active window.
  261.     #===========================================================================
  262.     self.z, @page = 255, 1; refresh; activate
  263.   end
  264.   #=============================================================================
  265.   #   Update - updates the window.
  266.   #=============================================================================
  267.   def update
  268.     super
  269.     #===========================================================================
  270.     #   Here we check for action from the directional keys - scrolling between
  271.     #   pages and up/down within a page, if applicable. It also updates the
  272.     #   page number display at the bottom of the window.
  273.     #===========================================================================
  274.     process_cursor_move; scrolldata.each_key do |k| eval("@#{k}.update") end
  275.   end
  276.   #=============================================================================
  277.   #   Dispose - disposes the window.
  278.   #=============================================================================
  279.   def dispose
  280.     #===========================================================================
  281.     #   This disposes the page number display at the bottom of the window when
  282.     #   the window is closed. It has to be done before the call to super, or
  283.     #   the window will be disposed first, which prevents us from disposing
  284.     #   any remaining pieces of it. That would leave the numbers and page arrows
  285.     #   floating on the screen, which we do not want.
  286.     #===========================================================================
  287.     scrolldata.each_key do |k| eval("@#{k}.dispose") end
  288.     super
  289.   end
  290.   #=============================================================================
  291.   #   Max Pages - the total number of pages that the book contains.
  292.   #     Override this in your child class and have it return the number of pages
  293.   #     that your book has. I chose to do this with a method rather than a
  294.   #     variable as by using a method logic can be implemented, varying the
  295.   #     number of pages in different situations.
  296.   #=============================================================================
  297.   def max_pages; 1; end
  298.   #=============================================================================
  299.   #   Dy - how far from the top of the window the first text will be drawn.
  300.   #     Override this in your child class and have it return the height (often
  301.   #     in lines - this method is typically defined as # * line_height) that you
  302.   #     wish to have as the offset. My reasoning for having this as a method is
  303.   #     the same as my reasoning for having Max Pages as a method.
  304.   #=============================================================================
  305.   def dy; 0; end
  306.   #=============================================================================
  307.   #   Refresh - refreshes the window.
  308.   #=============================================================================
  309.   def refresh
  310.     #===========================================================================
  311.     #   Here we set the Y-origin for the window's display to 0, so that the new
  312.     #   page will display from the top even if the player had scrolled all the
  313.     #   way to the bottom of the previous page. We also build the contents for
  314.     #   the current page, draw the page number display, and then draw whatever
  315.     #   the page is intended to contain. When creating a child window for this
  316.     #   class, make sure to create a draw_page# method for each page in the
  317.     #   window. I've set things up so that a page will remain blank (or display
  318.     #   its text from @pagetext, if it has any) if the method doesn't exist
  319.     #   rather than throwing an error and crashing, but that's no excuse to
  320.     #   leave a poor little page without a handler! Well, unless you're just
  321.     #   displaying text, but still. Try to be creative! You can create
  322.     #   encyclopedias with pictures, or magazines with articles set in various
  323.     #   column styles, or dozens of other things! Don't limit yourself to just
  324.     #   plain books - though those are good, too.
  325.     #===========================================================================
  326.     self.oy = 0; create_contents; draw_scroll; eval("draw_page#{@page}")
  327.   end
  328.   #=============================================================================
  329.   #   Contents Height - returns the height of the window's contents.
  330.   #     This is used to calculate whether or not the window needs to be able to
  331.   #     scroll, among other things.
  332.   #
  333.   #     If you create a child window that uses more than just text, you will
  334.   #     probably have to overwrite this method. Make sure to include a call to
  335.   #     the super somewhere in your method - you will likely want to add
  336.   #     something to the result of the super to get the height of the window.
  337.   #     For example, say we have a page with an image that is 54 pixels tall,
  338.   #     and we want to include it as well as a 3 pixel border at the top and
  339.   #     bottom in addition to some text from @pagetext. The picture is only on
  340.   #     page 2. We would have a method that looks something like this inside of
  341.   #     our child class:
  342.   #     def contents_height
  343.   #       addedHeight = if @page == 2 then 60
  344.   #                     else 0 end
  345.   #       super + addedHeight
  346.   #     end
  347.   #
  348.   #     It takes a padding value, used to determine the amount of vertical
  349.   #     padding to give the window.
  350.   #=============================================================================
  351.   def contents_height(padding = 2)
  352.     #===========================================================================
  353.     #   Here we set i equal to dy / line_height + 1, or the number of lines that
  354.     #   appear above our text as well as a line of padding at the bottom. i is
  355.     #   an integer that holds the number of rows of text that the page contains.
  356.     #   It is multiplied by 24 to find the height of the contents in pixels. We
  357.     #   also create b, a dummy bitmap used to test the size of the text to help
  358.     #   determine whether or not we need to wrap to a new row. b is necessary
  359.     #   because the contents of the window, which would normally be used for the
  360.     #   text_size method, are disposed during the create_contents method, which
  361.     #   is where this is most needed.
  362.     #===========================================================================
  363.     i, b = dy / line_height + 1, Bitmap.new(1,1)
  364.     #===========================================================================
  365.     #   In here we loop through the strings in @pagetext's array for the current
  366.     #   page. In word wrap mode we break them apart into words by splitting them
  367.     #   at spaces, then test if adding the next word would cause the line to run
  368.     #   off of the window. If it would, we instead add a new line. In character
  369.     #   wrap mode, we break it apart at each character instead of each space.
  370.     #   If wrapping occurs, we ignore leading spaces in order to avoid
  371.     #   unnecessary white space.
  372.     #===========================================================================
  373.     @page ||= 1
  374.     @pagetext[@page].each do |l|
  375.       if @wrap == :word then t = l.split(/\s/)
  376.       else t = []; l.each_char do |c| t.push(c) end end
  377.       x = 0
  378.       t.each do |w|
  379.         dw = convert_escape_characters(w).gsub(/\\(\w)(\[(\w+)\])?/) { "" }
  380.         (i += 1; x = 0) if x + b.text_size(dw + (@wrap == :word ? " " : "")).width > contents_width
  381.         next if x == 0 && w == " "
  382.         x += b.text_size(dw + (@wrap == :word ? " " : "")).width
  383.       end
  384.       i += 1
  385.     end
  386.     #===========================================================================
  387.     #   Here we return the number of lines as a number of pixels, if it's larger
  388.     #   than the default height given. If not, it uses the default height.
  389.     #===========================================================================
  390.     return [line_height*i, height - standard_padding * padding].max
  391.   end
  392.   #=============================================================================
  393.   #   Method Missing - this is where I handle missing draw_page# methods to
  394.   #         prevent errors.
  395.   #=============================================================================
  396.   def method_missing(method)
  397.     #===========================================================================
  398.     #   Here we check whether the missing method is a draw_page# method. If it
  399.     #   is, we default to using write_page_text to print the page's information
  400.     #   from @pagetext. If it's not, an error will be thrown.
  401.     #===========================================================================
  402.     if method =~ /^draw_page(\d+)$/ then write_page_text
  403.     else super end
  404.   end
  405.   #=============================================================================
  406.   #   Write Page Text - writes the current page's information from @pagetext to
  407.   #         the window.
  408.   #     I love all of my daughter here dearly, but this is, without a doubt, my
  409.   #     favourite feature of hers. It's pretty much the script equivalent of a
  410.   #     beautiful singing voice. We take the strings contained in @pagetext
  411.   #     and write them to the screen, wrapping to the next line at word
  412.   #     boundaries when it becomes necessary. The one potential issue with this
  413.   #     method is that if you have a word that's longer than the window is wide,
  414.   #     it will never display and the window will hang. This can be avoided by
  415.   #     using :letter wrap mode, but that doesn't allow for the use of escape
  416.   #     characters. You can also call this method with an array and a starting
  417.   #     line in order to place text wherever you'd like. Additionally, you may
  418.   #     specify a newline boundary to add to the front of any wrapped line,
  419.   #     allowing you to tab long lines in lists.
  420.   #=============================================================================
  421.   def write_page_text(text = @pagetext[@page], i = 0, newline_boundary = "", mode = :ex)
  422.     #===========================================================================
  423.     #   In here we loop through the strings in the text array for the current
  424.     #   page. In word wrap mode we break them apart into words by splitting them
  425.     #   at spaces, then test if adding the next word would cause the line to run
  426.     #   off of the window. If it does not, we write the word to the screen. If
  427.     #   it would, we add a new line and then write the word. In character wrap
  428.     #   mode, we break it apart at each character instead of each space. If
  429.     #   wrapping occurs, we ignore leading spaces in order to avoid unnecessary
  430.     #   white space. It returns the index of the next empty row.
  431.     #===========================================================================
  432.     @page ||= 1
  433.     text.each do |l|
  434.       if @wrap == :word then t = l.split(/\s/)
  435.       else t = []; l.each_char do |c| t.push(c) end end
  436.       cc, x = "", 0
  437.       t.each do |w|
  438.         w = convert_escape_characters(w).gsub(/\e(\w)(\[(\w+)\])?/) { |s| cc += s; "" }
  439.         (i += 1; x = 0; w.insert(0, newline_boundary)) if x + text_size(w + (@wrap == :word ? " " : "")).width > contents_width
  440.         rect = Rect.new(x, i * line_height + dy, contents_width, line_height)
  441.         next if x == 0 && w == " "
  442.         if mode == :ex then draw_text_ex(rect.x, rect.y, cc + w + (@wrap == :word ? " " : ""))
  443.         else draw_text(rect, w + (@wrap == :word ? " " : "")) end
  444.         x += text_size(w + (@wrap == :word ? " " : "")).width
  445.       end
  446.       i += 1
  447.     end
  448.     return i
  449.   end
  450.   #=============================================================================
  451.   #   Arrow Bitmap - defines the bitmap from which the window's arrows will be
  452.   #         taken.
  453.   #     This will provide the arrow sprites with the windowskin in order to get
  454.   #     their arrows if they should be visible.
  455.   #=============================================================================
  456.   def arrow_bitmap(d)
  457.     #===========================================================================
  458.     #   Here we check what page we're on. If we're past the first page we'll
  459.     #   give the left arrow the windowskin so that it will be visible, and if
  460.     #   we're not on the last page we'll give it to the right arrow.
  461.     #===========================================================================
  462.     self.windowskin if (@page < max_pages && d == :r) || (@page > 1 && d == :l)
  463.   end
  464.   #=============================================================================
  465.   #   Sx - the base X position for the page number data.
  466.   #     This calculates where in the X plane the page number and arrows generated
  467.   #     by draw_scroll should be placed.
  468.   #=============================================================================
  469.   def sx
  470.     #===========================================================================
  471.     #   We take the maximum possible size for the page number display and devise
  472.     #   a starting X coordinate based on that.
  473.     #===========================================================================
  474.     self.x +
  475.     (contents_width - text_size("#{max_pages}/#{max_pages}").width + 4) / 2 - 5
  476.   end
  477.   #=============================================================================
  478.   #   Scrolldata - information about the page number display, including the
  479.   #         source information for the arrows.
  480.   #     This returns a hash of information, all of which will be drawn by
  481.   #     draw_scroll when it is run.
  482.   #=============================================================================
  483.   def scrolldata
  484.     #===========================================================================
  485.     #   First we calculate an X value to help us display the right arrow. After
  486.     #   that, we calculate the y value at which the information should be drawn.
  487.     #===========================================================================
  488.     x = text_size("#{max_pages}/#{max_pages}").width + 4
  489.     y = if Graphics.height - height == 0 then height - 28
  490.         else self.y + height - 28 end
  491.     #===========================================================================
  492.     #   Here's the meat of the method. You may need to edit the src_rect
  493.     #   information for the arrows if you're using a custom windowskin - it's
  494.     #   configured to use the base. Note that each of the keys in this hash
  495.     #   will become a Sprite object when draw_scroll is called.
  496.     #
  497.     #   Each key in the main hash is linked to a second hash. There are 5
  498.     #   possible values in that second hash:
  499.     #   :x => Easy enough. This is the X coordinate at which the item will be
  500.     #         drawn.
  501.     #   :y => Also easy - the Y coordinate for drawing.
  502.     #   :bitmap => The Sprite's bitmap. For :pagecount, this should be an empty
  503.     #         bitmap placed at the x we calculated earlier. Its height should be
  504.     #         equivalent to line_height - I simply set it at 24 (the default
  505.     #         value for line_height) for visibility.
  506.     #   :src_rect => The visible portion of the Sprite's bitmap. You'll need to
  507.     #         change this for :rarrow and :larrow if you're using a custom
  508.     #         windowskin that has arrows of a different size than those in the
  509.     #         default window.
  510.     #   :d_rect => :pagecount only. This should be the same as :src_rect. It
  511.     #         exists to simplify drawing the page numbers and so that if you
  512.     #         overwrite/extend this method with new Sprites you can have the
  513.     #         page numbers drawn in the way you want.
  514.     #===========================================================================
  515.     { :pagecount => { :x => sx + 10, :y => y - 7,
  516.         :bitmap => Bitmap.new(x, 24), :src_rect => Rect.new(0,0,x+4,line_height),
  517.         :d_rect => Rect.new(0, 0, x + 4, line_height) },
  518.       :rarrow => { :x => sx + x + 28, :y => y,
  519.         :bitmap => arrow_bitmap(:r), :src_rect => Rect.new(104,25,7,12) },
  520.       :larrow => { :x => sx - 12, :y => y,
  521.         :bitmap => arrow_bitmap(:l), :src_rect => Rect.new(80,25,7,12) } }
  522.   end
  523.   #=============================================================================
  524.   #   Draw Scroll - draws the sprites defined in Scrolldata.
  525.   #     This takes the hash from Scrolldata and creates a sprite for each key,
  526.   #     using the values defined in the key's hash.
  527.   #=============================================================================
  528.   def draw_scroll
  529.     #===========================================================================
  530.     #   First we get the key and value pair from the hash. If the Sprite
  531.     #   currently exists, we dispose it so that we can redraw it in a new way.
  532.     #   We then create the Sprite and set its x, y, and z values as well as its
  533.     #   bitmap and src_rect. After that, we draw the page numbers in any Sprite
  534.     #   that has a d_rect defined.
  535.     #===========================================================================
  536.     scrolldata.each_pair do |k,v|
  537.       eval("@#{k}.dispose if !@#{k}.nil?
  538.      @#{k},      @#{k}.x, @#{k}.y, @#{k}.z, @#{k}.bitmap, @#{k}.src_rect  =
  539.      Sprite.new, v[:x],   v[:y],   255,     v[:bitmap], v[:src_rect]
  540.      @#{k}.bitmap.draw_text(v[:d_rect], '#{@page}/#{max_pages}', 1) if v[:d_rect]
  541.      ")
  542.     end
  543.   end
  544.   #=============================================================================
  545.   #   Process Cursor Move - this is where we check if the player is scrolling
  546.   #         through the window.
  547.   #     It checks for direction key input and performs actions based on whether
  548.   #     or not there is.
  549.   #=============================================================================
  550.   def process_cursor_move
  551.     #===========================================================================
  552.     #   First we set oldpage to the current page number, so that we can check
  553.     #   if the page ended up changing. Then we check if the player has pressed
  554.     #   left - if they have and we are not on the first page, we go back a page.
  555.     #   After that we check if they have pressed right, and go forward if we
  556.     #   are not on the last page. Then we move on to scrolling up and down
  557.     #   within a page - if they hit up and are not at the top of the page, it
  558.     #   will scroll up, and if they hit down and are not at the bottom of the
  559.     #   page it will scroll down. After we are done checking for input, we
  560.     #   redraw the page if the page has changed.
  561.     #===========================================================================
  562.     (@changed = false; return) if @changed
  563.     oldpage = @page
  564.     if Input.trigger?(:LEFT) && 1 < @page then @page -= 1
  565.     elsif Input.trigger?(:RIGHT) && @page < max_pages then @page += 1
  566.     elsif ((Input.press?(:UP)) if Input.repeat?(:UP)) && self.oy > 0
  567.       self.oy -= 24; draw_scroll
  568.     elsif ((Input.press?(:DOWN)) if Input.repeat?(:DOWN)) && contents_height(4) + 24 - height >= self.oy
  569.       draw_scroll; self.oy += 24 end
  570.     (refresh; @changed = true) if oldpage != @page
  571.   end
  572. end
  573.  
  574. #===============================================================================
  575. #   Game_Interpreter
  576. #     This is a default class that handles event processing. I have defined the
  577. #     show_book method in here to allow for quick display of simple books.
  578. #===============================================================================
  579. class Game_Interpreter
  580.   #=============================================================================
  581.   #   Show Book - this method calls the Scene_Book class.
  582.   #     This method takes the name of a book class (and potentially a second
  583.   #     scene to go to after the player closes the book - if no second scene is
  584.   #     entered it will default to Scene_Map) and displays the book contained
  585.   #     in the class.
  586.   #=============================================================================
  587.   def show_book(book)
  588.     SceneManager.goto(Scene_Book); SceneManager.scene.set_book(book)
  589.   end
  590. end
  591.  
  592. #===============================================================================
  593. #   Scene_Book
  594. #     This is a class that displays simple books. It allows the player to read
  595. #     the book, and will return to the given scene when closed.
  596. #===============================================================================
  597. class Scene_Book < Scene_Base
  598.   #=============================================================================
  599.   #   Set Book - this method selects the book that the class should display, as
  600.   #         well as what class the game should go to when the player closes the
  601.   #         book.
  602.   #     This method takes the name of a book class and sets the scene's book
  603.   #     object to the given book. It also takes the name of a class, and sets
  604.   #     the class that will open when the book is closed to that class.
  605.   #=============================================================================
  606.   def set_book(book)
  607.     @book = book.new
  608.   end
  609.   #=============================================================================
  610.   #   Update - this method updates the class.
  611.   #     If the scene contains a book, it updates the book. If there is no book,
  612.   #     it will wait for one to be given with set_book. If the player presses
  613.   #     a Cancel button, it will close the book and go to the next scene.
  614.   #=============================================================================
  615.   def update
  616.     super
  617.     @book.update if @book
  618.     SceneManager.return if Input.trigger?(:B)
  619.   end
  620. end
Advertisement
Add Comment
Please, Sign In to add comment