=begin ================================================================================ * Basic Info ================================================================================ * Script Name: ZMail * Version: 1.3.0 * Last Update: May 10th, 2013 * Writer: Zalerinian (~ZF) ================================================================================ * Usage ================================================================================ * To let the player read the mail: * SceneManager.call(Scene_ZMail) * The above script call will run the ZMail scene. * * To add mail to the list: * ZMail.add_mail(key, message, condition(s), name, attachments, sender) * 'key' The way you access the mail. * 'message' The message content. * 'condition(s)' The test run for the mail. This should be an array of * string. Editable. * 'name' The displayed name of the mail. Editable. Default: Null_Name. * 'attachments' is an array of strings that will give the player items. * Items need to look like: "1|5". This will give the player 5 of item 1. * 'sender' is a string representing who sent the mail. * * To change the conditions of a piece of mail: * ZMail.edit_cond(key, condition, check) * 'key' The key for the piece of mail. 'condition' The conditions that * determine readability. This should be an array of strings * 'check' is a true or false value that will determine if you want to * check the conditions immediately. * * To change the display name of a piece of mail: * ZMail.rename(key, name) * 'key' The key for the piece of mail. 'name' is the displayed name. * * To add more to a piece of mail: * ZMail.add_to_mail(key, space, mail) * 'key' The key for the piece of mail. 'space' True or false value. If * true, a space will be inserted between the end of the previous entry * and the beginning of the addition. 'mail' is the additional text. * * To see the contents of the entire mail file: * ZMail.dump_mail_file * Will print out the contents of the mail file to the console. This is * not visible without using a console. * * To wipe the mail file and create a new one: * ZMail.init(true) * Call the init method with true as its parameter. This will force-create * a new mail file. There is no chance of recovery after using this. * * * To find out if a piece of mail is readable: * ZMail.is_readable(key) * This will return true or false, true for readable and false for not. * * To change the attachments later in the game" * ZMail.edit_attachments(key, attachments) * 'key' is the key associated with the mail. * 'attachments' is an array of strings using the same format as add_mail. * To get a list of the attachments on a piece of mail: * ZMail.get_attachments(key) * 'key' is the key associated with the mail. * To clear the attachments off of a piece of mail: * ZMail.wipe_attachments(key) * 'key' is the key associated with the mail. * To get the sender name of a piece of mail: * ZMail.get_sender_name(key) * 'key' is the key associated with the piece of mail. * To change the sender's name of a piece of mail: * ZMail.edit_sender(key, name) * 'key' is the key associated with the piece of mail. * 'name' is the new name to be given. * To use Control Characters in your mail: * The available Control Characters are: * \\V[#] where '#' is a number. This will display the value of * the variable in the brackets. * \\P[#] where '#' is a number. This will display the display * name of the #th actor in your party. * \\N[#] where '#' is a number. This will display the display * name of the #th actor in the database. Do not use leading 0's. * To use these, make sure you put two backslashes before the letter. * If you do not, the character will NOT be converted. This is an issue * with the Ace engine. ================================================================================ * Version History ================================================================================ * V 1.3.0 May 10th, 2013 * + Added an option to have the mail visible through the main menu. * V 1.2.0 May 5th, 2013 * + Added the ability to attach items or money to mail. See above. * + Mail names can now be changed. See above for details * + A sender's name can now be specified, and will be displayed on top of * the mail. You can enable/disable this. * > Fixed an issue where mail with multiple pages would cut off early. * > Fixed players being able to return from a piece of mail before * deciding whether or not to keep it. * V 1.1.1 April 24th, 2013 * > Fixed a number of saving related issues. * V 1.1.0 April 22nd, 2013 * + Added support for Control Characters (\V, \P, etc.) * V 1.0.0 April 21st, 2013 * Initial public release. ================================================================================ * Support, Feedback, & Bug Reports ================================================================================ * If you have any questions or comments, I am usually available on the * RPG Maker forums, at forums.rpgmakerweb.com. If you cannot seem to get * in contact with me there, you can email me at: scripts@razelon.tk. ================================================================================ * Credit & Editting ================================================================================ * I do not require credit to be given. You may use this in either a * commercial or non-commercial game. The only thing I ask is that you do * not take credit for this script. * * You may edit this script to any other version of RPG Maker, new or old * without requesting my permission to do so. ================================================================================ * Configuration Options: ================================================================================ =end module ZSettings Storage = 100 # * The game variable that the mail file is stored in # * so that it isn't wiped when the game closes. Mail_Unread = "Unread Mail" # * Name of the command that will read new mail. Mail_Archived = "Stored Mail" # * Name of the command that will read archived mail. Mail_Delete = "Discard" # * Name of the command that deletes mail from existence. Mail_Archive = "Keep" # * Name of the command that archives mail for later. Mail_To_main = "Return" # * Name of the command that returns to the main menu. Mail_Max_LPP = 8 # * Max Lines per page when reading the mail. Additional # * lines are put on a new page. Mail_Max_NPP = 3 # * Max number of notifications per window. Applies to # * attachments only. Mail_Reread = "Reread" # * Name of the command that will re-read the mail. Mail_Exit = "Leave" # * Name of the command that will close the mail window. Mail_Attachments = "Get Attached" # * Name of the command that will get attachments. Mail_Item_Gained = "gained" # * Phrase displayed when an attachment gives the player an item. Mail_Item_Lost = "mysteriously lost" # * Phrase displayed when an attachment take an item from the player. Mail_Show_Sender = true # * Show the sender's name in the mail, or keep it hidden. Mail_Add_Menu = false # * Show a menu item for mail? Mail_Menu_Name = "Mail" # * Name of the menu option. end class Win_Options def self.width_is(key) amail = ZMail.get_mail_file mail_contents = amail[key] a = Window_Help.new a.hide lines = mail_contents.split("\n") i = 0 line_lengths = [] lines.each {|line| line_lengths[i] = a.contents.text_size(line).width.to_i i += 1 } line_lengths.sort! highest = line_lengths.size return line_lengths[highest - 1] end def self.height_is(key) amail = ZMail.get_mail_file a = Window_Help.new a.hide return a.text_size(amail[key]).height end def self.width(lines) a = Window_Help.new(6) a.hide return a.text_size(lines).width end def self.height(lines) a = Window_Help.new(20) a.hide return a.text_size(lines).height end def self.get_mail_pages(key) @mail_list = ZMail.get_mail_file @all_lines = @mail_list[key] @lines = @all_lines.split("\n") @pages = [] i = 0 page_no = 0 @lines.each {|line| if i >= ZSettings::Mail_Max_LPP page_no += 1 i = 0 end if @pages[page_no] == nil @pages[page_no] = "" end real_line = regex(line) @pages[page_no] += real_line + "\n" i += 1 } return @pages end def self.regex(line) result = line.clone result.gsub!(/\\/) { "\e" } result.gsub!(/\e/) { "\\" } result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] } result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] } result.gsub!(/\eN\[(\d+)\]/i) { actor_name($1.to_i) } result.gsub!(/\eP\[(\d+)\]/i) { party_member_name($1.to_i) } result.gsub!(/\eG/i) { Vocab::currency_unit } result end def actor_name(n) actor = n >= 1 ? $game_actors[n] : nil actor ? actor.name : "" end def party_member_name(n) actor = n >= 1 ? $game_party.members[n - 1] : nil actor ? actor.name : "" end end class ZMail_storage attr_accessor :mail def initialize @mail = {} end end class ZMail def self.init(force = false) if force then @mail_file = ZMail_storage.new puts "New mail file forced. Wiping existing..." $game_variables[ZSettings::Storage]["Mail_System"] = nil save_mailfile return end if $game_variables[ZSettings::Storage].is_a?(Hash) then a = $game_variables[ZSettings::Storage].is_a?(Hash) if a.has_key?("Mail_System") @mail_file = ZMail_storage.new @old_mail = $game_variables[ZSettings::Storage] @old_mail["Mail_System"].each_pair { |key, value| @mail_file.mail[key] = value } puts "Mail file successfully loaded." end else @mail_file = ZMail_storage.new puts "New mail file created." end end def self.add_mail(key = "Null_Mail", mail = "NULL", cond = "false", name = "Null_Name", attachments = [], sender = "Anonymous") init if @mail_file == nil cond.to_s unless cond.is_a?(Array) @mail_file.mail[key] = mail @mail_file.mail[key + "_arch?"] = false if cond.is_a?(Array) @mail_file.mail[key + "_cond"] = cond else @mail_file.mail[key + "_cond"] = [cond] end @mail_file.mail[key + "_readable"] = check_conds(key) @mail_file.mail[key + "_name"] = name @mail_file.mail[key + "_sender"] = sender if attachments.is_a?(Array) @mail_file.mail[key + "_attach"] = attachments else @mail_file.mail[key + "_attach"] = [attachments] end save_mailfile end def self.add_to_mail(key, space = false, mail) init if @mail_file == nil if space then @mail_file.mail[key] += " " + mail else @mail_file.mail[key] += mail end save_mailfile end def self.dump_mail_file init if @mail_file == nil @mail_file.mail.each_pair {|key, value| puts "Key name: " + key.to_s + "\t\tKey Value: " + value.to_s } end def self.key_list(type = 0) init if @mail_file == nil case type when 0 @keys = @mail_file.mail.keys @keys when 1 @keys = @mail_file.mail.keys @keys.reject!{ |key| not key.include?("_cond") } @keys when 2 @keys = @mail_file.mail.keys @keys.reject! {|key| key.include?("_cond" || "_arch?" || "_readable" || "_name" || "_sender" || "_attach") } @keys.uniq! @keys end end def self.check_conds(hash_key = nil) init if @mail_file == nil if hash_key != nil then @check = @mail_file.mail[hash_key + "_cond"].clone @check.reject! {|item| eval(item) != true } if @check.size == @mail_file.mail[hash_key + "_cond"].size @mail_file.mail[hash_key + "_readable"] = true @mail_file.mail.delete(hash_key + "_cond") else @check = @mail_file.mail[hash_key + "_readable"] = false end else @key_list = key_list(2) @key_list.each{|hash_key| if @mail_file.mail[hash_key + "_cond"] == nil next end @check = @mail_file.mail[hash_key + "_cond"].clone @check.reject! {|item| eval(item) != true } if @check.size == @mail_file.mail[hash_key + "_cond"].size @mail_file.mail[hash_key + "_readable"] = true @mail_file.mail.delete(hash_key + "_cond") else @mail_file.mail[hash_key + "_readable"] = false end } end end def self.setup_mail init if @mail_file == nil check_conds key_list(2) @unread_mail = {} @archived = {} @keys.each {|key| if @mail_file.mail[key + "_readable"] && !@mail_file.mail[key + "_arch?"] @unread_mail[key] = @mail_file.mail[key] elsif @mail_file.mail[key + "_arch?"] @archived[key] = @mail_file.mail[key] end } end def self.get_mail(type) setup_mail if type == 0 @unread_mail.keys else @archived.keys end end def self.edit_cond(key, condition = "false", check = false) init if @mail_file == nil if not @mail_file.mail.include?(key + "_cond") return false end if condition == nil conditon = "false" end if not condition.is_a?(String) condition.to_s elsif condition.is_a?(Array) condition.each {|cond| if cond.is_a?(String) next else cond.to_s end } end if not condition.is_a?(Array) cond = [condition] @mail_file.mail[key + "_cond"] = cond else @mail_file.mail[key + "_cond"] = condition end if check check_conds end # If save_mailfile end # Function def self.edit_attachments(key, attachments) init if @mail_file == nil if @mail_file.mail.has_key?(key + "_attach") @mail_file.mail[key + "_attach"] = attachments if attachments.is_a?(Array) save_mailfile end end def self.get_attachments(key) init if @mail_file == nil @mail_file.mail[key + "_attach"] end def self.wipe_attachments(key) @mail_file.mail.delete(key + "_attach") save_mailfile end def self.get_mail_file init if @mail_file == nil return @mail_file.mail end def self.delete_mail(key) init if @mail_file == nil @mail_file.mail.delete(key) @mail_file.mail.delete(key + "_arch?") @mail_file.mail.delete(key + "_cond") @mail_file.mail.delete(key + "_readable") @mail_file.mail.delete(key + "_name") @mail_file.mail.delete(key + "_sender") @mail_file.mail.delete(key + "_attach") save_mailfile end def self.archive(key) init if @mail_file == nil @mail_file.mail[key + "_arch?"] = true save_mailfile end def self.rename(key, name) init if @mail_file == nil @mail_file.mail[key + "_name"] = name save_mailfile end def self.is_readable(key) init if @mail_file == nil return @mail_file.mail[key + "_readable"] end def self.get_name(key) init if @mail_file == nil return @mail_file.mail[key + "_name"] end def self.get_sender_name(key) init if @mail_file == nil return @mail_file.mail[key + "_sender"] end def self.edit_sender(key, name) init if @mail_file == nil @mail_file.mail[key + "_sender"] = name save_mailfile end def self.save_mailfile init if @mail_file == nil if $game_variables[ZSettings::Storage].is_a?(Hash) current_save = $game_variables[ZSettings::Storage] current_save["Mail_System"] = @mail_file.mail $game_variables[ZSettings::Storage] = current_save else save = {} save["Mail_System"] = @mail_file.mail $game_variables[ZSettings::Storage] = save end end end # Class class Mail_Command < Window_Command def make_command_list add_command(ZSettings::Mail_Unread, :unread) add_command(ZSettings::Mail_Archived, :archived) add_command(ZSettings::Mail_Exit, :quit) end def umail_actions(the_key) a = ZMail.get_attachments(the_key) add_command(ZSettings::Mail_Reread, :reread) unless a.is_a?(Array) && !a.empty? add_command(ZSettings::Mail_Delete, :delete) add_command(ZSettings::Mail_Archive, :archive) end if a != nil && a.is_a?(Array) && !a.empty? add_command(ZSettings::Mail_Attachments, :attachments) end end def amail_actions add_command(ZSettings::Mail_Reread, :reread) add_command(ZSettings::Mail_Delete, :delete) add_command(ZSettings::Mail_To_main, :to_mail_main) end def unread_list @unread_mail = ZMail.get_mail(0) @unread_mail.each {|key| add_command(ZMail.get_name(key), :read_unread) } add_command(ZSettings::Mail_To_main, :to_mail_main) end def stored_list @archived = ZMail.get_mail(1) @archived.each {|key| add_command(ZMail.get_name(key), :read_archived) } add_command(ZSettings::Mail_To_main, :to_mail_main) end def c_refresh(comm_set, key = nil) @list = [] case comm_set when 0 make_command_list when 1 umail_actions(key) when 2 amail_actions when 3 unread_list when 4 stored_list end create_contents contents.clear draw_all_items self.height = window_height self.index = 0 activate end end class Scene_ZMail < Scene_Base def archive_mail ZMail.archive(@key) reset end def create_background @background_sprite = Sprite.new @background_sprite.bitmap = SceneManager.background_bitmap @background_sprite.color.set(16, 16, 16, 128) end def create_mail_actions @main.show @actions_showing = true if @arch == true @main.c_refresh(2) else @main.c_refresh(1, @key) end @main.set_handler(:reread, method(:setup_reread)) @main.set_handler(:delete, method(:delete_mail)) @main.set_handler(:archive, method(:archive_mail)) @main.set_handler(:attachments, method(:handle_attached)) @main.set_handler(:to_mail_main, method(:reset)) end def delete_mail ZMail.delete_mail(@key) @key = nil reset end def get_input(window = 0) if window == 0 @mail_window.pause = true elsif window == 1 @notif.pause = true end wait(10) Fiber.yield until Input.trigger?(:C) Input.update if window == 0 @mail_window.pause = false elsif window == 1 @notif.pause = false end end def handle_attached attached = ZMail.get_attachments(@key) attached = [attached] unless attached.is_a?(Array) holder = [] @gained = [] attached.each{|item| holder.push(item.split(/\|/)) } holder.each {|block| if block[0].to_i == 0 $game_party.gain_gold(block[1].to_i) @gained.push(block[0].to_i, block[1].to_i) else $game_party.gain_item($data_items[block[0].to_i], block[1].to_i) @gained.push(block[0].to_i, block[1].to_i) end } @fiber = Fiber.new {notify_attached} @fiber.resume end def notify_attached @showing_attached = true @main.deactivate n_pages = [] while @gained.size != 0 if @gained[0] == 0 item_name = Vocab::currency_unit else item_name = $data_items[@gained[0]].name end word = @gained[1] > 0 ? ZSettings::Mail_Item_Gained + " " : Z_Script_Setting::Mail_Item_Lost + " " plural = @gained[1] >= 2 ? "s!" : "!" n_pages[n_pages.size] = "You have " + word + (Math.sqrt(@gained[1].to_i ** 2).truncate).to_s + " " + item_name + plural @gained.delete_at(0) @gained.delete_at(0) end sn_pages = [] i = 0 n_pages.each {|note| if i < ZSettings::Mail_Max_NPP sn_pages[i] = "" if sn_pages[i] == nil sn_pages[i] += (note + "\n") else i += 1 sn_pages[i] = (note + "\n") end } i = 0 @notif = Window_Help.new(9) unless @notif @notif.arrows_visible = false loop do @notif.width = Win_Options.width(sn_pages[i]) @notif.height = (Win_Options.height(sn_pages[i]) * ZSettings::Mail_Max_NPP) + (@notif.standard_padding * 2) @notif.x = Graphics.width / 3 - @notif.width / 4 @notif.y = Graphics.height / 2 - 50 @notif.set_text(sn_pages[i]) get_input(1) break if i == sn_pages.size - 1 i += 1 end @notif.hide @notif = nil i = nil ZMail.wipe_attachments(@key) @main.c_refresh(1, @key) @main.activate @showing_attached = false @fiber = nil end def new_mail @main.c_refresh(3) @main.set_handler(:read_unread, method(:unread)) @main.set_handler(:to_mail_main, method(:reset)) end def old_mail @main.c_refresh(4) @main.set_handler(:read_archived, method(:stored)) @main.set_handler(:to_mail_main, method(:reset)) end def open_mail(mail_key) @mail_window = Window_Help.new(ZSettings::Mail_Max_LPP) unless @mail_window @mail_window.width = Win_Options.width_is(mail_key) + 48 @mail_window.x = (Graphics.width - @mail_window.width) / 2 - 75 @mail_window.y = 46 @mail_window.arrows_visible = false @pages = Win_Options.get_mail_pages(mail_key) @pages[@pages.size] = @pages[0] @current_page = 0 @mail_busy = true end def read @main.deactivate @main.hide @send_name = Window_Help.new(1) if ZSettings::Mail_Show_Sender == true @send_name.width = Win_Options.width(ZMail.get_sender_name(@key)) + (@send_name.standard_padding * 2) unless ZSettings::Mail_Show_Sender == true @send_name.arrows_visible = false if ZSettings::Mail_Show_Sender == true @send_name.x = @mail_window.x + 24 if ZSettings::Mail_Show_Sender == true @send_name.y = @mail_window.y - @send_name.height / 1.45 if ZSettings::Mail_Show_Sender == true @send_name.set_text(ZMail.get_sender_name(@key)) if ZSettings::Mail_Show_Sender == true loop do @mail_window.set_text(@pages[@current_page]) if @pages.size == 2 break end get_input @current_page += 1 Fiber.yield break unless @current_page <= @pages.size - 2 end @mail_window.set_text(@pages[@pages.size - 1]) @fiber = nil @mail_busy = false create_mail_actions end def reset @arch = false @actions_showing = false @mail_busy = false @showing_attached = false @mail_window.hide if @mail_window @mail_window = nil @send_name.hide if @send_name @send_name = nil @main.show if @main @main.c_refresh(0) @main.index = 0 @main.activate end def setup_reread @actions_showing = false @current_page = 0 @mail_window.set_text("") @mail_window.hide @mail_window = nil @main.hide open_mail(@key) end def start super create_background @mail_busy = false @showing_attached = false @actions_showing = false @main = Mail_Command.new(Graphics.width - 180, 35) @main.arrows_visible = false @main.set_handler(:unread, method(:new_mail)) @main.set_handler(:archived, method(:old_mail)) @main.set_handler(:quit, method(:exit)) end def stored @stored_mail = ZMail.get_mail(1) @arch = true key_in = @main.index @key = @stored_mail[key_in] open_mail(@key) end def unread @unread_mail = ZMail.get_mail(0) key_in = @main.index @key = @unread_mail[key_in] open_mail(@key) end def update super update_fiber if Input.trigger?(:B) && @mail_busy == false && @showing_attached == false && @actions_showing == false exit end end def exit @send_name.hide if @send_name @notif.hide if @notif @mail_window.hide if @mail_window @main.hide if @main @send_name = nil @notif = nil @mail_window = nil @main = nil SceneManager.return end def update_fiber if @fiber @fiber.resume elsif @mail_busy == true @fiber = Fiber.new {read} @fiber.resume elsif @showing_attached == true @fiber = Fiber.new {notify_attached} @fiber.resume end end def wait(duration) duration.times { Fiber.yield } end end class Window_MenuCommand < Window_Command alias additional_commands add_original_commands def add_original_commands additional_commands if ZSettings::Mail_Add_Menu == true add_command(ZSettings::Mail_Menu_Name, :call_mail) end end end class Scene_Menu < Scene_MenuBase alias setup_window create_command_window def create_command_window setup_window @command_window.set_handler(:call_mail, method(:mail)) end def mail SceneManager.call(Scene_ZMail) end end