OSP Code QoL Books & scrolls reading presentation

Users who are viewing this thread

Garedyr

Master Knight
Some RPG games have implemented system where you can read book and scrolls. As you probably noticed - books serve no purpose in M&B games except being one time use objects for raising your character stats. That's why I decided to create this bad boy to bring some immersion and content to your mod.


Overwiew​


First, let's take a look at pros & cons of this kit:

Pros:
  • Ease of manipulation - the code is documented and should be easy to modify if you know what you're doing.
  • Versatility - possibilities with this kit are almost limitless. You can start a quest after loading certain page for example.
  • Compatibility - script should be compatible with most of the mods without custom fonts, you should be able to make it multiplayer compatible with no problems. Not sure how it looks like with custom font installed.
  • User friendly GUI - book selection menu is very intuitive and easy to work with.
  • Page generator included - text boxes in this game have weird behavior of changing their position if there's too little or too much text in the string with defined area size. That's why I created a simple pages generator for you in JavaScript so you don't have to match your text with the box size by trial and error for every page.

Cons:
  • Modding experience required - unfortunately, the kit requires you to know at least some fundamentals of M&B scripting. Well, if you know what operations try_begin, else_try, try_end and str_store_string are there for then you should be fine.
  • Your own effort required - you probably know this by know. You're going to add your own books and/or scrolls after all. Also, the presentation is going to look much better if you create your own high-res textures for books.
  • Could still be buggy - I tried my best to ensure that most of the bugs and exploits were taken care of, however I'm only human after all. Please post a comment here if you encounter any bugs or problems.

Now take a look at the screenshots to have an idea how it looks like:
MRMch.jpg
3Da2u.jpg
IqgxT.jpg
tdZJE.jpg
keLdJ.jpg
H13RF.jpg
soEvQ.jpg

*Please take a note that the open book texture and scroll item mesh is not included in the OSP. For the open book mesh I provided you with a texture template with important areas (book cover area, book page area and actual text box area) marked out. Open scroll mesh currently uses Native texture.

How it works:
  • After you press the defined button (default 'B') while in specific mission in mission_templates, the book selection menu will open up. Then you can scroll thru the item menu and select the item you want to read. Additionally, there's an item mesh sneak peak on the left displayed on hower. Currently there are as many selectable items supported as big is the maximum size merchant inventory. Press the defined button again to quit.
  • After you select the item the script get_book_details_from_book_database is called for the item you selected and presentation is automatically closed and re-opened (instant process). The script assigns variables for presentation for the specific item.
  • Basic presentation elements are created for the variables from previous script and script flip_page_for_book is called. It's purpose is to generate the text from ready strings. Note that currently you can have max two pages for scrolls (makes sense, doesn't it) and as many as you like for books. Book pages amount is only limited to as many as the game engine can handle.

Credits:
  • me (Masterancza/Garedyr)
  • rubik (because I took inspiration on how to do item selection menu from one of his OSP's)


Installation​


For a foundation you're going to need the necessary resources. You can find them here.
The file contains:
  • book_generator folder - this folder contains a simple but powerful tool when it comes to generating book and scroll pages for our presentation. Extract it anywhere.
  • Resource folder - you need to either drop the book_reading_osp.brf (which is inside of it) to your mod resources folder or merge it with existing brf file.
  • Textures folder - Here you can find the template open book texture. Just drop the file to your mod's textures folder. You can edit it later.

Next, the presentation code (insert to module_presentations):
Code:
("book_reading", prsntf_manual_end_only, 0,
  [
    (ti_on_presentation_load,
    [
   (presentation_set_duration, 999999),
   (set_fixed_point_multiplier, 1000),
  
   (str_clear, s1), # for left text box
   (str_clear, s2), # for right text box or title
   (str_clear, s3), # for left page number
   (str_clear, s4), # for right page number
  
   ## Menu
   (try_begin),
      (eq, "$g_book", 1),
     
      (create_mesh_overlay, "$g_presentation_obj_1", "mesh_book_menu"),
     
      # Header
      (create_text_overlay, "$g_presentation_obj_title", "@Select a book or scroll^ to read:^^^^^^^^", tf_double_space|tf_center_justify),
      (position_set_x, pos1, 685), # was 655
      (position_set_y, pos1, 385), # 200 530
      (overlay_set_position, "$g_presentation_obj_title", pos1),
      (position_set_x, pos1, 1000), # was 1100
      (position_set_y, pos1, 1000), # was 1100
      (overlay_set_size, "$g_presentation_obj_title", pos1),
      (position_set_x, pos1, 975), # was 945
      (position_set_y, pos1, 150),
      (overlay_set_area_size, "$g_presentation_obj_title", pos1),
     
      # Scrollable area
      (create_text_overlay, "$g_presentation_obj_2", "str_empty_string", tf_scrollable),
      (position_set_x, pos1, 630), # was 600
      (position_set_y, pos1, 250), # was 250
      (overlay_set_position, "$g_presentation_obj_2", pos1),
      (position_set_x, pos1, 168), # was 138
      (position_set_y, pos1, 230), # was 230
      (overlay_set_area_size, "$g_presentation_obj_2", pos1),
     
      # Div begin
      (set_container_overlay, "$g_presentation_obj_2"),
     
         (troop_clear_inventory, "trp_temp_array_a"),
         (troop_get_inventory_capacity, ":inv_cap", "trp_player"),
        
         # Checking player's inventory for books
         (try_for_range, ":i_slot", 0, ":inv_cap"),
            (troop_get_inventory_slot, ":item", "trp_player", ":i_slot"),
            (neq, ":item", -1),
            (item_get_type, ":typ", ":item"),
            (eq, ":typ", itp_type_book),
           
            # Dupe checker
            (assign, ":found_dupes", 0),
           
            (try_for_range, ":dupe_checker", 10, 106),
               (troop_get_inventory_slot, ":possible_dupe", "trp_temp_array_a", ":dupe_checker"),
               (eq, ":possible_dupe", ":item"),
               (val_add, ":found_dupes", 1),
            (try_end),
           
            # Adding item to array if no dupes were found
            (try_begin),
               (eq, ":found_dupes", 0),
               (troop_add_item, "trp_temp_array_a", ":item"),
            (try_end),
         (try_end),
        
         # Assigning base positions
         (assign, ":pos_x", 0),
         (assign, ":pos_y", 1250),
         (assign, ":slot_no", 10),
        
         # A total of 32 rows
         (try_for_range, ":unused_height", 0, 32),
            (try_for_range, ":unused_width", 0, 3), # 3 columns
               (create_mesh_overlay, reg1, "mesh_mp_inventory_choose"),
               (position_set_x, pos1, 320), # was 320
               (position_set_y, pos1, 320), # was 320
               (overlay_set_size, reg1, pos1),
               (position_set_x, pos1, ":pos_x"),
               (position_set_y, pos1, ":pos_y"),
               (overlay_set_position, reg1, pos1),
               (troop_set_slot, "trp_temp_array_a", ":slot_no", reg1),
               (create_mesh_overlay, reg1, "mesh_inv_slot"),
               (position_set_x, pos1, 400), # was 400
               (position_set_y, pos1, 400), # was 400
               (overlay_set_size, reg1, pos1),
               (position_set_x, pos1, ":pos_x"),
               (position_set_y, pos1, ":pos_y"),
               (overlay_set_position, reg1, pos1),
               (troop_get_inventory_slot, ":item_no", "trp_temp_array_a", ":slot_no"),
               (val_max, ":item_no", 0),
               (create_mesh_overlay_with_item_id, reg1, ":item_no"),
               (position_set_x, pos1, 400), # was 400
               (position_set_y, pos1, 400), # was 400
               (overlay_set_size, reg1, pos1),
               (store_add, ":item_x", ":pos_x", 20),
               (store_add, ":item_y", ":pos_y", 20),
               (position_set_x, pos1, ":item_x"),
               (position_set_y, pos1, ":item_y"),
               (overlay_set_position, reg1, pos1),
               (troop_set_slot, "trp_temp_array_b", ":slot_no", reg1),
               (val_add, ":pos_x", 40),
               (val_add, ":slot_no", 1),
            (try_end),
           
            (assign, ":pos_x", 0),
            (val_sub, ":pos_y", 40),
         (try_end),
      (set_container_overlay, -1),
      # Div end
     
      # Hint
      (create_text_overlay, "$g_presentation_obj_3", "@Press 'B' again to quit", tf_with_outline|tf_center_justify),
      (overlay_set_color, "$g_presentation_obj_3", 0xFFFFFF),
      (position_set_x, pos1, 800), # was 138
      (position_set_y, pos1, 800), # was 230
      (overlay_set_size, "$g_presentation_obj_3", pos1),
      (position_set_x, pos1, 694), # was 600
      (position_set_y, pos1, 140), # was 250
      (overlay_set_position, "$g_presentation_obj_3", pos1),
     
      # Book mesh sneak peak
      (assign, "$g_current_opened_item_mesh", -1),
     
      (try_for_range, ":slot_no_c", 10, 106),
         (troop_get_inventory_slot, ":item_no_c", "trp_temp_array_a", ":slot_no_c"),
         (neq, ":item_no_c", -1),
         (create_mesh_overlay_with_item_id, reg1, ":item_no_c"),
         (position_set_x, pos1, 2300), # was 138
         (position_set_y, pos1, 2300), # was 230
         (overlay_set_size, reg1, pos1),
         (position_set_x, pos1, 325), # was 600
         (position_set_y, pos1, 436), # was 250
         (overlay_set_position, reg1, pos1),
         (overlay_set_display, reg1, 0),
         (troop_set_slot, "trp_temp_array_c", ":slot_no_c", reg1),
      (try_end),
   ## Books & Scrolls
   (else_try),
      # Current book/scroll page flips
      (assign, "$g_current_flips", 0),
     
      # First page
      (call_script, "script_flip_page_for_book", "$g_book"),
     
      ## Book
      (try_begin),
         (eq, "$g_book_style", 0),
        
         # Book mesh
         (create_mesh_overlay, "$g_presentation_obj_1", "$g_book_mesh"),
        
         # Book title
         (create_text_overlay, "$g_presentation_obj_title", s2, tf_double_space|tf_center_justify),
         (position_set_x, pos1, 665),
         (position_set_y, pos1, 385), # 200 530
         (overlay_set_position, "$g_presentation_obj_title", pos1),
         (position_set_x, pos1, 1200), # was 1000
         (position_set_y, pos1, 1200), # was 1000
         (overlay_set_size, "$g_presentation_obj_title", pos1),
         (position_set_x, pos1, 955), # was 480
         (position_set_y, pos1, 150),
         (overlay_set_area_size, "$g_presentation_obj_title", pos1),
        
         # Book title on/off
         (try_begin),
            (eq, "$g_book_title", 0),
            (overlay_set_display, "$g_presentation_obj_title", 0),
         (try_end),
        
         # Page numbers
         # Left
         (create_text_overlay, "$g_presentation_obj_2", s3, tf_center_justify),
         (position_set_x, pos1, 320),
         (position_set_y, pos1, 138),
         (overlay_set_position, "$g_presentation_obj_2", pos1),
         # Right
         (create_text_overlay, "$g_presentation_obj_3", s4, tf_center_justify),
         (position_set_x, pos1, 660), # was 650
         (position_set_y, pos1, 138),
         (overlay_set_position, "$g_presentation_obj_3", pos1),
        
         # Page numbers on/off
         (try_begin),
            (eq, "$g_book_page_numbers", 0),
            (overlay_set_display, "$g_presentation_obj_2", 0),
            (overlay_set_display, "$g_presentation_obj_3", 0),
         (try_end),
        
         # Text boxes
         # Left align
         (create_text_overlay, "$g_presentation_obj_4", s1, tf_double_space),
         (position_set_x, pos1, 170), # x is higher by 10 in reality | was 175
         (position_set_y, pos1, 185), # was 165
         (overlay_set_position, "$g_presentation_obj_4", pos1),
         (position_set_x, pos1, 900), # text size x
         (position_set_y, pos1, 900), # text size y
         (overlay_set_size, "$g_presentation_obj_4", pos1),
         (position_set_x, pos1, 470), # x is exactly same in reality | was 475
         (position_set_y, pos1, 50), # was 220
         (overlay_set_area_size, "$g_presentation_obj_4", pos1),
        
         # Right align
         (create_text_overlay, "$g_presentation_obj_5", s2, tf_double_space),
         (position_set_x, pos1, 530), # was 520
         (position_set_y, pos1, 185), # 200 530 | was 165
         (overlay_set_position, "$g_presentation_obj_5", pos1),
         (position_set_x, pos1, 900), # was 1100
         (position_set_y, pos1, 900), # was 1100
         (overlay_set_size, "$g_presentation_obj_5", pos1),
         (position_set_x, pos1, 820), # was 810
         (position_set_y, pos1, 50),
         (overlay_set_area_size, "$g_presentation_obj_5", pos1),  
         # If book has title right text is hidden for the first page
         (try_begin),
            (eq, "$g_book_title", 1),
            (overlay_set_display, "$g_presentation_obj_5", 0),
         (try_end),
        
         # Buttons
         # Previous page button
         (create_image_button_overlay, "$g_presentation_obj_6", "mesh_book_arrow_left", "mesh_book_arrow_left_pressed"),
         (position_set_x, pos1, 300),
         (position_set_y, pos1, 300),
         (overlay_set_size, "$g_presentation_obj_6", pos1),
         (position_set_x, pos1, 175),
         (position_set_y, pos1, 136),
         (overlay_set_position, "$g_presentation_obj_6", pos1),
        
         # Next page button
         (create_image_button_overlay, "$g_presentation_obj_7", "mesh_book_arrow_right", "mesh_book_arrow_right_pressed"),
         (position_set_x, pos1, 300),
         (position_set_y, pos1, 300),
         (overlay_set_size, "$g_presentation_obj_7", pos1),
         (position_set_x, pos1, 790), # was 800
         (position_set_y, pos1, 136),
         (overlay_set_position, "$g_presentation_obj_7", pos1),
        
      ## Scroll
      (else_try),  
         # Scroll mesh front
         (create_mesh_overlay, "$g_presentation_obj_1", "$g_book_mesh"),
        
         # Scroll mesh back
         (create_mesh_overlay, "$g_presentation_obj_2", "$g_book_mesh_back"),
         (overlay_set_display, "$g_presentation_obj_2", 0), # hidden
        
         # Text box
         (create_text_overlay, "$g_presentation_obj_3", s1, tf_double_space),
         (position_set_x, pos1, 360),
         (position_set_y, pos1, 165),
         (overlay_set_position, "$g_presentation_obj_3", pos1),
         (position_set_x, pos1, 900), # text size x
         (position_set_y, pos1, 900), # text size y
         (overlay_set_size, "$g_presentation_obj_3", pos1),
         (position_set_x, pos1, 700),
         (position_set_y, pos1, 50),
         (overlay_set_area_size, "$g_presentation_obj_3", pos1),
        
         # Previous page button
         (create_image_button_overlay, "$g_presentation_obj_4", "mesh_book_arrow_left", "mesh_book_arrow_left_pressed"),
         (position_set_x, pos1, 300),
         (position_set_y, pos1, 300),
         (overlay_set_size, "$g_presentation_obj_4", pos1),
         (position_set_x, pos1, 330),
         (position_set_y, pos1, 115),
         (overlay_set_position, "$g_presentation_obj_4", pos1),
        
         # Next page button
         (create_image_button_overlay, "$g_presentation_obj_5", "mesh_book_arrow_right", "mesh_book_arrow_right_pressed"),
         (position_set_x, pos1, 300),
         (position_set_y, pos1, 300),
         (overlay_set_size, "$g_presentation_obj_5", pos1),
         (position_set_x, pos1, 650),
         (position_set_y, pos1, 115),
         (overlay_set_position, "$g_presentation_obj_5", pos1),
      (try_end),
   (try_end),
    ]),
   (ti_on_presentation_run,
   [
      (set_fixed_point_multiplier, 1000),
     
      # Exit
      (try_begin),
         (key_clicked, key_b),
         (presentation_set_duration, 0),
      (try_end),
     
      # String & Button hiding/showing
      (try_begin),
         (neq, "$g_book", 1), # not in book menu
            (try_begin),
               (ge, "$g_current_flips", 1), # after one flip
                  # Book
                  (try_begin),
                     (eq, "$g_book_style", 0),
                        # Title switch
                        (try_begin),
                           (eq, "$g_book_title", 1),
                           (overlay_set_display, "$g_presentation_obj_title", 0),
                           (overlay_set_display, "$g_presentation_obj_5", 1),
                        (try_end),
                       
                        # Button switch        
                        # Previous page button
                        (overlay_set_display, "$g_presentation_obj_6", 1),
                       
                        # Next page button
                        (try_begin),
                           (eq, "$g_current_flips", "$g_max_flips"),
                           (overlay_set_display, "$g_presentation_obj_7", 0),
                        (else_try),
                           (overlay_set_display, "$g_presentation_obj_7", 1),
                        (try_end),
                  # Scroll
                  (else_try),
                     # Hiding back page and enabling front one
                     (overlay_set_display, "$g_presentation_obj_1", 0),
                     (overlay_set_display, "$g_presentation_obj_2", 1),
                    
                     # Button switch        
                     # Previous page button
                     (overlay_set_display, "$g_presentation_obj_4", 1),
                    
                     # Next page button
                     (overlay_set_display, "$g_presentation_obj_5", 0),
                  (try_end),
            (else_try),
               # Book
               (try_begin),
                  (eq, "$g_book_style", 0),
                     # Title switch
                     (try_begin),
                        (eq, "$g_book_title", 1),
                        (overlay_set_display, "$g_presentation_obj_title", 1),
                        (overlay_set_display, "$g_presentation_obj_5", 0),
                     (try_end),
                    
                     # Button switch        
                     # Previous page button
                     (overlay_set_display, "$g_presentation_obj_6", 0),
                    
                     # Next page button
                     (try_begin),
                        (neq, "$g_max_flips", 0),
                        (overlay_set_display, "$g_presentation_obj_7", 1),
                     (try_end),
               # Scroll
               (else_try),
                  # Hiding back page and enabling front one
                  (overlay_set_display, "$g_presentation_obj_1", 1),
                  (overlay_set_display, "$g_presentation_obj_2", 0),
                 
                  # Button switch        
                  # Previous page button
                  (overlay_set_display, "$g_presentation_obj_4", 0),
                 
                  # Next page button
                  (try_begin),
                     (neq, "$g_max_flips", 0),
                     (overlay_set_display, "$g_presentation_obj_5", 1),
                  (else_try),
                     (overlay_set_display, "$g_presentation_obj_5", 0),
                  (try_end),
               (try_end),
            (try_end),
      (try_end),
   ]),
   (ti_on_presentation_mouse_enter_leave,
   [
   (store_trigger_param_1, ":object"),
   (store_trigger_param_2, ":enter_leave"),
  
   (try_begin),
      (eq, "$g_book", 1),
         (try_begin),
            (eq, ":enter_leave", 0),
               (try_for_range, ":slot_no", 10, 106),
                  (troop_slot_eq, "trp_temp_array_a", ":slot_no", ":object"),
                  (troop_get_inventory_slot, ":item", "trp_temp_array_a", ":slot_no"),
                     (try_begin),
                        (neq, ":item", -1),
                        (troop_get_slot, ":target_obj", "trp_temp_array_b", ":slot_no"),
                        (troop_get_slot, ":target_obj_c", "trp_temp_array_c", ":slot_no"),
                        (overlay_get_position, pos0, ":target_obj"),
                        (show_item_details, ":item", pos0, 100),
                        (assign, "$g_current_opened_item_details", ":slot_no"),
                       
                        # Open mesh sneak peak
                        (try_begin),
                           (neq, "$g_current_opened_item_mesh", -1),
                           (overlay_set_display, "$g_current_opened_item_mesh", 0), # bug fix
                        (try_end),
                       
                        (overlay_set_display, ":target_obj_c", 1),
                        (assign, "$g_current_opened_item_mesh", ":target_obj_c"),
                     (try_end),
               (try_end),
         (else_try),
            (try_for_range, ":slot_no", 10, 106),
               (troop_slot_eq, "trp_temp_array_a", ":slot_no", ":object"),
                  (try_begin),
                     (eq, "$g_current_opened_item_details", ":slot_no"),
                     (close_item_details),
                    
                     # Close mesh sneak peak
                     (overlay_set_display, "$g_current_opened_item_mesh", 0),
                     (assign, "$g_current_opened_item_mesh", -1),
                  (try_end),
            (try_end),
         (try_end),
   (try_end),
    ]),
   (ti_on_presentation_mouse_press,
    [
      (store_trigger_param_1, ":przycisk"),
      (store_trigger_param_2, ":rodzaj"),
     
      # Book selection menu
      (try_begin),
         (eq, "$g_book", 1),
            (try_begin),
               (eq, ":rodzaj", 0),
                  (try_for_range, ":slot_no", 10, 106),
                     (troop_slot_eq, "trp_temp_array_a", ":slot_no", ":przycisk"),
                     (troop_get_inventory_slot, ":item", "trp_temp_array_a", ":slot_no"),
                        (try_begin),
                           (neq, ":item", -1),
                           (close_item_details),
                           (call_script, "script_get_book_details_from_book_database", ":item"),
                           (play_sound, "snd_click"),
                           (presentation_set_duration, 0),
                           (start_presentation, "prsnt_book_reading"),
                        (try_end),
                  (try_end),
            (try_end),
      (try_end),
    ]),
   (ti_on_presentation_event_state_change,
    [
      (store_trigger_param_1, ":przycisk"),
     
      # Page flipping buttons
      (try_begin),
         (neq, "$g_book", 1),
            # Book
            (try_begin),
               (eq, "$g_book_style", 0),
                  # Page - 1
                  (try_begin),
                     (eq, ":przycisk", "$g_presentation_obj_6"),
                     (val_add, "$g_current_flips", -1),
                     (call_script, "script_flip_page_for_book", "$g_book"),
                    
                     # Page numbers -
                     (overlay_set_text, "$g_presentation_obj_2", s3),
                     (overlay_set_text, "$g_presentation_obj_3", s4),
                    
                     # Text boxes
                     (overlay_set_text, "$g_presentation_obj_4", s1),
                     (overlay_set_text, "$g_presentation_obj_5", s2),
                    
                     # Page flip sound
                     #(play_sound, "snd_page_flip"),
                  # Page + 1
                  (else_try),
                     (eq, ":przycisk", "$g_presentation_obj_7"),
                     (val_add, "$g_current_flips", 1),
                     (call_script, "script_flip_page_for_book", "$g_book"),
                    
                     # Page numbers +
                     (overlay_set_text, "$g_presentation_obj_2", s3),
                     (overlay_set_text, "$g_presentation_obj_3", s4),
                    
                     # Text boxes
                     (overlay_set_text, "$g_presentation_obj_4", s1),
                     (overlay_set_text, "$g_presentation_obj_5", s2),
                    
                     # Page flip sound
                     #(play_sound, "snd_page_flip"),
                  (try_end),
            # Scroll
            (else_try),
               # Page - 1
               (try_begin),
                  (eq, ":przycisk", "$g_presentation_obj_4"),
                  (val_add, "$g_current_flips", -1),
                  (call_script, "script_flip_page_for_book", "$g_book"),
                 
                  # Text box
                  (overlay_set_text, "$g_presentation_obj_3", s1),
                 
                  # Page flip sound
                  #(play_sound, "snd_page_flip"),
               # Page + 1
               (else_try),
                  (eq, ":przycisk", "$g_presentation_obj_5"),
                  (val_add, "$g_current_flips", 1),
                  (call_script, "script_flip_page_for_book", "$g_book"),
                 
                  # Text box
                  (overlay_set_text, "$g_presentation_obj_3", s1),
                 
                  # Page flip sound
                  #(play_sound, "snd_page_flip"),
               (try_end),
            (try_end),
      (try_end),
    ]),
  ]),

Now it's time for scripts (insert to module_scripts):
Code:
# script_flip_page_for_book
  # Input: book
  # Output: s1, s2, s3, s4
  # Script used for getting book/scroll text pages
  ("flip_page_for_book",
    [
    (store_script_param, ":book", 1),
   
    (str_clear, s1),
    (str_clear, s2),
    (str_clear, s3),
    (str_clear, s4),
   
    (try_begin),
        # Temp book 1
        (eq, ":book", "itm_book_temp_1"),
            (try_begin),
                # Title
                (eq, "$g_current_flips", 0),
                (str_store_string, s1, "str_empty_string"),
                (str_store_string, s2, "@ Template book^^by^^Garedyr"),
                (str_store_string, s3, "str_empty_string"),
                (str_store_string, s4, "str_empty_string"),
            (else_try),
                # Page 1 & 2
                (eq, "$g_current_flips", 1),
                (str_store_string, s1, "@ Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Vivamus^ vitae euismod enim. Sed porttitor^ sagittis velit vitae auctor. Sed^ iaculis pharetra nulla, ut placerat^ lacus volutpat eget. Vestibulum^ fermentum quam sit amet fermentum^ facilisis. Suspendisse in lectus ut^ dolor facilisis ornare. Aenean^ tincidunt auctor rutrum.^ Pellentesque erat mauris, blandit et^ egestas a, porttitor at libero.^ Phasellus eleifend tempor tortor, in^ blandit ligula molestie eu.^ Phasellus feugiat semper orci, nec^ luctus nisi molestie sed. Praesent^ rhoncus, diam ac sollicitudin^ sagittis, ex elit aliquam ex, sed^ ornare odio ex eu arcu. Praesent^ felis justo, tincidunt eleifend^ posuere at, ultricies vitae quam.^ Nam arcu libero, dictum non laoreet^ porttitor, imperdiet quis dui."),
                (str_store_string, s2, "@ Integer a vestibulum lorem.^ Suspendisse vulputate dolor nec^ neque aliquam, ac suscipit lacus^ imperdiet. Vestibulum eget tristique^ arcu. Nulla ultricies augue id nisl^ porttitor aliquet nec a turpis.^ Vivamus a tempor dolor. Ut in diam^ convallis, egestas nibh eu,^ scelerisque est. Proin faucibus^ interdum libero nec viverra. Sed^ quis consectetur nulla. Aliquam sit^ amet neque nunc. Vivamus molestie^ egestas mollis. Nam vulputate magna^ metus, sit amet porta velit volutpat^ quis. Nam tempor felis orci, ut^ vehicula sapien posuere eu. In^ finibus interdum lacus at^ tincidunt.^^^^^^"),
                (str_store_string, s3, "@1"),
                (str_store_string, s4, "@2"),
            (else_try),
                # Page 3 & 4
                (eq, "$g_current_flips", 2),
                (str_store_string, s1, "@ Donec bibendum dapibus elit id^ imperdiet. Cras dapibus ligula^ turpis, vel consectetur enim^ interdum at. Pellentesque habitant^ morbi tristique senectus et netus et^ malesuada fames ac turpis egestas.^ Praesent dapibus, nunc a gravida^ commodo, felis ex porta mi, vel^ mattis sem diam vel nunc. Nam et^ lorem lobortis nibh finibus^ lobortis. Pellentesque sit amet arcu^ vel nisl dignissim sodales. Vivamus^ at sem vel purus fermentum aliquet.^ Ut quis facilisis dolor. Aliquam^ varius consequat pulvinar. Nulla^ massa justo, interdum id pulvinar^ ac, ultrices sed magna. Fusce erat^ felis, elementum et ullamcorper sed,^ elementum nec sapien. Fusce vitae^ ultrices erat, mattis cursus libero.^ Pellentesque cursus mauris lectus,^ sit amet pretium nisi bibendum non.^ Aenean sed metus sem. Morbi sed"),
                (str_store_string, s2, "@ nulla lacinia, mollis dui sed,^ finibus lorem. Cras lobortis^ convallis hendrerit. Ut dapibus^ sodales pellentesque. Mauris^ dignissim sapien quis viverra^ mollis. Donec eros felis, dapibus^ eget lorem vitae, vestibulum^ imperdiet orci. Aliquam vel augue^ porttitor arcu porttitor imperdiet.^ Mauris pharetra euismod libero, sit^ amet interdum urna porta id. Proin^ vitae dolor viverra, rhoncus tortor^ eget, pulvinar velit. Suspendisse^ sed nisl eu lacus pharetra luctus.^ Fusce porttitor tellus vitae metus^ viverra suscipit. Orci varius^ natoque penatibus et magnis dis^ parturient montes, nascetur^ ridiculus mus. Mauris commodo eros^ pharetra dignissim dictum. Donec^ fermentum nulla porttitor ante^ finibus ultrices. Donec a imperdiet^ mi, et rhoncus neque. Donec"),
                (str_store_string, s3, "@3"),
                (str_store_string, s4, "@4"),
            (else_try),
                # Page 5 & 6
                (eq, "$g_current_flips", 3),
                (str_store_string, s1, "@ consequat scelerisque venenatis. Ut^ a dolor dolor. Nullam vitae aliquet^ elit. Maecenas a felis a nisi^ vulputate placerat. Sed gravida, leo^ non malesuada sodales, nisi tellus^ volutpat arcu, eu rutrum lorem justo^ ut libero. Integer scelerisque augue^ eget aliquet maximus. Maecenas in^ tempor elit. Mauris vel pretium^ lacus, in tincidunt quam. Maecenas^ pellentesque, justo quis fringilla^ maximus, lacus nulla molestie justo,^ ut dictum tellus neque id nulla.^ Curabitur orci metus, feugiat at^ dolor egestas, viverra malesuada^ nisi. Morbi est ante, viverra in^ nisl sed, sollicitudin malesuada^ sem. Vestibulum leo est, accumsan^ non augue eu, pretium imperdiet^ erat. Nam mollis posuere augue ut^ vestibulum. Sed tortor neque,^ imperdiet a sodales a, bibendum ac^ urna."),
                (str_store_string, s2, "@ Praesent interdum convallis^ malesuada. Suspendisse potenti.^ Quisque quis fringilla quam, dapibus^ elementum augue. Etiam vulputate^ blandit dolor, id aliquet urna.^ Suspendisse eleifend eu lorem quis^ vehicula. Nullam tincidunt justo et^ dolor egestas pellentesque. Maecenas^ vitae feugiat augue, sed tempor^ nunc. Praesent vel vehicula lectus,^ quis imperdiet quam. Vestibulum^ maximus elit sit amet cursus dictum.^ Vivamus accumsan quis tortor vitae^ accumsan. Aenean lobortis nisi id^ quam aliquet efficitur. Sed^ consectetur sapien sit amet eleifend^ tristique. Aenean eu sapien eu elit^ blandit laoreet a sed purus.^^^^^^"),
                (str_store_string, s3, "@5"),
                (str_store_string, s4, "@6"),
            (try_end),
    (else_try),
        (eq, ":book", "itm_temp_scroll"),
            (try_begin),
                (eq, "$g_current_flips", 0),
                (str_store_string, s1, "@ Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Donec^ porta lorem nec felis cursus, eget^ pellentesque diam gravida. Vivamus^ ac enim tincidunt, pellentesque^ libero eu, faucibus est. Donec^ placerat dolor bibendum, dignissim^ purus sit amet, tincidunt purus.^ Praesent vel odio quis quam dictum^ congue ac luctus nisl. Class aptent^ taciti sociosqu ad litora torquent^ per conubia nostra, per inceptos^ himenaeos. Quisque tellus nisl,^ blandit vitae euismod et, convallis^ vitae urna. Etiam sed purus erat.^ Morbi varius ornare leo quis^ porttitor. Ut sed cursus est, non^ feugiat risus. Suspendisse a ipsum^ mattis, dapibus lacus sit amet,^ ultricies mauris. Fusce quis nisl^ varius, porta eros quis, finibus^ nulla.^^"),
            (else_try),
                (str_store_string, s1, "@ Vestibulum tempus orci lectus, et^ aliquam quam facilisis tincidunt.^ Phasellus porttitor porttitor augue,^ non vestibulum eros faucibus sit^ amet. Interdum et malesuada fames ac^ ante ipsum primis in faucibus. Nunc^ turpis purus, congue ac odio et,^ scelerisque bibendum urna. Aenean^ dignissim mi ante, nec pharetra^ tortor porta sit amet. Duis^ consectetur pulvinar ipsum, non^ aliquam elit congue id. Curabitur^ pharetra condimentum enim, ut^ viverra risus tempor eu. Integer^ dapibus nisl vitae lectus gravida^ rutrum. Maecenas elementum massa sit^ amet ligula porta, nec eleifend elit^ aliquet. Etiam volutpat dignissim^ enim id blandit. Sed ligula lectus,^ hendrerit porttitor velit nec,^ fermentum iaculis erat. Integer nibh^ ipsum, venenatis quis venenatis ut,^ volutpat vel ligula. Nam finibus,"),
            (try_end),
    (try_end),
  ]),
  # Garedyr end
 
  # script_get_book_details_from_book_database
  # Input: book
  # Output: "$g_book", "$g_book_mesh", "$g_book_mesh"_back, "$g_book_style", "$g_book_title", "$g_book_page_numbers", "$g_max_flips"
  # Script used to initiate book/scroll variables
  ("get_book_details_from_book_database",
    [
    (store_script_param, ":book", 1),
   
    # For both books and scrolls
    # Used to determine book for reading by menu
    (assign, "$g_book", ":book"),
   
    # Book variables
    # "$g_book_mesh" - determines which mesh will be used for presentation
    # "$g_book_style" - determines whether use book or scroll style presentation
    # "$g_book_title" - set it to 1 if you want the first page to be title page, 0 for no title
    # "$g_book_page_numbers" - set it to 1 if you want to display page numbers, 0 for no page numbers
    # "$g_max_flips" - range 0-x, determines how many times you can flip pages
   
    # Scroll variables
    # "$g_book_mesh" - determines which mesh will be used for presentation
    # "$g_book_mesh_back" - determines which mesh will be used for the second scroll page (use same as above if there isn't any)
    # "$g_book_style" - determines whether use book or scroll style presentation
    # "$g_max_flips" - range 0-1, determines how many times you can flip pages (scrolls usually have only front and back page)
   
    # Books
    (try_begin),
        # Template book
        (eq, ":book", "itm_book_temp_1"),
        (assign, "$g_book_mesh", "mesh_book_open_1"),
        (assign, "$g_book_style", 0),
        (assign, "$g_book_title", 1),
        (assign, "$g_book_page_numbers", 1),
        (assign, "$g_max_flips", 3),
    # Scrolls
    (else_try),
        # Template scroll
        (eq, ":book", "itm_temp_scroll"),
        (assign, "$g_book_mesh", "mesh_scroll_open_1"),
        (assign, "$g_book_mesh_back", "mesh_scroll_open_1_back"),
        (assign, "$g_book_style", 1),
        (assign, "$g_max_flips", 1),
    (try_end),
  ]),
  # Garedyr end

Now the meshes (insert to module_meshes):
Code:
("book_arrow_left", 0, "cb_ui_comp_arrow_l_d", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("book_arrow_left_pressed", 0, "cb_ui_comp_arrow_l_p", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("book_arrow_right", 0, "cb_ui_comp_arrow_r_d", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("book_arrow_right_pressed", 0, "cb_ui_comp_arrow_r_p", 0, 0, 0, 0, 0, 0, 1, 1, 1),

("book_menu", 0, "book_menu", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("book_open_1", 0, "book_open_1", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("scroll_open_1", 0, "scroll_open_1", 0, 0, 0, 0, 0, 0, 1, 1, 1),
("scroll_open_1_back", 0, "scroll_open_1_back", 0, 0, 0, 0, 0, 0, 1, 1, 1),

Items (insert to module_items):
Code:
["book_temp_1","temp book 1", [("book_b",0)], itp_type_book, 0, 50,weight(2)|abundance(100),imodbits_none],
["temp_scroll","template scroll", [("book_b",0)], itp_type_book, 0,0,weight(0)|abundance(0),0],

Finally, the mission templates (insert to module_mission_templates):
Code:
# Book reading
# Make sure you maintain at least 0.5 second delay on the trigger.
# Otherwise the presentation won't load correctly and you may experience funny things.
# Ofc you can call the presentation from elsewhere if you want to do so.
book_reading = (
  0, 0.5, 0,
    [(neg|is_presentation_active, "prsnt_book_reading"), (key_clicked, key_b)],
    [
    # You can start from any book directly here if you insert
    # get_book_details_from_book_database for your item and comment out the line below.
    (assign, "$g_book", 1), # 1 = book menu
    (start_presentation, "prsnt_book_reading"),
    ])

Now insert the book_reading, in the same way other triggers are to the mission you want to be able to read.
Example in town_center mission:
(44,mtef_visitor_source|mtef_team_1,af_override_horse,aif_start_alarmed,1,[]),
(45,mtef_visitor_source|mtef_team_1,af_override_horse,aif_start_alarmed,1,[]),
(46,mtef_visitor_source|mtef_team_1,af_override_horse,aif_start_alarmed,1,[]),
(47,mtef_visitor_source|mtef_team_1,af_override_horse,aif_start_alarmed,1,[]),
],
[
[...]

book_reading,

[...]

(ti_on_agent_spawn, 0, 0, [],
[
(store_trigger_param_1, ":agent_no"),
(call_script, "script_init_town_agent", ":agent_no"),
(try_begin),

That concludes the installation. Now test if everything works correctly. Give player the items you added and press 'B' while in mission you added the trigger to.
Instructions on how to add your own books & scrolls and multiple language support are located in the second post below.
 
Last edited:
Adding your own books & scrolls and multiple languages support​


The first step is to add an appropriate item and script get_book_details_from_book_database entry for you book/scroll. You can handle adding item entry (just make sure it has itp_type_book flag) so I'm going to skip to the module_scripts. As you can see there are some global variables documented there.

They are:
# "$g_book_mesh" - determines which mesh will be used for presentation
# "$g_book_style" - determines whether use book or scroll style presentation
# "$g_book_title" - set it to 1 if you want the first page to be title page, 0 for no title
# "$g_book_page_numbers" - set it to 1 if you want to display page numbers, 0 for no page numbers
# "$g_max_flips" - range 0-x, determines how many times you can flip pages

# Scroll variables
# "$g_book_mesh" - determines which mesh will be used for presentation
# "$g_book_mesh_back" - determines which mesh will be used for the second scroll page (use same as above if there isn't any)
# "$g_book_style" - determines whether use book or scroll style presentation
# "$g_max_flips" - range 0-1, determines how many times you can flip pages (scrolls usually have only front and back page)

Now when you know what each of the variables do, you can create your own entry here. Add else_try and setup your book/scroll.
Template book & scroll is a good reference so you can copy it and change the numbers.

Example entries:
# Books
(try_begin),
# Template book
(eq, ":book", "itm_book_temp_1"),
(assign, "$g_book_mesh", "mesh_book_open_1"),
(assign, "$g_book_style", 0),
(assign, "$g_book_title", 1),
(assign, "$g_book_page_numbers", 1),
(assign, "$g_max_flips", 3),
(else_try),
# Template book 2
(eq, ":book", "itm_book_temp_2"),
(assign, "$g_book_mesh", "mesh_book_open_1"),
(assign, "$g_book_style", 0),
(assign, "$g_book_title", 0),
(assign, "$g_book_page_numbers", 0),
(assign, "$g_max_flips", 3),

(else_try),
# Template scroll
(eq, ":book", "itm_temp_scroll"),
(assign, "$g_book_mesh", "mesh_scroll_open_1"),
(assign, "$g_book_mesh_back", "mesh_scroll_open_1_back"),
(assign, "$g_book_style", 1),
(assign, "$g_max_flips", 1),
(else_try),
# Template scroll 2
(eq, ":book", "itm_temp_scroll_2"),
(assign, "$g_book_mesh", "mesh_scroll_open_2"),
(assign, "$g_book_mesh_back", "mesh_scroll_open_2_back"),
(assign, "$g_book_style", 1),
(assign, "$g_max_flips", 0),

(try_end),
]),
# Garedyr end

Now it's the most complicated part - the actual book/scroll pages creating. There's another script above the one you edited just a moment ago. Script flip_page_for_book contains pages for all of your books and scrolls. Please take note that the procedure is the same for every entry you create, however some of the elements will be different depending on variables you've chosen in script get_book_details_from_book_database.

The script relies on global variables called "$g_current_flips" (set automatically when you flip the page) and "$g_max_flips" (assigned by you). Let's say you're making a new book.
  • If you set the "$g_max_flips" variable to 3 and "$g_book_title" to 1, then you're book is going to have a total of 6 pages (+ 1 for title).
  • If you set the "$g_max_flips" variable to 3 and "$g_book_title" to 0, then you're book is going to have a total of 8 pages (none for title).
  • Scrolls don't have a title and should have no more than 2 pages total. (global variable "$g_max_flips" for scrolls should be either 0 or 1)

Take a look at the Template book 1 entry. It has 6 pages, title and page numbers on. It should give you idea how to create similiar book.
Now let's create entry for a book without title and page numbers. Create else_try for new book in the same way entries for template book & scroll are.

Here's the example:
(try_begin),
# Temp book 1
(eq, ":book", "itm_book_temp_1"),

[...]
(else_try),
# Page 5 & 6
(eq, "$g_current_flips", 3),
(str_store_string, s1, "@ consequat scelerisque venenatis. Ut^ a dolor dolor. Nullam vitae aliquet^ elit. Maecenas a felis a nisi^ vulputate placerat. Sed gravida, leo^ non malesuada sodales, nisi tellus^ volutpat arcu, eu rutrum lorem justo^ ut libero. Integer scelerisque augue^ eget aliquet maximus. Maecenas in^ tempor elit. Mauris vel pretium^ lacus, in tincidunt quam. Maecenas^ pellentesque, justo quis fringilla^ maximus, lacus nulla molestie justo,^ ut dictum tellus neque id nulla.^ Curabitur orci metus, feugiat at^ dolor egestas, viverra malesuada^ nisi. Morbi est ante, viverra in^ nisl sed, sollicitudin malesuada^ sem. Vestibulum leo est, accumsan^ non augue eu, pretium imperdiet^ erat. Nam mollis posuere augue ut^ vestibulum. Sed tortor neque,^ imperdiet a sodales a, bibendum ac^ urna."),
(str_store_string, s2, "@ Praesent interdum convallis^ malesuada. Suspendisse potenti.^ Quisque quis fringilla quam, dapibus^ elementum augue. Etiam vulputate^ blandit dolor, id aliquet urna.^ Suspendisse eleifend eu lorem quis^ vehicula. Nullam tincidunt justo et^ dolor egestas pellentesque. Maecenas^ vitae feugiat augue, sed tempor^ nunc. Praesent vel vehicula lectus,^ quis imperdiet quam. Vestibulum^ maximus elit sit amet cursus dictum.^ Vivamus accumsan quis tortor vitae^ accumsan. Aenean lobortis nisi id^ quam aliquet efficitur. Sed^ consectetur sapien sit amet eleifend^ tristique. Aenean eu sapien eu elit^ blandit laoreet a sed purus.^^^^^^"),
(str_store_string, s3, "@5"),
(str_store_string, s4, "@6"),
(try_end),
(else_try),
# Template book 2
(eq, ":book", "itm_book_temp_2"),
(try_begin),
(eq, "$g_current_flips", 0),
(str_store_string, s1, "@ something"),
(str_store_string, s2, "@ something"),
(str_store_string, s3, "str_empty_string"),
(str_store_string, s4, "str_empty_string"),
(else_try),
(eq, "$g_current_flips", 1),
(str_store_string, s1, "@ something"),
(str_store_string, s2, "@ something"),
(str_store_string, s3, "str_empty_string"),
(str_store_string, s4, "str_empty_string"),
(try_end),

(try_end),

We don't have title here so this book starts immediately with text. You can see the operation str_store_string used four times after each "$g_current_flips" condition.
  • s1 is for text on the left side.
  • s2 is for text on the right side.
  • s3 and s4 are for the page numbers. We are not using them for this entry so they're set to "str_empty_string".

As you can see our text boxes are all set to display " something". That's not the correct way of adding text, it won't be placed properly in the game. It's time for you to open the book_generator that you downloaded with other necessary files. Just launch the generator.html file. There are tooltips on how to use it inside the program itself, so I'm not going to explain it here. The only thing you must know is that you should add one space at the begining of the text if you're using the first method or add one space at the begining of each line if you're using the second method. Don't use generator for book title pages. Just look how the template one is done and add it the same way.

After you've successfully generated the text you want to insert your string, copy the content of 'Generated text comes here:' box to your string.
If you choose the second method and generate only one line, then your text should look similiar to this:
This is a template book 2.^^^^^^^^^^^^^^^^^^^^^^

Now insert it inside either s1 or s2 so it looks like this (be careful not to delete the one space at the begining):
(else_try),
# Template book 2
(eq, ":book", "itm_book_temp_2"),
(try_begin),
(eq, "$g_current_flips", 0),
(str_store_string, s1, "@ This is a template book 2.^^^^^^^^^^^^^^^^^^^^^^"),
(str_store_string, s2, "@ something"),
(str_store_string, s3, "str_empty_string"),
(str_store_string, s4, "str_empty_string"),
(else_try),
(eq, "$g_current_flips", 1),
(str_store_string, s1, "@ something"),
(str_store_string, s2, "@ something"),
(str_store_string, s3, "str_empty_string"),
(str_store_string, s4, "str_empty_string"),
(try_end),

Now when you know the pattern, you can easily repeat the step for string s2 and add more else_tries for flips.


When it comes to scrolls, they're much simplier. The procedure with module_items and entry in module_scripts for get_book_details_from_book_database is identical. Just assign a proper variables. Your entries for script flip_page_for_book will be different than those for books.

Let's take a look at the template scroll entry inside script flip_page_for_book:
(else_try),
(eq, ":book", "itm_temp_scroll"),
(try_begin),
(eq, "$g_current_flips", 0),
(str_store_string, s1, "@ Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Donec^ porta lorem nec felis cursus, eget^ pellentesque diam gravida. Vivamus^ ac enim tincidunt, pellentesque^ libero eu, faucibus est. Donec^ placerat dolor bibendum, dignissim^ purus sit amet, tincidunt purus.^ Praesent vel odio quis quam dictum^ congue ac luctus nisl. Class aptent^ taciti sociosqu ad litora torquent^ per conubia nostra, per inceptos^ himenaeos. Quisque tellus nisl,^ blandit vitae euismod et, convallis^ vitae urna. Etiam sed purus erat.^ Morbi varius ornare leo quis^ porttitor. Ut sed cursus est, non^ feugiat risus. Suspendisse a ipsum^ mattis, dapibus lacus sit amet,^ ultricies mauris. Fusce quis nisl^ varius, porta eros quis, finibus^ nulla.^^"),
(else_try),
(str_store_string, s1, "@ Vestibulum tempus orci lectus, et^ aliquam quam facilisis tincidunt.^ Phasellus porttitor porttitor augue,^ non vestibulum eros faucibus sit^ amet. Interdum et malesuada fames ac^ ante ipsum primis in faucibus. Nunc^ turpis purus, congue ac odio et,^ scelerisque bibendum urna. Aenean^ dignissim mi ante, nec pharetra^ tortor porta sit amet. Duis^ consectetur pulvinar ipsum, non^ aliquam elit congue id. Curabitur^ pharetra condimentum enim, ut^ viverra risus tempor eu. Integer^ dapibus nisl vitae lectus gravida^ rutrum. Maecenas elementum massa sit^ amet ligula porta, nec eleifend elit^ aliquet. Etiam volutpat dignissim^ enim id blandit. Sed ligula lectus,^ hendrerit porttitor velit nec,^ fermentum iaculis erat. Integer nibh^ ipsum, venenatis quis venenatis ut,^ volutpat vel ligula. Nam finibus,"),
(try_end),

Scrolls can only have two pages (and don't have page numbers, title, they got single textbox) so there'll be only one or two strings (scrolls use only one string register for both pages - s1). If your scroll's "$g_max_flips" value is set to 0 then you can just remove the whole block below:
(else_try),
(eq, ":book", "itm_temp_scroll"),
(try_begin),
(eq, "$g_current_flips", 0),
(str_store_string, s1, "@ Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Donec^ porta lorem nec felis cursus, eget^ pellentesque diam gravida. Vivamus^ ac enim tincidunt, pellentesque^ libero eu, faucibus est. Donec^ placerat dolor bibendum, dignissim^ purus sit amet, tincidunt purus.^ Praesent vel odio quis quam dictum^ congue ac luctus nisl. Class aptent^ taciti sociosqu ad litora torquent^ per conubia nostra, per inceptos^ himenaeos. Quisque tellus nisl,^ blandit vitae euismod et, convallis^ vitae urna. Etiam sed purus erat.^ Morbi varius ornare leo quis^ porttitor. Ut sed cursus est, non^ feugiat risus. Suspendisse a ipsum^ mattis, dapibus lacus sit amet,^ ultricies mauris. Fusce quis nisl^ varius, porta eros quis, finibus^ nulla.^^"),
(else_try),
(str_store_string, s1, "@ Vestibulum tempus orci lectus, et^ aliquam quam facilisis tincidunt.^ Phasellus porttitor porttitor augue,^ non vestibulum eros faucibus sit^ amet. Interdum et malesuada fames ac^ ante ipsum primis in faucibus. Nunc^ turpis purus, congue ac odio et,^ scelerisque bibendum urna. Aenean^ dignissim mi ante, nec pharetra^ tortor porta sit amet. Duis^ consectetur pulvinar ipsum, non^ aliquam elit congue id. Curabitur^ pharetra condimentum enim, ut^ viverra risus tempor eu. Integer^ dapibus nisl vitae lectus gravida^ rutrum. Maecenas elementum massa sit^ amet ligula porta, nec eleifend elit^ aliquet. Etiam volutpat dignissim^ enim id blandit. Sed ligula lectus,^ hendrerit porttitor velit nec,^ fermentum iaculis erat. Integer nibh^ ipsum, venenatis quis venenatis ut,^ volutpat vel ligula. Nam finibus,"),

(try_end),

Multiple language support
See this post for the guide.



You can also add operation for raising skills, starting quests, playing sounds, etc in each block. I leave the rest to you. Feel free to post if you got any suggestions, bug reports or if you have any problems with understanding any part of the guide.
Thanks for reading.
 
Last edited:
Awesome... You've had to spend a lot of time creating this... by the way, good work with the writing of the post.
I can think of a few ideas on how to implement your creation...
Keep up the good work.  :wink:
 
That's  really great, now players need to actually read -and understand-  those famous books :shifty: (gain skills, clues for quests ...)
I think it's perfect for classic RPG mods like  BerTolkien's Nox.
 
HarryPham123 said:
Hmm it needs somethings...like sounds of the scroll. But your osp is great  :iamamoron:

Nothing is stopping you from adding them yourself :shifty:
There are actually a few commented out play_sound lines in presentation code which you can use if you have a proper sound for them :cool:
 
Ethred said:
Hi, how to use "book_generator folder"? I don't understand...

Welcome!

You're supposed to extract that folder anywhere you want and run generator.html file with your internet browser to generate strings for book pages text using it. The Module System won't let us limit the string size (or at least there is no way to do it without using some pure Python witchcraft with reverse engineering) and I didn't want to make user count every letter in each string row + total rows (cause it would be huge pain in the arse for most people) so I wrote this generator.

First method is for pre-written text while second one is for the text you're about to write.

Remember that your text will look the best in the game if you insert one space at the begining of each row if you're using second method or just one space at the begining of the first row if you're using the first one.
 
I just implemented the code and it works fine but ......
How could you put a condition in the script for languages? something like:
- if language = english then use string 1
- if language = spanish then use string 2
Because the text of the book can also be put in string ...
My mod, by default is for Latin America, but they also play it in many parts of the world and if I write the text in Spanish only, it would be a bit selfish of me...
 
I just implemented the code and it works fine but ......
How could you put a condition in the script for languages? something like:
- if language = english then use string 1
- if language = spanish then use string 2
Because the text of the book can also be put in string ...
My mod, by default is for Latin America, but they also play it in many parts of the world and if I write the text in Spanish only, it would be a bit selfish of me...

Welcome,

The easiest and least painful way of implementing multiple language support for books would be creating entry in module_strings for each book page string and storing that string instead of the text in flip_page_for_book script located in module_scripts. Then you just create entries for that strings in your target languages.

In practice:
Add English (or whatever the base language of your mod is) strings:

Python:
# Book x
("book_x_page_1", " Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Vivamus^ vitae euismod enim. Sed porttitor^ sagittis velit vitae auctor. Sed^ iaculis pharetra nulla, ut placerat^ lacus volutpat eget. Vestibulum^ fermentum quam sit amet fermentum^ facilisis. Suspendisse in lectus ut^ dolor facilisis ornare. Aenean^ tincidunt auctor rutrum.^ Pellentesque erat mauris, blandit et^ egestas a, porttitor at libero.^ Phasellus eleifend tempor tortor, in^ blandit ligula molestie eu.^ Phasellus feugiat semper orci, nec^ luctus nisi molestie sed. Praesent^ rhoncus, diam ac sollicitudin^ sagittis, ex elit aliquam ex, sed^ ornare odio ex eu arcu. Praesent^ felis justo, tincidunt eleifend^ posuere at, ultricies vitae quam.^ Nam arcu libero, dictum non laoreet^ porttitor, imperdiet quis dui."),
("book_x_page_2", "Integer a vestibulum lorem.^ Suspendisse vulputate dolor nec^ neque aliquam, ac suscipit lacus^ imperdiet. Vestibulum eget tristique^ arcu. Nulla ultricies augue id nisl^ porttitor aliquet nec a turpis.^ Vivamus a tempor dolor. Ut in diam^ convallis, egestas nibh eu,^ scelerisque est. Proin faucibus^ interdum libero nec viverra. Sed^ quis consectetur nulla. Aliquam sit^ amet neque nunc. Vivamus molestie^ egestas mollis. Nam vulputate magna^ metus, sit amet porta velit volutpat^ quis. Nam tempor felis orci, ut^ vehicula sapien posuere eu. In^ finibus interdum lacus at^ tincidunt.^^^^^^"),

...and so on.
That's how the string selection system looks now:

[...]
Python:
(else_try),
    # Page 1 & 2
    (eq, "$g_current_flips", 1),
    (str_store_string, s1, "@ Lorem ipsum dolor sit amet,^ consectetur adipiscing elit. Vivamus^ vitae euismod enim. Sed porttitor^ sagittis velit vitae auctor. Sed^ iaculis pharetra nulla, ut placerat^ lacus volutpat eget. Vestibulum^ fermentum quam sit amet fermentum^ facilisis. Suspendisse in lectus ut^ dolor facilisis ornare. Aenean^ tincidunt auctor rutrum.^ Pellentesque erat mauris, blandit et^ egestas a, porttitor at libero.^ Phasellus eleifend tempor tortor, in^ blandit ligula molestie eu.^ Phasellus feugiat semper orci, nec^ luctus nisi molestie sed. Praesent^ rhoncus, diam ac sollicitudin^ sagittis, ex elit aliquam ex, sed^ ornare odio ex eu arcu. Praesent^ felis justo, tincidunt eleifend^ posuere at, ultricies vitae quam.^ Nam arcu libero, dictum non laoreet^ porttitor, imperdiet quis dui."),
    (str_store_string, s2, "@ Integer a vestibulum lorem.^ Suspendisse vulputate dolor nec^ neque aliquam, ac suscipit lacus^ imperdiet. Vestibulum eget tristique^ arcu. Nulla ultricies augue id nisl^ porttitor aliquet nec a turpis.^ Vivamus a tempor dolor. Ut in diam^ convallis, egestas nibh eu,^ scelerisque est. Proin faucibus^ interdum libero nec viverra. Sed^ quis consectetur nulla. Aliquam sit^ amet neque nunc. Vivamus molestie^ egestas mollis. Nam vulputate magna^ metus, sit amet porta velit volutpat^ quis. Nam tempor felis orci, ut^ vehicula sapien posuere eu. In^ finibus interdum lacus at^ tincidunt.^^^^^^"),
    (str_store_string, s3, "@1"),
    (str_store_string, s4, "@2"),
[...]

Change it to something like this:

[...]
Python:
(else_try),
    # Page 1 & 2
    (eq, "$g_current_flips", 1),
    (str_store_string, s1, "str_book_x_page_1"),
    (str_store_string, s2, "str_book_x_page_2"),
    (str_store_string, s3, "@1"),
    (str_store_string, s4, "@2"),
[...]
Add translation for book strings you created earlier:

Python:
str_book_x_page_1|This is the language X translation for book x page 1.
str_book_x_page_2|This is the language X translation for book x page 2.
...and so on. Add translation entries for each game_strings file of your-mod-supported languages.

Hope the information I provided is helpful.
 
Back
Top Bottom