neonblack

Character Composite V2.1

Oct 24th, 2012
8,363
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ##----------------------------------------------------------------------------##
  2. ## Composite Character v2.1
  3. ## Created by Neon Black
  4. ##
  5. ## Only for non-commercial use.  See full terms of use and contact info at:
  6. ## http://cphouseset.wordpress.com/liscense-and-terms-of-use/
  7. ##----------------------------------------------------------------------------##
  8.                                                                               ##
  9. ##----------------------------------------------------------------------------##
  10. ##    Revision Info:
  11. ## V2.1 - 2.12.2013
  12. ##  Added new script calls
  13. ## V2.0 - 1.24.2013
  14. ##  Rewrote entire script from scratch
  15. ## V1.0 - 10.17.2012
  16. ##  Wrote and debugged main script
  17. ##----------------------------------------------------------------------------##
  18.                                                                               ##
  19. $imported = {} if $imported.nil?                                              ##
  20. $imported["COMPOSITE"] = 2.1                                                  ##
  21.                                                                               ##
  22. ##----------------------------------------------------------------------------##
  23. ##    Instructions:
  24. ## Place this script in the "Materials" section of the scripts above "Main".
  25. ## To use this script you must have additional composite graphics in a folder
  26. ## for characters and a folder for faces.  Charactersets will use composites
  27. ## based on their names in the NAMES setting.  Some layers of the composite
  28. ## may also change based on the equipped items on the actor associated with
  29. ## file name.  There are several tags that work with both actors and equips.
  30. ##
  31. ##    Tags:
  32. ## tag init[Handler, hue]
  33. ##  - Can only be tagged in actors.  Changes composite layer :tag to handler
  34. ##    "Handler" with the defined hue.  Do not use colons for layer names or
  35. ##    quotes for file handler names.
  36. ## gender[male]
  37. ##  - Sets the character's initial gender to "male" or "female" depending on
  38. ##    which you place in the brackets.  This can only tag actors.
  39. ## alt name[Christopher]
  40. ##  - Sets the character's name for the opposite gender.  If the player changes
  41. ##    the gender in the GUI and has not changed the name, the new name will be
  42. ##    displayed.  The name "Christopher" here can be any name you desire.
  43. ## tag image[Handler, hue]
  44. ##  - Changes the default images for layer :tag to file handler "Handler".
  45. ##
  46. ##    Script Calls:
  47. ## The character creation screen can be called with either of these two script
  48. ## calls from an event.  Other script calls also exist.
  49. ##
  50. ## creation(id)  -or-  creation(id, array)
  51. ##  - The value "id" can be either the actor's ID or the name of the character
  52. ##    set to modify.  The "array" value does not need to be used ever.  This is
  53. ##    the array of handlers from "GUI_LISTS" to use.  If no array is defined,
  54. ##    "BASE_GUI" is used instead.
  55. ## composite_custom(id, handler, name, hue)
  56. ##  - Changes composite "id"'s layer "handler" into file "name" with a hue of
  57. ##    "hue".  This occurs on the same priority level as the character creation
  58. ##    screen, so it is covered by armour and can be modified by the player.
  59. ##    "id" must be a value from NAMES, "handler" a layer from COMPOSITE, "name"
  60. ##    a file from FILE_HANDLERS, and "hue" a number from 0 to 255.
  61. ## composite_force(id, handler, name, hue)
  62. ##  - Similar to the command above, but this takes the highest priority when
  63. ##    being drawn and cannot be changed by the player.
  64. ## composite_reset(id)
  65. ##  - Removes all layers added using the "composite_force" script call.
  66. ##
  67. ##    Special Layers:
  68. ## In order to allow a slight bit more customization, there are 3 types of
  69. ## special layers that link directly to other layers.  These layers end with
  70. ## "Back", "Hueless", and "All".
  71. ##
  72. ## Back Layers
  73. ##  - These layers do not actually need to be behind the normal layer.  They
  74. ##    are simply a second layer with all the same properties of the parent
  75. ##    layer.  An example would be :hairRear which would be a rear layer of
  76. ##    :hair.
  77. ## Hueless Layers
  78. ##  - These layers ignore the changed hue values.  The main use of these would
  79. ##    be objects with skin tone or perhaps objects that you only want to change
  80. ##    part of the colour on.  The only object that uses this in the example
  81. ##    is :eyesHueless which is a hueless layer of :eyes.
  82. ## All Layers
  83. ##  - These are special layers on the character.  They are a layer that appears
  84. ##    on the character no matter what the player does.  The file that appears
  85. ##    is still linked to the file part it is attatched to for the sake of hue.
  86. ##    The file that appears for one of these layers is defined in the hash
  87. ##    GUI_OPTIONS.
  88. ##----------------------------------------------------------------------------##
  89.                                                                               ##
  90. module CP        # Do not touch                                               ##
  91. module COMPOSITE #  these lines.                                              ##
  92.                                                                               ##
  93. ##----------------------------------------------------------------------------##
  94. ##    Config:
  95. ## The config options are below.  You can set these depending on the flavour of
  96. ## your game.  Each option is explained in a bit more detail above it.
  97. ##
  98. ##------
  99.  
  100. # The folders containing the composite parts for characters and for facesets.
  101. CHAR_FOLDER = "Graphics/Composite/Charas/"
  102. FACE_FOLDER = "Graphics/Composite/Faces/"
  103.  
  104. # Determines if the creation screen uses face sets are not.  Set to false if
  105. # you do not want a faceset displayed.
  106. USE_FACESETS = true
  107.  
  108. # The width and height of the character window in the creation screen.  The
  109. # character in the screen is zoomed in to 200%.
  110. WINDOW_WIDTH = 90
  111. WINDOW_HEIGHT = 112
  112.  
  113. # The text options for the character selection GUI.  EMPTY_TEXT refers to an
  114. # option which is blank for some reason.
  115. GUI_CLOSE = "Finish Editing"
  116. EMPTY_TEXT = "None"
  117.  
  118. # The number of allowed character spaces for names when input from the editor.
  119. CHARACTERS = 6
  120.  
  121. # Names for the male and female genders.
  122. GENDER_NAMES = ["Male", "Female"]
  123.  
  124. # Determines if male undefined characters start out as male characters.
  125. MALE_DEFAULT = true
  126.  
  127. ##------
  128.  
  129. # Determine the files that are recognized as composite images and the actor
  130. # they are linked to, for the sake of armour, storage, etc.
  131. NAMES ={
  132.   "$Hero1" => 11,
  133.   "$Hero2" => 12,
  134. }
  135.  
  136. # The switches related to characters.  A switch is turned ON when the character
  137. # is male and OFF when the character is female.
  138. SWITCHES ={
  139.   11 => 72,
  140.   12 => 73,
  141. }
  142.  
  143. # The order for composite layers.  The first layer is the lowest layer.
  144. COMPOSITE =[
  145.   :hairRear,
  146.   :cape,
  147.   :armorRear,
  148.   :headAll,
  149.   :head,
  150.   :eyes,
  151.   :eyesAll,
  152.   :eyesHueless,
  153.   :armor,
  154.   :hair,
  155.   :glasses,
  156.   :helmet,
  157. ]
  158.  
  159. # These are the handlers for all files in the composite folders.  Actor and
  160. # equip tags as well as GUI options point to a handler and the handler
  161. # determines the male and female files to look up.  Make sure every handler
  162. # has a different name.
  163. FILE_HANDLERS ={
  164. # "Handler"       => ["Male_File", "Female_File"],
  165.   "Shaggy"        => ["Hair1M", nil],
  166.   "Slick"         => ["Hair2M", nil],
  167.   "Spiked"        => ["Hair3M", nil],
  168.   "Fancy"         => ["Hair4M", nil],
  169.   "Stylish"       => [nil, "Hair1F"],
  170.   "Waist Length"  => [nil, "Hair2F"],
  171.   "Curled"        => [nil, "Hair3F"],
  172.   "Pigtails"      => [nil, "Hair4F"],
  173.   "Short"         => ["Hair1U", "Hair1U"],
  174.   "Long"          => ["Hair2U", "Hair2U"],
  175.   "Observant"     => ["Eye1M", "Eye1F"],
  176.   "Closed"        => ["Eye2M", "Eye2F"],
  177.   "Intent"        => ["Eye3M", "Eye3F"],
  178.  
  179.   "HeadBase"      => ["HeadAll", "HeadAll"],
  180.   "FaceBase"      => ["FaceM", "FaceF"],
  181.   "BodyBase"      => ["BaseM", "BaseF"],
  182.  
  183.   "Clothes"       => ["ClothesM", "ClothesF"],
  184.   "Cloth"         => ["ClothM", "ClothF"],
  185.   "Armor"         => ["ArmourM", "ArmourF"],
  186.   "Glasses"       => ["Glasses", "Glasses"],
  187.   "Sunglasses"    => ["Sunglasses", "Sunglasses"],
  188.   "Goggles"       => ["Goggles", "Goggles"],
  189. }
  190.  
  191. # Standard handlers.  These are default handlers of certain layers.
  192. STANDARD ={
  193.   :headAll  => "HeadBase",
  194.   :head     => "FaceBase",
  195.   :armor    => "BodyBase",
  196. }
  197.  
  198. # The GUI options that may be called from an array.  If the "Name" field is set
  199. # to a :symbol like the :barber example, it will point back to another option
  200. # and use that option's name and layer.  The point is simply to link different
  201. # handlers to it as well as giving it different colour options.  The colorize?
  202. # option can be set to a value of 0, 1, or 2 depending on the style of hue bar
  203. # you would like displayed.  If it is set to 0, no bar will be displayed.
  204. GUI_OPTIONS ={
  205. # :handler  => ["Name",   colorize?, "AllFile"],
  206.   :Name     => ["Name",   0,         nil],
  207.   :Gender   => ["Gender", 0,         nil],
  208.   :hair     => ["Hair",   1,         nil],
  209.   :eyes     => ["Eyes",   1,         "EyeAll"],
  210.  
  211.   :barber   => [:hair,    true,      nil],
  212. }
  213.  
  214. # These are the basic options to use in the GUI if no array is defined.
  215. BASE_GUI = [:Name, :Gender, :hair, :eyes]
  216.  
  217. # These are the lists that refer to the options.  Male and Female only options
  218. # are automatically filtered depending on the character's gender.
  219. GUI_LISTS ={
  220.   :hair     => ["Shaggy", "Slick", "Spiked", "Fancy", "Stylish", "Waist Length",
  221.                 "Curled", "Pigtails"],
  222.   :eyes     => ["Observant", "Intent", "Closed"],
  223.  
  224.  
  225.   :barber   => ["Shaggy", "Slick", "Spiked", "Fancy", "Stylish", "Waist Length",
  226.                 "Curled", "Pigtails", "Short", "Long"],
  227. }
  228.  
  229. ##----------------------------------------------------------------------------##
  230.                                                                               ##
  231.                                                                               ##
  232. ##----------------------------------------------------------------------------##
  233. ## The following lines are the actual core code of the script.  While you are
  234. ## certainly invited to look, modifying it may result in undesirable results.
  235. ## Modify at your own risk!
  236. ###----------------------------------------------------------------------------
  237.  
  238.  
  239. end
  240. end
  241.  
  242. module Cache
  243.   class << self  ## Alias for the used methods in this module.
  244.     alias cp_cm_character character
  245.     alias cp_cm_face face
  246.     alias cp_cm_clear clear
  247.   end
  248.  
  249.   def self.character(*args)  ## Checks if the file is a composite.
  250.     return cp_cm_character(*args) unless Composites.include?(args[0])
  251.     create_composite(args[0], "Graphics/Characters/")
  252.     hue = args[1] ? args[1] : 0
  253.     load_bitmap("Graphics/Characters/", args[0], hue)
  254.   end
  255.  
  256.   def self.face(*args)  ## Checks if the face is a composite.
  257.     return cp_cm_face(*args) unless Composites.include?(args[0])
  258.     create_composite(args[0], "Graphics/Faces/")
  259.     hue = args[1] ? args[1] : 0
  260.     load_bitmap("Graphics/Faces/", args[0], hue)
  261.   end
  262.  
  263.   def self.need_comp_ref?(file, path)  ## Checks refresh status.
  264.     return true if Composites.refresh?(file)
  265.     return true if @cache[path].nil? || @cache[path].disposed?
  266.     return false
  267.   end
  268.  
  269.   def self.create_composite(file, folder)  ## Find and create the composite.
  270.     path = "#{folder}#{file}"
  271.     return unless need_comp_ref?(file, path)
  272.     foldrs = ["Graphics/Characters/", "Graphics/Faces/"]
  273.     Composites.constants.each_with_index do |fld, i|
  274.       paths = "#{foldrs[i]}#{file}"
  275.       array = Composites.images(file)
  276.       Composites.layers do |i|
  277.         image = array[i]
  278.         unless @temp
  279.           @temp = Bitmap.new("#{fld}#{image}") rescue next
  280.           @temp.hue_change(Composites.hues(file)[i]) unless Composites.hues(file)[i].nil?
  281.         else
  282.           t = Bitmap.new("#{fld}#{image}") rescue next
  283.           t.hue_change(Composites.hues(file)[i]) unless Composites.hues(file)[i].nil?
  284.           @temp.blt(0, 0, t, t.rect)
  285.           t.dispose; t = nil
  286.         end
  287.       end
  288.       @temp = Bitmap.new unless @temp
  289.       Composites.refreshed(file)
  290.       @cache[paths] = Bitmap.new(@temp.width, @temp.height)
  291.       @cache[paths].blt(0, 0, @temp, @temp.rect)
  292.       @temp.dispose; @temp = nil
  293.     end
  294.     Composites.remove_temp_layers(file)
  295.   end
  296.  
  297.   def self.clear  ## Reset the composite cache.
  298.     cp_cm_clear
  299.     Composites.clear
  300.   end
  301. end
  302.  
  303. module Composites
  304.   def self.include?(file)  ## Checks if a file is a composite.
  305.     return CP::COMPOSITE::NAMES.include?(file)
  306.   end
  307.  
  308.   def self.options  ## Easy access of the options hash.
  309.     return CP::COMPOSITE::GUI_OPTIONS
  310.   end
  311.  
  312.   def self.lists  ## Easy access of the gui lists hash.
  313.     return CP::COMPOSITE::GUI_LISTS
  314.   end
  315.  
  316.   def self.list_by_block(handler, block)  ## Returns a list based on gender.
  317.     return [] unless [0, 1].include?(block) && lists.include?(handler)
  318.     return lists[handler].select {|a| !files[a][block].nil?}
  319.   end
  320.  
  321.   def self.layers  ## Gets each layer key one at a time.
  322.     CP::COMPOSITE::COMPOSITE.each do |key|
  323.       yield key
  324.     end
  325.   end
  326.  
  327.   def self.constants  ## Gets the folder constants.
  328.     if CP::COMPOSITE::USE_FACESETS
  329.       return [CP::COMPOSITE::CHAR_FOLDER, CP::COMPOSITE::FACE_FOLDER]
  330.     else
  331.       return [CP::COMPOSITE::CHAR_FOLDER]
  332.     end
  333.   end
  334.  
  335.   def self.files  ## Gets the file handler hash.
  336.     return CP::COMPOSITE::FILE_HANDLERS
  337.   end
  338.  
  339.   def self.include_block?(block, handler)  ## Checks gender blocks to handlers.
  340.     return false unless files.include?(handler)
  341.     return !files[handler][block].nil?
  342.   end
  343.  
  344.   def self.standard  ## Gets the standard GUI display.
  345.     return CP::COMPOSITE::STANDARD
  346.   end
  347.  
  348.   def self.get_first_handler(block, key)  ## Gets the init files based on block.
  349.     return nil if ![0, 1].include?(block) || !lists.include?(key)
  350.     lists[key].each do |handler|
  351.       next unless files.include?(handler)
  352.       return handler unless files[handler][block].nil?
  353.     end
  354.     return nil
  355.   end
  356.  
  357.   def self.n(file)  ## Returns a number from a file.
  358.     return CP::COMPOSITE::NAMES[file]
  359.   end
  360.  
  361.   def self.refreshed(file)  ## Resets a file's refresh status.
  362.     return unless n(file)
  363.     actor(file).composite_refresh = false
  364.   end
  365.  
  366.   def self.images(file)  ## Get all images of a file.
  367.     return @temp_images[file] if @temp_images && @temp_images[file]
  368.     return actor(file).composite_images
  369.   end
  370.  
  371.   def self.hues(file)  ## Get all hues of a file.
  372.     return @temp_hues[file] if @temp_hues && @temp_hues[file]
  373.     return actor(file).composite_hues
  374.   end
  375.  
  376.   def self.remove_temp_layers(file)  ## Removes temporary (save) layers.
  377.     @temp_images.delete(file) if @temp_images
  378.     @temp_hues.delete(file) if @temp_hues
  379.   end
  380.  
  381.   def self.make_temp_file(file, handlers)  ## Create a new temp of a file.
  382.     @temp_images = {} if @temp_images.nil?; @temp_hues = {} if @temp_hues.nil?
  383.     @temp_images[file] = {}; @temp_hues[file] = {}
  384.     handlers.each do |key, array|
  385.       @temp_images[file][key] = array[0]
  386.       @temp_hues[file][key] = array[1]
  387.     end
  388.   end
  389.  
  390.   def self.refresh?(file)  ## Check if a file needs refreshing.
  391.     return false unless n(file)  ## Includes temp file checking.
  392.     return true if @temp_images && @temp_images.include?(file)
  393.     return actor(file).composite_refresh
  394.   end
  395.  
  396.   def self.actor(file)  ## Gets a game actor from a file name.
  397.     return $game_actors[n(file)]
  398.   end
  399.  
  400.   def self.clear  ## Allows forced reset of each file.
  401.     CP::COMPOSITE::NAMES.keys.each do |file|
  402.       actor(file).composite_refresh = true
  403.     end
  404.   end
  405. end
  406.  
  407. class Game_Actor < Game_Battler
  408.   attr_accessor :composite_refresh
  409.  
  410.   alias cp_cmpst_init initialize
  411.   def initialize(*args)  ## Sets the initial values for composites.
  412.     cp_cmpst_init(*args)
  413.     @composite_refresh = true
  414.     @editor_changes = {}
  415.     @editor_hues = {}
  416.     @forced_composites = {}
  417.   end
  418.  
  419.   def composite_images  ## Returns the composite images for an actor.
  420.     make_composite_lists if @composite_refresh
  421.     return @composite_images
  422.   end
  423.  
  424.   def composite_hues  ## Returns the composite hues.
  425.     make_composite_lists if @composite_refresh
  426.     return @composite_hues
  427.   end
  428.  
  429.   def edd_additions(hueless, rear)  ## Make a new filename based on layers.
  430.     a = ""
  431.     b = hueless ? "#{a}Hueless" : a
  432.     c = rear ? "#{b}Rear" : b
  433.     return c
  434.   end
  435.  
  436.   def get_composite_lists  ## Gets a composite list for save files.
  437.     return {} unless Composites.include?(character_name)
  438.     make_composite_lists
  439.     r = {}
  440.     @composite_images.each {|k, v| r[k] = [v, @composite_hues[k]]}
  441.     return r
  442.   end
  443.  
  444.   def make_composite_lists  ## Makes the list of composites and hues.
  445.     @composite_images = {}
  446.     @composite_hues = {}
  447.     @composite_male = get_base_gender  ## Sets gender.
  448.     if CP::COMPOSITE::SWITCHES.include?(@actor_id)  ## Sets a gender switch.
  449.       $game_switches[CP::COMPOSITE::SWITCHES[@actor_id]] = @composite_male
  450.     end
  451.     block = @composite_male ? 0 : 1
  452.     make_equip_hashes(block)  ## Ensures equips are set up.
  453.     Composites.layers do |key|  ## Check each layer.
  454.       @composite_hues[key] = 0  ## Gets init values for variables.
  455.       name = nil
  456.       string = key.to_s
  457.       hueless = string.include?("Hueless")
  458.       rear = string.include?("Rear")
  459.       all = string.include?("All")
  460.       string.gsub!(/(Hueless|All|Rear)/, '')
  461.       edd = edd_additions(hueless, rear)
  462.       line = CP::COMPOSITE::GUI_OPTIONS[string.to_sym]
  463.       handler = get_composite_handler(key)
  464.       parent = get_composite_handler(string.to_sym)
  465.       hues = get_composite_hue(key)
  466.       if all && !line.nil?  ## Determines the needed value.
  467.         name = line[2]
  468.       elsif handler && Composites.files.include?(handler) &&
  469.             Composites.files[handler][block]
  470.         name = "#{Composites.files[handler][block]}#{edd}"
  471.       elsif parent && Composites.files.include?(parent) &&
  472.             Composites.files[parent][block] && (rear || hueless)
  473.         name = "#{Composites.files[parent][block]}#{edd}"
  474.       elsif Composites.standard.include?(key)
  475.         name = Composites.files[Composites.standard[key]][block]
  476.       end
  477.       next unless name  ## Skips if there is no name.
  478.       @composite_images[key] = name  ## Creates the hashes.
  479.       @composite_hues[key] = hueless ? 0 : hues
  480.     end
  481.   end
  482.  
  483.   def get_base_gender  ## Gets the gender.
  484.     return @editor_changes[:Gender] if @editor_changes.include?(:Gender)
  485.     return actor.gender_base
  486.   end
  487.  
  488.   def get_composite_handler(key)  ## Complex method to find the file handler.
  489.     block = @composite_male ? 0 : 1
  490.     if @forced_composites.include?(key) && Composites.include_block?(block,
  491.        @forced_composites[key][0])
  492.       hues = @forced_composites[key][0]
  493.     elsif @equip_hashes.include?(key) && Composites.include_block?(block,
  494.        @equip_hashes[key][0])
  495.       handler = @equip_hashes[key][0]
  496.     elsif @editor_changes.include?(key) && Composites.include_block?(block,
  497.           @editor_changes[key])
  498.       handler = @editor_changes[key]
  499.     elsif actor.composite_init.include?(key) && Composites.include_block?(block,
  500.           actor.composite_init[key][0])
  501.       handler = actor.composite_init[key][0]
  502.     elsif Composites.get_first_handler(block, key)
  503.       handler = Composites.get_first_handler(block, key)
  504.     else
  505.       handler = nil
  506.     end
  507.     return handler
  508.   end
  509.  
  510.   def get_composite_hue(key)  ## Same as above but for hues.
  511.     block = @composite_male ? 0 : 1
  512.     if @forced_composites.include?(key) && Composites.include_block?(block,
  513.        @forced_composites[key][0])
  514.       hues = @forced_composites[key][1]
  515.     elsif @equip_hashes.include?(key) && Composites.include_block?(block,
  516.        @equip_hashes[key][0])
  517.       hues = @equip_hashes[key][1]
  518.     elsif @editor_changes.include?(key) && Composites.include_block?(block,
  519.           @editor_changes[key])
  520.       hues = @editor_hues[key]
  521.     elsif actor.composite_init.include?(key) && Composites.include_block?(block,
  522.           actor.composite_init[key][0])
  523.       hues = actor.composite_init[key][1]
  524.     else
  525.       hues = 0
  526.     end
  527.     return hues
  528.   end
  529.  
  530.   def make_equip_hashes(block)  ## Makes the handler hash for equips.
  531.     @equip_hashes = {}
  532.     equips.each do |eq|
  533.       next unless eq
  534.       eq.composite_hash.each do |key, array|
  535.         next if Composites.files[array[0]][male? ? 0 : 1].nil?
  536.         @equip_hashes[key] = array
  537.       end
  538.     end
  539.   end
  540.  
  541.   alias cp_composite_change_eq change_equip
  542.   def change_equip(*args)  ## Ensures refreshing on equip change.
  543.     cp_composite_change_eq(*args)
  544.     @composite_refresh = true
  545.   end
  546.  
  547.   def change_composite(hand, value = nil, hue = nil)
  548.     array = ["#{hand}".to_sym, "#{hand}Rear".to_sym, "#{hand}Hueless".to_sym,
  549.              "#{hand}All".to_sym]
  550.     array.each do |handler|  ## Changes values for a layer and sublayers.
  551.       unless value.nil?
  552.         @editor_changes[handler] = value
  553.         @editor_hues[handler] = hue if hue
  554.       else
  555.         @editor_changes.delete(handler)
  556.         @editor_hues.delete(handler)
  557.       end
  558.     end
  559.     @composite_refresh = true
  560.   end
  561.  
  562.   def force_composite(hand, value = nil, hue = nil)
  563.     array = ["#{hand}".to_sym, "#{hand}Rear".to_sym, "#{hand}Hueless".to_sym,
  564.              "#{hand}All".to_sym]
  565.     array.each do |handler|  ## Changes values for a layer and sublayers.
  566.       unless value.nil?
  567.         @forced_composites[handler] = []
  568.         @forced_composites[handler][0] = value
  569.         @forced_composites[handler][1] = hue if hue
  570.       else
  571.         @forced_composites.delete(handler)
  572.       end
  573.     end
  574.     @composite_refresh = true
  575.   end
  576.  
  577.   def reset_composite
  578.     @forced_composites = {}
  579.     @composite_refresh = true
  580.   end
  581.  
  582.   def reset_name  ## Changes the name to a default name.
  583.     return if actor.alt_name.empty?
  584.     @composite_male = get_base_gender
  585.     if @composite_male == actor.gender_base
  586.       @name = actor.name if @name == actor.alt_name
  587.     else
  588.       @name = actor.alt_name if @name == actor.name
  589.     end
  590.   end
  591.  
  592.   def male?  ## Check if the actor is male.
  593.     return @composite_male
  594.   end
  595. end
  596.  
  597. class Window_SaveFile < Window_Base
  598.   def draw_party_characters(x, y)  ## Creates a temp array for the save file.
  599.     header = DataManager.load_header(@file_index)
  600.     return unless header
  601.     header[:characters].each_with_index do |data, i|
  602.       Composites.make_temp_file(data[0], data[2])
  603.       draw_character(data[0], data[1], x + i * 48, y)
  604.     end
  605.   end
  606. end
  607.  
  608. class Game_Party < Game_Unit
  609.   def characters_for_savefile  ## Adds the composite arrays to a save file.
  610.     battle_members.collect do |actor|
  611.       [actor.character_name, actor.character_index, actor.get_composite_lists]
  612.     end
  613.   end
  614. end
  615.  
  616. class Scene_Load < Scene_File  ## Clears the composites on a load.
  617.   alias cp_comp_load_succ on_load_success
  618.   def on_load_success
  619.     Composites.clear
  620.     cp_comp_load_succ
  621.   end
  622. end
  623.  
  624. class Scene_Save < Scene_File  ## Clears the composites on save.
  625.   alias cp_comp_save_ok on_savefile_ok
  626.   def on_savefile_ok
  627.     Composites.clear
  628.     cp_comp_save_ok
  629.   end
  630. end
  631.  
  632. class Bitmap
  633.   def draw_rainbow(*args)  ## Draws a rainbow rectangle.
  634.     case args.size
  635.     when 1
  636.       rect = args[0].clone
  637.     when 4
  638.       rect = Rect.new(args[0], args[1], args[2], args[3])
  639.     end
  640.     ca = rainbow_colours
  641.     6.times do |i|
  642.       wv = rect.width / (6 - i)
  643.       n = i == 5 ? 0 : 1
  644.       r2 = Rect.new(rect.x, rect.y, wv + n, rect.height)
  645.       self.gradient_fill_rect(r2, ca[i], ca[(i + 1) % 6])
  646.       rect.width -= wv
  647.       rect.x += wv
  648.     end
  649.   end
  650.  
  651.   def rainbow_colours  ## Colours for the rectangle.
  652.     c1 = Color.new(255,   0,   0); c2 = Color.new(255, 255,   0)
  653.     c3 = Color.new(  0, 255,   0); c4 = Color.new(  0, 255, 255)
  654.     c5 = Color.new(  0,   0, 255); c6 = Color.new(255,   0, 255)
  655.     return [c1, c2, c3, c4, c5, c6]
  656.   end
  657.  
  658.   @@wheel = Bitmap.new(360, 1)
  659.   @@wheel.draw_rainbow(0, 0, 360, 1)
  660.  
  661.   def self.hue_colour_wheel(hue)  ## Show the new hue colour.
  662.     if @@wheel.disposed?
  663.       @@wheel = Bitmap.new(360, 1)
  664.       @@wheel.draw_rainbow(0, 0, 360, 1)
  665.     end
  666.     return @@wheel.get_pixel(hue % 360, 0)
  667.   end
  668. end
  669.  
  670. ## The core bits of the script scene are below.
  671. class Window_CCFace < Window_Base
  672.   def initialize(actor, input)
  673.     super(0, 0, 120, 120)
  674.     self.visible = CP::COMPOSITE::USE_FACESETS
  675.     @input_window = input
  676.     self.y = @input_window.y
  677.     self.x = @input_window.x - (self.width + 8)
  678.     @actor = $data_actors[actor]
  679.     refresh
  680.   end
  681.  
  682.   def refresh
  683.     contents.clear
  684.     draw_face(@actor.face_name, @actor.face_index, 0, 0)
  685.   end
  686. end
  687.  
  688. class Window_CCCharacter < Window_Base
  689.   def initialize(actor, input)
  690.     super(0, 0, CP::COMPOSITE::WINDOW_WIDTH, CP::COMPOSITE::WINDOW_HEIGHT)
  691.     @input_window = input
  692.     self.y = @input_window.y
  693.     self.x = @input_window.x + @input_window.width + 8
  694.     @actor = $data_actors[actor]
  695.     @ticker = 10
  696.     @last_frame = 1
  697.     @frame = 1
  698.     refresh
  699.   end
  700.  
  701.   def update
  702.     @ticker += 1
  703.     @frame = (@ticker % 40) / 10; @frame = 1 if @frame == 3
  704.     return if @frame == @last_frame
  705.     @last_frame = @frame
  706.     refresh
  707.   end
  708.  
  709.   def refresh
  710.     contents.clear
  711.     x = contents.width / 2
  712.     y = contents.height - 6
  713.     draw_character(@actor.character_name, @actor.character_index, x, y, @frame)
  714.   end
  715.  
  716.   def draw_character(character_name, character_index, x, y, frame = 1)
  717.     return unless character_name
  718.     bitmap = Cache.character(character_name)
  719.     sign = character_name[/^[\!\$]./]
  720.     if sign && sign.include?('$')
  721.       cw = bitmap.width / 3
  722.       ch = bitmap.height / 4
  723.     else
  724.       cw = bitmap.width / 12
  725.       ch = bitmap.height / 8
  726.     end
  727.     n = character_index
  728.     src_rect = Rect.new((n%4*3+frame)*cw, (n/4*4)*ch, cw, ch)
  729.     ret_rect = Rect.new(x - cw, y - cw * 2, cw * 2, ch * 2)
  730.     contents.stretch_blt(ret_rect, bitmap, src_rect)
  731.   end
  732. end
  733.  
  734. class Window_CCGui < Window_Selectable
  735.   def initialize(file, list)
  736.     @list = list
  737.     extra_width = CP::COMPOSITE::WINDOW_WIDTH + 8
  738.     extra_width += 128 if CP::COMPOSITE::USE_FACESETS
  739.     x = (Graphics.width - (180 + extra_width)) / 2
  740.     x += 128 if CP::COMPOSITE::USE_FACESETS
  741.     y = (Graphics.height - window_height) / 2
  742.     h = window_height
  743.     super(x, y, 180, h)
  744.     @file = file
  745.     refresh
  746.   end
  747.  
  748.   def window_height
  749.     [fitting_height(item_max * 2), Graphics.height].min
  750.   end
  751.  
  752.   def item_max
  753.     @list.size + 1
  754.   end
  755.  
  756.   def contents_height
  757.     (item_max * 2) * line_height
  758.   end
  759.  
  760.   def item_height
  761.     line_height * 2
  762.   end
  763.  
  764.   def refresh
  765.     contents.clear
  766.     draw_all_items
  767.   end
  768.  
  769.   def data
  770.     @list[@index]
  771.   end
  772.  
  773.   def adj_data
  774.     if Composites.options[data][0].is_a?(Symbol)
  775.       return Composites.options[data][0]
  776.     else
  777.       return data
  778.     end
  779.   end
  780.  
  781.   def draw_item(index)
  782.     rect = item_rect(index)
  783.     lh = line_height
  784.     if index == @list.size
  785.       text = CP::COMPOSITE::GUI_CLOSE
  786.       change_color(normal_color)
  787.       draw_text(rect.x + 2, rect.y + lh / 2, rect.width - 4, lh, text, 1)
  788.     else
  789.       block = Composites.options[@list[index]]
  790.       if block[0].is_a?(Symbol)
  791.         title = Composites.options[block[0]][0]
  792.       else
  793.         title = block[0]
  794.       end
  795.       value = (CP::COMPOSITE::COMPOSITE.include?(@list[index]) ||
  796.               @list[index] == :Gender || @list[index] == :Name)
  797.       sym = value ? @list[index] : block[0]
  798.       change_color(system_color)
  799.       draw_text(rect.x + 2, rect.y, rect.width - 4, lh, title)
  800.       case sym
  801.       when :Gender
  802.         na = CP::COMPOSITE::GENDER_NAMES
  803.         name = Composites.actor(@file).male? ? na[0] : na[1]
  804.       when :Name
  805.         name = Composites.actor(@file).name
  806.       else
  807.         name = Composites.actor(@file).get_composite_handler(sym)
  808.         name = CP::COMPOSITE::EMPTY_TEXT if name.nil?
  809.         hue = Composites.actor(@file).get_composite_hue(sym)
  810.         if block[1]
  811.           c1 = Bitmap.hue_colour_wheel(hue)
  812.           c2 = Color.new(c1.red, c1.green, c1.blue, 0)
  813.           r2 = contents.text_size(name).width
  814.           hr = Rect.new(contents.width - (r2 + 6), rect.y + lh + 3, r2 + 1, lh - 6)
  815.           contents.gradient_fill_rect(hr, c2, c1)
  816.         end
  817.       end
  818.       change_color(normal_color)
  819.       draw_text(rect.x + 2, rect.y + lh, rect.width - 6, lh, name, 2)
  820.     end
  821.   end
  822. end
  823.  
  824. class Window_CCSelect < Window_Selectable
  825.   attr_reader :hue
  826.  
  827.   def initialize(file, input)
  828.     super(0, 0, 160, 0)
  829.     @input_window = input
  830.     @file = file
  831.     @data = nil
  832.     @hue = 0
  833.   end
  834.  
  835.   def item_max
  836.     return 1 if @data.nil? || @data.empty?
  837.     return @data.size
  838.   end
  839.  
  840.   def refresh
  841.     contents.clear
  842.     draw_all_items
  843.     draw_hue_wheel
  844.   end
  845.  
  846.   def draw_item(index)
  847.     rect = item_rect(index); rect.x += 2; rect.width -= 4
  848.     change_color(normal_color)
  849.     draw_text(rect, @data[index])
  850.   end
  851.  
  852.   def draw_hue_wheel
  853.     rect = item_rect(item_max); contents.clear_rect(rect)
  854.     rect.y += 4; rect.height -= 8; rect.x += 8; rect.width -= 16
  855.     ind = Composites.options[@input_window.data]
  856.     return if !ind || ind[1] == 0
  857.     if ind[1] == 2
  858.       value = @hue >= 180 ? @hue - 360 : @hue
  859.       rect.height /= 2; rect.height -= 1; rect.x -= 60
  860.       contents.draw_rainbow(rect)
  861.       rect.y += (rect.height + 1); rect.x -= value / 3
  862.       contents.draw_rainbow(rect)
  863.       rect.x += 119
  864.       contents.draw_rainbow(rect)
  865.       rect.y -= (rect.height + 1); rect.x += value / 3
  866.       contents.draw_rainbow(rect)
  867.       bitmap2 = Bitmap.new(10, 19)
  868.       bitmap2.fill_rect(0, 0, 10, 19, Color.new(255, 255, 255))
  869.       c1 = Bitmap.hue_colour_wheel(0)
  870.       c2 = Bitmap.hue_colour_wheel(@hue)
  871.       bitmap2.gradient_fill_rect(1, 1, 8, 17, c1, c2, true)
  872.       rect = item_rect(item_max)
  873.       contents.blt((rect.width - 10) / 2, rect.y + 2, bitmap2, bitmap2.rect)
  874.       rect.width = 10
  875.       contents.clear_rect(rect)
  876.       rect.x = contents.width - rect.width
  877.       contents.clear_rect(rect)
  878.     elsif ind[1] == 1
  879.       contents.draw_rainbow(rect)
  880.       bitmap2 = Bitmap.new(7, 20)
  881.       bitmap2.fill_rect(0, 0, 7, 20, Color.new(255, 255, 255))
  882.       bitmap2.fill_rect(1, 2, 5, 16, Bitmap.hue_colour_wheel(@hue))
  883.       off = @hue / 3
  884.       contents.blt(rect.x - 3 + off, rect.y - 2, bitmap2, bitmap2.rect)
  885.     end
  886.   end
  887.  
  888.   def show
  889.     val = @input_window.adj_data
  890.     ind = @input_window.data
  891.     actor = Composites.actor(@file)
  892.     block = Composites.actor(@file).male? ? 0 : 1
  893.     @name = Composites.list_by_block(ind, block).index(actor.get_composite_handler(val))
  894.     @index = val != :Gender ? @name : Composites.actor(@file).male? ? 0 : 1
  895.     @index = 0 if @index.nil?
  896.     @hue = actor.get_composite_hue(val) unless val == :Gender
  897.     cont = Composites.options[ind]
  898.     if val == :Gender
  899.       @data = CP::COMPOSITE::GENDER_NAMES
  900.     else
  901.       @data = Composites.list_by_block(ind, block)
  902.     end
  903.     add = Composites.options[ind][1] ? 1 : 0
  904.     add = 0 if val == :Gender
  905.     self.height = fitting_height(@data.size + add)
  906.     create_contents
  907.     refresh
  908.     self.x = @input_window.x + 16
  909.     iw = @input_window
  910.     self.y = iw.y + iw.standard_padding + (iw.index * (iw.line_height * 2)) - iw.oy + 28
  911.     self.y = Graphics.height - self.height if y + height > Graphics.height
  912.     super
  913.     activate
  914.   end
  915.  
  916.   def cursor_right(wrap)
  917.     return if Composites.options.include?(@input_window.data) &&
  918.               !Composites.options[@input_window.data][1]
  919.     @hue /= 12; @hue *= 12
  920.     @hue += 12; @hue -= 360 if @hue >= 360
  921.     draw_hue_wheel
  922.   end
  923.  
  924.   def cursor_left(wrap)
  925.     return if Composites.options.include?(@input_window.data) &&
  926.               !Composites.options[@input_window.data][1]
  927.     @hue /= 12; @hue *= 12
  928.     @hue -= 12; @hue += 360 if @hue < 0
  929.     draw_hue_wheel
  930.   end
  931. end
  932.  
  933. class Game_Interpreter
  934.   def creation(char, list = nil)  ## Allows for easy calling of the scene.
  935.     return if $game_party.in_battle
  936.     if char.is_a?(Integer)
  937.       return unless CP::COMPOSITE::NAMES.has_value?(char)
  938.       char = CP::COMPOSITE::NAMES.index(char)
  939.     else
  940.       return unless Composites.include?(char)
  941.     end
  942.     list = CP::COMPOSITE::BASE_GUI if list.nil?
  943.     return unless list.is_a?(Array)
  944.     SceneManager.call(Scene_CharacterCreation)
  945.     SceneManager.scene.prepare(char, list)
  946.     Fiber.yield
  947.   end
  948.  
  949.   def composite_force(char, handler, name, hue = 0)
  950.     if char.is_a?(Integer)
  951.       return unless CP::COMPOSITE::NAMES.has_value?(char)
  952.     else
  953.       return unless Composites.include?(char)
  954.       char = CP::COMPOSITE::NAMES[char]
  955.     end
  956.     $game_actors[char].force_composite(handler, name, hue)
  957.   end
  958.  
  959.   def composite_custom(char, handler, name, hue = 0)
  960.     if char.is_a?(Integer)
  961.       return unless CP::COMPOSITE::NAMES.has_value?(char)
  962.     else
  963.       return unless Composites.include?(char)
  964.       char = CP::COMPOSITE::NAMES[char]
  965.     end
  966.     $game_actors[char].change_composite(handler, name, hue)
  967.   end
  968.  
  969.   def composite_reset(char)
  970.     if char.is_a?(Integer)
  971.       return unless CP::COMPOSITE::NAMES.has_value?(char)
  972.     else
  973.       return unless Composites.include?(char)
  974.       char = CP::COMPOSITE::NAMES[char]
  975.     end
  976.     $game_actors[char].reset_composite
  977.   end
  978. end
  979.  
  980. class Scene_CharacterCreation < Scene_MenuBase
  981.   def prepare(file, list)
  982.     @file = file
  983.     @list = list
  984.   end
  985.  
  986.   def start
  987.     super
  988.     @actor = Composites.actor(@file)
  989.     create_windows
  990.   end
  991.  
  992.   def create_windows
  993.     @input_window = Window_CCGui.new(@file, @list)
  994.     @input_window.set_handler(:ok,      method(:gui_ok))
  995.     @input_window.set_handler(:cancel,  method(:gui_cancel))
  996.     @select_window = Window_CCSelect.new(@file, @input_window)
  997.     @select_window.set_handler(:ok,     method(:select_ok))
  998.     @select_window.set_handler(:cancel, method(:select_cancel))
  999.     @chara_window = Window_CCCharacter.new(@actor.id, @input_window)
  1000.     @face_window = Window_CCFace.new(@actor.id, @input_window)
  1001.     @input_window.activate.select(0)
  1002.     @select_window.hide
  1003.   end
  1004.  
  1005.   def gui_ok
  1006.     val = @input_window.data
  1007.     if val == :Name
  1008.       SceneManager.call(Scene_Name)
  1009.       SceneManager.scene.prepare(Composites.actor(@file).id, CP::COMPOSITE::CHARACTERS)
  1010.       @input_window.refresh
  1011.     elsif val == nil
  1012.       return_scene
  1013.     else
  1014.       @select_window.show
  1015.     end
  1016.   end
  1017.  
  1018.   def gui_cancel
  1019.     @input_window.activate.select(@input_window.item_max - 1)
  1020.   end
  1021.  
  1022.   def select_ok
  1023.     val = @input_window.data
  1024.     adj = @input_window.adj_data
  1025.     id = @select_window.index
  1026.     if adj == :Gender
  1027.       if id == 0
  1028.         Composites.actor(@file).change_composite(:Gender, true)
  1029.         Composites.actor(@file).reset_name
  1030.       elsif id == 1
  1031.         Composites.actor(@file).change_composite(:Gender, false)
  1032.         Composites.actor(@file).reset_name
  1033.       end
  1034.     else
  1035.       block = Composites.actor(@file).male? ? 0 : 1
  1036.       handler = Composites.list_by_block(val, block)[@select_window.index]
  1037.       hue = @select_window.hue
  1038.       Composites.actor(@file).change_composite(adj, handler, hue)
  1039.     end
  1040.     @select_window.hide
  1041.     @chara_window.refresh
  1042.     @face_window.refresh
  1043.     @input_window.activate.refresh
  1044.   end
  1045.  
  1046.   def select_cancel
  1047.     @select_window.hide
  1048.     @input_window.activate
  1049.   end
  1050. end
  1051.  
  1052. class RPG::BaseItem
  1053.   def composite_hash
  1054.     add_composite_data if @composite_hash.nil?
  1055.     return @composite_hash
  1056.   end
  1057.  
  1058.   def composite_init
  1059.     add_composite_data if @composite_init.nil?
  1060.     return @composite_init
  1061.   end
  1062.  
  1063.   def gender_base
  1064.     add_composite_data if @gender_base.nil?
  1065.     return @gender_base
  1066.   end
  1067.  
  1068.   def alt_name
  1069.     add_composite_data if @alt_name.nil?
  1070.     return @alt_name
  1071.   end
  1072.  
  1073.   INITI_RE = /(.+) init\[(.+)[,]\s*(\d+)\]/i
  1074.   IMAGE_RE = /(.+) image\[(.+)[,]\s*(\d+)\]/i
  1075.   GENDER_RE = /gender\[(male|female)\]/i
  1076.   ALT_NAME = /alt name\[(.+)\]/i
  1077.  
  1078.   def add_composite_data
  1079.     @gender_base = CP::COMPOSITE::MALE_DEFAULT
  1080.     @composite_hash = {}; @composite_init = {}; @alt_name = ""
  1081.     self.note.split(/[\r\n]+/).each do |line|
  1082.       case line
  1083.       when INITI_RE
  1084.         @composite_init[$1.to_sym] = [$2.to_s, $3.to_i]
  1085.         @composite_init["#{$1.to_s}Rear".to_sym] = [$2.to_s, $3.to_i]
  1086.         @composite_init["#{$1.to_s}Hueless".to_sym] = [$2.to_s, 0]
  1087.         @composite_init["#{$1.to_s}All".to_sym] = [$2.to_s, $3.to_i]
  1088.       when IMAGE_RE
  1089.         @composite_hash[$1.to_sym] = [$2.to_s, $3.to_i]
  1090.         @composite_hash["#{$1.to_s}Rear".to_sym] = [$2.to_s, $3.to_i]
  1091.         @composite_hash["#{$1.to_s}Hueless".to_sym] = [$2.to_s, 0]
  1092.         @composite_hash["#{$1.to_s}All".to_sym] = [$2.to_s, $3.to_i]
  1093.       when GENDER_RE
  1094.         @gender_base = true if $1.to_s.downcase == "male"
  1095.         @gender_base = false if $1.to_s.downcase == "female"
  1096.       when ALT_NAME
  1097.         @alt_name = $1.to_s
  1098.       end
  1099.     end
  1100.   end
  1101. end
  1102.  
  1103. ###--------------------------------------------------------------------------###
  1104. #  End of script.                                                              #
  1105. ###--------------------------------------------------------------------------###
RAW Paste Data