Advertisement
KhegayIV

[RGSS3] L'James Notetag System

Sep 9th, 2015
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 34.15 KB | None | 0 0
  1. #==============================================================================
  2. #
  3. #
  4. #                      L'James Notetag System v.1.1
  5. #
  6. #
  7. #==============================================================================
  8. #                                Changelog
  9. #==============================================================================
  10. #
  11. # 23.IX.15 - v.1.0 finished
  12. # 29.IX.15 - parameters with underscore in name can parse tags with space
  13. #            hash.set_limit changed to hash_set_key_limit, add set_limit to
  14. #            value, array and hash parameters
  15. # 30.IX.15 - shared parsers bugfix
  16. # 01. X.15 - array unique bugfix. Unique is now true by default
  17. # 02. X.15 - rewrite internal scheme structure. New scheme types use
  18. #            another methods. Add block parameters
  19. # 06. X.15 - another unique bugfix
  20. # 14. I.16 - fix bug with battle test
  21. #
  22. #==============================================================================
  23. #                                Description
  24. #==============================================================================
  25. #
  26. # This scrit serves to simplify work with notetags in custom scripts.
  27. #
  28. # Features:
  29. # * Executing specifed action when note matches with regex
  30. # * Automatic receiving data from notetags
  31. #
  32. #==============================================================================
  33. #                                Introduction
  34. #==============================================================================
  35. #
  36. # Warning: very bad english. I'll correct mistakes if you show me them
  37. #
  38. # Main idea of the system - automatic notetag scanning and converting into
  39. # values, called parameters, which can be received later through get_param
  40. #
  41. # There are five types of parameters, though you can create your own
  42. #  * Values - just a single value of certain type, e.g. integer.
  43. #             Default tag is <name value>
  44. #  * Arrays - array of values. Default tag: <name val1, val2, val3>
  45. #  * Hashes - collection of key-value pairs. Default tag:
  46. #             <name key1 val1, key2 val2>
  47. #  * Traits - boolean values. Notetag presence assigns 'true' value to trait,
  48. #             absence - 'false'. Default tag: <<name>>
  49. #  * Groups - groups of parameters that will be recorded in one Hash
  50. #
  51. # In order to scan notetags, system requires to create system extension,
  52. # which is used for styling and registering parameter schemes (scanning rules)
  53. # for specific database classes. This is done through simple DSL.
  54. #
  55. # Extension looks like this
  56. #
  57. # --------------------------------------------------------------------------
  58. # LJ::NOTETAGS.extension do
  59. #
  60. #   # Extension styling
  61. #   trait_parser create_parser.add_anon_matcher("[%s]"){|x| true}
  62. #
  63. #   # Parameter schemes' registraion
  64. #
  65. #   declare_feature do
  66. #  
  67. #     register :power, hash(:percent).limit(:fire, :ice, :lightning)
  68. #
  69. #     # Registers notetags like <power fire 150%> - hash parameter.
  70. #     # After loading obj.power[:fire] == 1.5 will be true
  71. #     # Another way:
  72. #     # hash(:percent).set_limit(:fire, :ice, :lightning).register(:power)
  73. #
  74. #   end
  75. #
  76. #   declare_skill do
  77. #     register :piercing, trait
  78. #   end
  79. #
  80. #   declare(RPG::Actor, RPG::Enemy) do
  81. #     register :undead, trait
  82. #   end
  83. # end
  84. # -------------------------------------------------------------------------
  85. #
  86. # In order to get parameter value you need to use obj.get_param(:param_name)
  87. # or just obj.param_name, where obj - is a instance of database class.
  88. #
  89. # Parameters can be used in a way like RPG Maker VXA features - i.e.,
  90. # battler equipment and state parameters are applied to that battler.
  91. # To receive parameter value you need to use battler.get_feature(:feature_name)
  92. # or just battler.feature_name, where battler - is a Game_Battler instance
  93. #
  94. #==============================================================================
  95. #                                   Styling
  96. #==============================================================================
  97. #
  98. # Extension style applies to all parameters in that extension. For example,
  99. # in sample extension above traits are set to look like [name] instead of
  100. # <<name>>. Styling is done through these methods:
  101. #
  102. #  * param_parser - sets regex via parser(see below) that will be used for
  103. #                    value, hash and array parameters.
  104. #                    Default: <name value> and <name> \n value \n <name>
  105. #  * trait_parser - sets regex via parser that will be used for traits
  106. #                    Default: <<name>>
  107. #  * arg_selector - sets regex that will be used by hash and array schemes
  108. #                   for selecting arguments from notetag. Has one capture group
  109. #                   By default, argument is everything but line separators
  110. #                   and comma: arguments of <name val1, val2, val 3> are
  111. #                   "val1", "val2" and "val3"
  112. #  * hash_splitter - sets regex that will be used by hashes to divide key and
  113. #                    value in argument string. Has two capture groups, first
  114. #                    captures key, second - value.
  115. #                    By default split happens on first space: "ab cde fgh"
  116. #                    will make pair :ab => "cde fgh"
  117. #
  118. # Example: Suppose we need to parse tag <hash a aaa, b bb b, c cccc cccc>. From
  119. # "a aaa, bb bb b, c cccc cccc" selector selects arguments "a aaa", "bb bb b"
  120. # ΠΈ "c cccc cccc". Then splitter splits each argument to key and value
  121. # "a" -> "aaa", "bb" -> "bb b", "c" -> "cccc cccc". After that key-value pairs
  122. # are processed by converters and accumulators(see below), and result is hash
  123. # {:a => "aaa", :bb => "bbb", :c => "cccc cccc"}
  124. #
  125. # Parsers
  126. # Parsers are used to parse notes. Parser - is a collection of regex and code
  127. # blocks that create a value string from MatchData. You can create your parser
  128. # with create_parser, and then add regexes with next methods:
  129. #  * add_matcher(regex){matcher} adds detection of a fixed regex. Matcher takes
  130. #    MatchData as argument and returns string which will be used by converter
  131. #  * add_anon_regex(regex_str){matcher} adds detection of a regex with variable
  132. #    param name. regex_str is a string which will be converted to a regex after
  133. #    replacing symbols %s with parameter name
  134. # These methods return self, so they can be changed
  135. #
  136. # Styling example:
  137. #
  138. #  trait_parser create_parser.add_anon_matcher("[%s]"){|x| true}.
  139. #                             add_anon_matcher("\"%s\""){|x| true}
  140. #  # This parser detects traits [name] and "name"
  141. #
  142. #  hash_splitter /^([^\s]+)\s*=>\s*(.*?)&/
  143. #  Hashes will look like <power fire => 150%>
  144. #
  145. #==============================================================================
  146. #                                Registration
  147. #==============================================================================
  148. #
  149. # Parameters need to be registered in a system for specified classes.
  150. # To start class parameters declaration you need to use method
  151. #
  152. # declare(*classes) do
  153. #   # scheme registraion
  154. # end  
  155. #
  156. # *classes - is a list of classes where notetags will be searched. Classes
  157. #  need to have mehod .note in order to work
  158. #
  159. # Also database classes have special methods: declare_actor, declare_class,
  160. # declare_item etc. Methods declare_usableitem, declare_equipitem and
  161. # declare_baseitem register schemes in several classes.
  162. # declare_features allows to register parameter that will behave similar to
  163. # RPG Maker VXA features - e.g. hero parameters depend on his equipment
  164. #
  165. # Scheme registration is done like this
  166. #   register name, scheme
  167. # or
  168. #   scheme.register(name)
  169. #
  170. # If name has underscore symbol, it will be interpreted as both underscore
  171. # and space
  172. #
  173. # Scheme - is a rule for notetag parsing. To create scheme you need to call
  174. # methods value(), array(), hash() or trait(), and then customize scheme.
  175. # value, array and hash methods can be called with parameter template -
  176. # like value(:int) - to get partially customized scheme
  177. #
  178. # Also you can create your parameter type. In order to do this you need
  179. # to inherit class LJ::NOTETAGS::SchemeBase or LJ::NOTETAGS::ParamScheme
  180. #  * In SchemeBase you need to override methods:
  181. #    ** load(note) which takes note and returns parameter value.
  182. #    ** accumulate(a,b) takes two values of your parameter and returns
  183. #       new value - "product" of that vaues.
  184. #  * ParamScheme in constructor takes loader (self can be passed in
  185. #    declaration), parser and default value, which will be returned in absence
  186. #    of a notetag. You need to override methods:
  187. #    ** construct(str) - takes string result of parser and constructs object
  188. #       from that string
  189. #    ** accumulate(a,b) - ...
  190. #
  191. # Also, besides schemes, you can register regex and action that will be
  192. # exexuted when regex is detected. This is done with
  193. # register_regex(regex){action} method. Action takes MatchData and current
  194. # object
  195. #
  196. #==============================================================================
  197. #                           Scheme customization
  198. #==============================================================================
  199. #
  200. # Converter - a function that takes string and returns parameter value
  201. #
  202. # Accumulator - a function that takes current parameter value and new parameter
  203. # value and returns chhanged parameter value. Accumulator is used in cases when
  204. # there're multiple notetags for that parameter in one object
  205. #
  206. # To customize standard type parameters use following methods, different for
  207. # each scheme type. Methods return self and can be chained
  208. #
  209. # Value:
  210. # * set_converter - sets converter. Default leaves value as string
  211. # * set_accumulator - sets accumulator. Default replaces current value with new
  212. # * set_method_accumulator - sets accumulator {|acc, val| acc.m(val)} where m -
  213. #    is a method name that is passed as argument
  214. # * set_default - sets value, that will be saved in absence of notetag in note
  215. # * set_startval - sets value that accumulator will use as current in first
  216. #    value assignment. E.g. integer parameter with startval=1 and default = 0
  217. #    will always add 1 to value, but return zero when no tags is found. When nil
  218. #    startval is used (default startval value), first notetag just saves value
  219. #    without accumulation
  220. # * set_limit - set list of values which will be accepted. When nil
  221. #    (default) limit is removed
  222. #
  223. # Example
  224. #   value.set_default(0).set_converter{|x| x.to_i}.set_method_accumulator(:+)
  225. #   # summed integer parameter. Equivalent to value(:int)
  226. #
  227. # Array:
  228. # * set_converter - sets converter for array elements. Default leaves value as
  229. #    string
  230. # * set_unique - when true, repeating values won't be saved. Default is true
  231. # * set_limit - set list of values which will be accepted. When nil
  232. #    (default) limit is removed
  233. #
  234. # Example
  235. #   array.set_converter{|x| x.to_sym}.set_unique
  236. #   # array with unique symbol values
  237. #
  238. # Hash:
  239. # * set_key_converter - set converter for keys. By default keys convert to
  240. #     symbols
  241. # * set_key_limit - set list of values which will be accepted as key. When nil
  242. #     (default) limit is removed
  243. # * Value, returned by hash[key] behaves like value parameter, returned by
  244. #    get_param, and is customized by the same methods
  245. #    ** set_converter
  246. #    ** set_accumulator
  247. #    ** set_method_accumulator
  248. #    ** set_default
  249. #    ** set_startval
  250. #    ** set_limit
  251. #
  252. # Example
  253. #   hash.set_key_limit(:fire :ice, :lightning).set_val_default(1).
  254. #   set_val_converter{|x| x.chomp("%").to_i/100.0}.
  255. #   set_val_method_accumulator(:*)
  256. #   # sets parameter with keys "ice", "fire", "lightning" and works like
  257. #   # hash(:percent)
  258. #
  259. # Traits cannot be customized
  260. #
  261. # Groups:
  262. #  Groups are different in that they are defined with special syntax:
  263. #
  264. #    register :name, group do
  265. #      #register group parameters
  266. #    end
  267. #  or
  268. #    register :name, group.declare{ #register group parameters }
  269. #  or
  270. #    group.declare{ #register group parameters }.register(:name)
  271. #
  272. #  Before do or declare you can use extension styling methods to change
  273. #  style in group. These methods can be chained
  274. #
  275. # Example:
  276. #    register :gr, group.hash_splitter(/^([^\s]+)\s*=>\s*(.*?)&/) do
  277. #      register :a1, value(:int)
  278. #      register :a2, value(:int)
  279. #    end
  280. #
  281. # With this scheme notetag <gr><a1 10><a2 20></gr> will be saved as
  282. # :gr => {:a1 => 10, :a2 => 20}
  283. #
  284. #  Warning: do not use same names inside and outside of group. System has no
  285. #  way to distinguish between them. Also be careful with styling
  286. #  
  287. #==============================================================================
  288. #                              Parameter templates
  289. #==============================================================================
  290. #
  291. # Value, array and hash parameters can be created using templates to get
  292. # pre-customized scheme with ready converters, accumulators (for hashes and
  293. # value parameters) and defaults.
  294. #
  295. # To create templated parameters you need to specify it after constructor,
  296. # like hash(:int)
  297. #
  298. # * :int - integer values. Default value is 0, converter does to_i, accumulator
  299. #     sums values
  300. # * :str - string values. Default is "", accumulator concatenates strings but
  301. #     divides with space
  302. # * :sym - symbol values. Default is nil, accumulator replaces old with new
  303. # * :percent - converter chops "%" if exist, makes to_i and divides by 100.0
  304. #     "150%" becomes 1,5. Default is 1, accumulator multiplies values
  305. # * :pluspercent - converter's the same as :percent, but accumulator sums
  306. #     percents instead of multiplying. Two +50% tags will make 2.0, not 2.25 or
  307. #     0.25
  308. #
  309. #==============================================================================
  310. #                                Terms of use
  311. #==============================================================================
  312. #
  313. # You can use L'JNT in commercial and non-commercial projects as long as you
  314. # give credit to L'James. Custom scripts that use this system, can have wtheir
  315. # own terms.
  316. #
  317. #==============================================================================
  318. #                    Some black magic. Better don't touch
  319. #==============================================================================
  320.  
  321. module LJ
  322.   module NOTETAGS
  323.     @exts = []
  324.    
  325.     def self.extension(&block)
  326.       @exts << Extension.new(block)
  327.     end
  328.    
  329.     def self.get_exts
  330.       @exts
  331.     end
  332.    
  333.        
  334.     class Extension      
  335.       def initialize(reg_block)
  336.         @blocks = {}
  337.         instance_eval(&reg_block)
  338.       end
  339.      
  340.       def get_trait_parser
  341.         @trait_parser ||= Parser.new.add_anon_matcher("<<%s>>"){|x| true}
  342.      end
  343.      
  344.      def get_param_parser
  345.        @param_parser ||= Parser.new.add_anon_matcher("<%s\\s+(.+?)>"){|x| x[0]}.
  346.          add_anon_matcher("<(%s)>\\n?(.+?)\\n?<\/\\1>", Regexp::MULTILINE){|x| x[1]}
  347.      end
  348.      
  349.      def get_arg_selector
  350.        @arr_sel ||= /\s*?([^\n\r,]+)\s*?/
  351.      end
  352.      
  353.      def get_hash_splitter
  354.        @splitter ||= /^([^\s]+)\s+(.+?)$/
  355.      end
  356.      
  357.      def get_blocks
  358.        @blocks
  359.      end
  360.      
  361.      def create_parser
  362.        Parser.new
  363.      end
  364.      
  365.      def trait_parser(parser)
  366.        @trait_parser = parser
  367.      end
  368.      
  369.      def param_parser(parser)
  370.        @param_parser = parser
  371.      end
  372.      
  373.      def arg_selector(selector)
  374.        @arg_sel = selector
  375.      end
  376.      
  377.      def hash_splitter(splitter)
  378.        @splitter = splitter
  379.      end
  380.      
  381.      def declare(*classes, &block)
  382.        classes.each do
  383.          |klass|
  384.          Manager.add_class(klass)
  385.          @blocks[klass] ||= []
  386.          @blocks[klass] << block
  387.        end
  388.      end
  389.  
  390.      
  391.      def declare_baseitem(&block)
  392.        declare(RPG::Actor, RPG::Class, RPG::Skill, RPG::Item,
  393.          RPG::Weapon, RPG::Armor, RPG::Enemy, RPG::State, &block)
  394.        #data_groups($data_actors, $data_classes, $data_skills, $data_items
  395.        #  $data_weapons, $data_armors, $data_states, $data_enemies)
  396.      end
  397.      
  398.      def declare_features(&block)
  399.        declare(RPG::Actor, RPG::Class,
  400.          RPG::Weapon, RPG::Armor, RPG::Enemy, RPG::State, &block)
  401.        #data_groups($data_actors, $data_classes
  402.        #  $data_weapons, $data_armors, $data_states, $data_enemies)
  403.      end
  404.      
  405.      def declare_actor(&block)
  406.        declare(RPG::Actor, &block)
  407.        #data_groups($data_actors)
  408.      end
  409.      
  410.      
  411.      def declare_class(&block)
  412.        declare(RPG::Class, &block)
  413.        #data_groups($data_classes)
  414.      end
  415.      
  416.      
  417.      def declare_usableitem(&block)
  418.        declare(RPG::Item, RPG::Skill, &block)
  419.        #data_groups($data_items, $data_skills)
  420.      end
  421.      
  422.      
  423.      def declare_skill(&block)
  424.        declare(RPG::Skill, &block)
  425.        #data_groups($data_skills)
  426.      end
  427.      
  428.      
  429.      def declare_item(&block)
  430.        declare(RPG::Item, &block)
  431.        #data_groups($data_items)
  432.      end
  433.      
  434.      
  435.      def declare_equipitem(&block)
  436.        declare(RPG::Weapon, RPG::Armor, &block)
  437.        #data_groups($data_weapons, $data_armors)
  438.      end
  439.      
  440.      
  441.      def declare_weapon(&block)
  442.        declare(RPG::Weapon, &block)
  443.        #data_groups($data_weapons)
  444.      end
  445.      
  446.      
  447.      def declare_armor(&block)
  448.        declare(RPG::Armor, &block)
  449.        #data_groups($data_armors)
  450.      end
  451.      
  452.      
  453.      def declare_enemy(&block)
  454.        declare(RPG::Enemy, &block)
  455.        #data_groups($data_enemies)
  456.      end
  457.      
  458.      
  459.      def declare_state(&block)
  460.        declare(RPG::State, &block)
  461.        #data_groups($data_states)
  462.      end
  463.    end #Extension
  464.    
  465.    #-------------------------------------------------------------------
  466.    
  467.    class Parser
  468.      attr_accessor :matchers
  469.      attr_accessor :anon_matchers
  470.      
  471.      def initialize
  472.        @matchers = {}
  473.        @anon_matchers = {}
  474.      end
  475.      
  476.      def add_matcher(regex, &matcher)
  477.        @matchers[regex] = matcher
  478.        self
  479.      end
  480.      
  481.      def add_anon_matcher(str, rules = 0, &matcher)
  482.        @anon_matchers[str] = [rules, matcher]
  483.        self
  484.      end
  485.      
  486.      def deanon(name)
  487.        name = name.to_s
  488.        @anon_matchers.each{|key, val|
  489.          add_matcher(Parser.make_regex(key, name, val[0]), &val[1])
  490.        }
  491.        if name.tr!('_', ' ')
  492.          @anon_matchers.each{|key, val|
  493.            add_matcher(Parser.make_regex(key, name, val[0]), &val[1])
  494.          }
  495.        end
  496.        @anon_matchers.clear
  497.      end      
  498.      
  499.      def load(note)
  500.        @matchers.collect{ |regex, matcher|
  501.          note.scan(regex).collect{|x| matcher.call(x)}
  502.        }.flatten
  503.      end
  504.      
  505.      def self.make_regex(str, name, options = 0)
  506.        Regexp.compile(sprintf(str, name), options)
  507.      end
  508.      
  509.      def copy
  510.        parser = Parser.new
  511.        parser.matchers = @matchers.clone
  512.        parser.anon_matchers = @anon_matchers.clone
  513.        parser
  514.      end
  515.    end
  516.    
  517.    #===================================================================#
  518.    
  519.    Identical = Proc.new{|x| x}
  520.    
  521.    class SchemeBase
  522.      def load(note)
  523.      end
  524.      
  525.      def construct(a, b)
  526.      end
  527.    end
  528.    
  529.    class ParamScheme < SchemeBase
  530.      
  531.      attr_reader :parser
  532.      attr_accessor :default
  533.      attr_accessor :startval
  534.      
  535.      def construct(acc, value)
  536.        
  537.      end
  538.      
  539.      def initialize(parser, loader, default = nil, startval = nil)
  540.        @parser = parser
  541.        @loader = loader
  542.        @default = default
  543.        @startval = startval
  544.      end
  545.      
  546.      def load(note)
  547.        values = @parser.load(note).collect{|x| construct(x)}.compact
  548.        return @default if values.empty?
  549.        if @startval != nil
  550.          values.inject(@startval){|acc, val| accumulate(acc, val) }
  551.        else
  552.          values.inject{|acc, val| accumulate(acc, val) }
  553.        end
  554.      end
  555.          
  556.      def register(name)
  557.        @loader.register(name, self)
  558.      end
  559.      
  560.    end
  561.    
  562.    #---------------------------------------------------------------
  563.    
  564.    class ValueParam < ParamScheme
  565.      
  566.      def initialize(parser, loader)
  567.        super(parser, loader)
  568.        @converter = Identical
  569.        @accumulator = Proc.new{|acc, x| x}
  570.        @shared_acc = nil
  571.        @limit = nil
  572.      end
  573.      
  574.      def set_default(dfl)
  575.        self.default = dfl
  576.        self
  577.      end
  578.      
  579.      def set_startval(st)
  580.        self.startval = st
  581.        self
  582.      end
  583.      
  584.      def set_limit(*limit)
  585.        if limit.first == nil
  586.          @limit = nil
  587.        else
  588.          @limit = limit
  589.        end
  590.        self
  591.      end
  592.      
  593.      def set_converter(&converter)
  594.        @converter = converter
  595.        self
  596.      end
  597.      
  598.      def set_accumulator(&acc)
  599.        @accumulator = acc
  600.        self
  601.      end
  602.      
  603.      def set_method_accumulator(m)
  604.        set_accumulator{
  605.          |acc, val|
  606.          acc.method(m).call(val)
  607.        }
  608.      end
  609.        
  610.      def construct(value)
  611.        value = @converter.call(value)
  612.        if (@limit == nil || @limit.include?(value))
  613.          value
  614.        else
  615.          nil
  616.        end
  617.      end
  618.      
  619.      def accumulate(a,b)
  620.        @accumulator.call(a, b)
  621.      end
  622.      
  623.    end
  624.    
  625.    #------------------------------------------------------------------
  626.    
  627.    class ArrayParam < ParamScheme
  628.      
  629.      
  630.      def initialize(parser, loader, selector)
  631.        super(parser, loader, [])
  632.        self.startval = self.default
  633.        @selector = selector
  634.        @converter = Proc.new{|x| x}
  635.        @unique = true
  636.        @limit = nil
  637.      end
  638.      
  639.      def set_converter(&converter)
  640.        @converter = converter
  641.        self
  642.      end
  643.      
  644.      def set_unique(unique)
  645.        @unique = unique
  646.        self
  647.      end
  648.      
  649.      def set_limit(*limit)
  650.        if limit.first == nil
  651.          @limit = nil
  652.        else
  653.          @limit = limit
  654.        end
  655.        self
  656.      end
  657.      
  658.      def construct(val)
  659.        res = val.scan(@selector).collect do
  660.          |x|
  661.          value = @converter.call(x[0].strip)
  662.          if (@limit == nil || @limit.include?(value))
  663.            value
  664.          else
  665.            nil
  666.          end
  667.        end.compact        
  668.        res.uniq! if @unique
  669.        res
  670.      end
  671.      
  672.      def accumulate(a,b)
  673.        if (@unique) then
  674.          a | b
  675.        else
  676.          a + b
  677.        end
  678.      end
  679.      
  680.    end
  681.    
  682.    #---------------------------------------------------------------
  683.    class HashParam < ParamScheme
  684.      def initialize(parser, loader, selector, splitter)
  685.        super(parser, loader, {})
  686.        self.startval = self.default
  687.        @kconv = Proc.new{|v| v.to_sym}
  688.        @vconv = Identical
  689.        @selector = selector
  690.        @splitter = splitter
  691.        @vacc = Proc.new{|acc, v| v}
  692.        @vdefault = nil
  693.        @limit = nil
  694.        @klimit = nil
  695.        @vstartval = nil
  696.      end
  697.      
  698.      
  699.      def set_key_limit(*limit)
  700.        if limit.first == nil
  701.          @klimit = nil
  702.        else
  703.          @klimit = limit
  704.        end
  705.        self
  706.      end
  707.      
  708.      
  709.      def set_key_converter(&converter)
  710.        @kconv = converter
  711.        self
  712.      end
  713.      
  714.      def set_default(default)
  715.        @vdefault = default
  716.        self.default.default = default  #WTH
  717.        self
  718.      end
  719.      
  720.      def set_startval(startval)
  721.        @vstartval = startval
  722.        self
  723.      end
  724.      
  725.      def set_limit(*limit)
  726.        if limit.first == nil
  727.          @limit = nil
  728.        else
  729.          @limit = limit
  730.        end
  731.        self
  732.      end
  733.      
  734.      def set_converter(&converter)
  735.        @vconv = converter
  736.        self
  737.      end
  738.      
  739.      def set_accumulator(&acc)
  740.        @vacc = acc
  741.        self
  742.      end
  743.      
  744.      def set_method_accumulator(m)
  745.        set_accumulator{
  746.          |acc, val|
  747.          acc.method(m).call(val)
  748.        }
  749.      end
  750.      
  751.      def construct(rawval)
  752.        acc = {}
  753.        rawval.scan(@selector).each{ |l|
  754.          m = l[0].strip.match(@splitter)
  755.          if m
  756.            key = @kconv.call(m[1])
  757.            val = @vconv.call(m[2])
  758.            if (@klimit==nil || @klimit.include?(key)) &&
  759.              (@limit == nil || @limit.include?(val))
  760.              unless acc.has_key? key || @vstartval != nil
  761.                acc[key] = val
  762.              else
  763.                acc[key] = @vacc.call(acc.has_key?(key) ? acc[key] : @vstartval,
  764.                val)
  765.              end
  766.            end
  767.          end
  768.        }
  769.        acc
  770.      end
  771.      
  772.      def accumulate(a,b)
  773.        a = a.clone
  774.        b.each do
  775.          |key, value|  
  776.          if a.has_key?(key)
  777.            a[key] = @vacc.call(a[key], value)
  778.          else
  779.            a[key] = value
  780.          end
  781.        end
  782.        a
  783.      end
  784.    end
  785.    
  786.    # --------------------------------------------------------------------
  787.    class Trait < ParamScheme
  788.      def initialize(parser, loader)
  789.        super(parser, loader, false)
  790.      end
  791.      
  792.      def construct(val)
  793.        val ? true : false
  794.      end
  795.      
  796.      def accumulate(a,b)
  797.        a || b
  798.      end
  799.      
  800.    end
  801.    
  802.    # --------------------------------------------------------------------
  803.    
  804.    class GroupSchemeBase
  805.      
  806.      attr_reader :parser
  807.      def initialize(parser, loader)
  808.        @parser = parser
  809.        @loader = loader
  810.        @ext = Extension.new(Proc.new{})
  811.      end
  812.      
  813.      def set_trait_parser(p)
  814.        @ext.trait_parser(p)
  815.        self
  816.      end
  817.      
  818.      def set_param_parser(p)
  819.        @ext.param_parser(p)
  820.        self
  821.      end
  822.      
  823.      def set_arg_selector(p)
  824.        @ext.arg_selector(p)
  825.        self
  826.      end
  827.      
  828.      def set_hash_splitter(p)
  829.        @ext.hash_splitter(p)
  830.        self
  831.      end
  832.      
  833.      def declare(&block)
  834.        GroupParam.new(@parser, @loader, @ext, block)
  835.      end
  836.    end
  837.    
  838.    class GroupParam < SchemeBase
  839.      attr_reader :parser
  840.      def initialize(parser, loader, ext, block)
  841.        @parser = parser
  842.        @loader = loader
  843.        @group_loader = Loader.new(ext, block)
  844.      end
  845.      
  846.      def load(note)
  847.        @parser.load(note).inject({}) do
  848.          |acc, val|
  849.          accumulate(acc, @group_loader.load_params(val, {}))
  850.        end
  851.      end
  852.      
  853.      def accumulate(a, b)
  854.        a = a.clone
  855.        shac = @group_loader.shared_accs
  856.        b.each do
  857.          |key, value|  
  858.          if a.has_key?(key)
  859.            a[key] = shac[key].call(a[key], value)
  860.          else
  861.            a[key] = value
  862.          end
  863.        end
  864.        a
  865.      end
  866.      
  867.      def register(name)
  868.        @loader.register(name, self)
  869.      end
  870.    end
  871.    
  872.    #====================================================================#
  873.    
  874.    class Loader
  875.      attr_reader :shared_accs
  876.      def initialize(ext, reg_block)
  877.        @ext = ext
  878.        @actions = {}
  879.        @params = {}
  880.        #ext.method(m).call(self)
  881.        instance_eval &reg_block
  882.        @shared_accs = {}
  883.        @params.each do
  884.          |key, value|
  885.          @shared_accs[key] = value.method(:accumulate)
  886.        end
  887.      end
  888.      
  889.      def register_regex(regex, &action)
  890.        @actions[regex] = action
  891.        
  892.      end
  893.      
  894.      def register(name, scheme, &block)
  895.        scheme.parser.deanon(name) if scheme.respond_to?(:parser)
  896.        if block_given? && scheme.respond_to?(:declare)
  897.          @params[name] = scheme.declare(&block)
  898.        else
  899.          @params[name] = scheme
  900.        end
  901.      end
  902.      
  903.      def value(type = nil)
  904.        res = ValueParam.new(@ext.get_param_parser.copy, self)
  905.        case type
  906.        when :int
  907.          res.set_converter{|x| x.to_i}.set_method_accumulator(:+).
  908.            set_default(0).set_startval(0)
  909.        when :str
  910.          res.set_accumulator{|acc, val| "#{acc} #{val}"}.set_default("")
  911.         when :sym
  912.           res.set_converter{|x| x.to_sym}
  913.         when :percent
  914.           res.set_converter{|x| x.chomp("%").to_i/100.0}.
  915.             set_method_accumulator(:*).set_default(1).set_startval(1)
  916.         when :pluspercent
  917.           res.set_converter{|x| 1+x.chomp("%").to_i/100.0}.
  918.             set_accumulator{|acc, val| acc+val - 1}.set_default(1).
  919.             set_startval(1)
  920.         end
  921.         res  
  922.       end
  923.      
  924.       def array(type = nil)
  925.         res = ArrayParam.new(@ext.get_param_parser.copy, self,
  926.           @ext.get_arg_selector)
  927.         case type
  928.         when :int
  929.           res.set_converter{|x| x.to_i}
  930.         when :str
  931.         when :sym
  932.           res.set_converter{|x| x.to_sym}
  933.         when :percent
  934.           res.set_converter{|x| x.chomp("%").to_i/100.0}
  935.         when :pluspercent
  936.           res.set_converter{|x| 1+x.chomp("%").to_i/100.0}
  937.         end
  938.         res
  939.       end
  940.      
  941.       def hash(type = nil)
  942.         res = HashParam.new(@ext.get_param_parser.copy, self,
  943.           @ext.get_arg_selector, @ext.get_hash_splitter)
  944.         case type
  945.         when :int
  946.           res.set_converter{|x| x.to_i}.set_method_accumulator(:+).
  947.             set_default(0).set_startval(0)
  948.         when :str
  949.           res.set_accumulator{|acc, val| "#{acc} #{val}"}.set_default("")
  950.         when :sym
  951.           res.set_converter{|x| x.to_sym}
  952.         when :percent
  953.           res.set_converter{|x| x.chomp("%").to_i/100.0}.
  954.             set_method_accumulator(:*).set_default(1).set_startval(1)
  955.         when :pluspercent
  956.           res.set_converter{|x| 1+x.chomp("%").to_i/100.0}.
  957.             set_accumulator{|acc, val| acc+val - 1}.set_default(1).
  958.             set_startval(1)
  959.         end
  960.         res
  961.       end
  962.      
  963.       def trait
  964.         Trait.new(@ext.get_trait_parser.copy, self)
  965.       end
  966.      
  967.       def group(&bl)
  968.         res = GroupSchemeBase.new(@ext.get_param_parser.copy, self)
  969.         res = res.declare(&bl) if block_given?
  970.         res          
  971.       end
  972.      
  973.       def empty?
  974.         @actions.empty? && @params.empty?
  975.       end
  976.      
  977.       def load(obj, holder = {})
  978.         note = obj.note
  979.         @actions.each{|regex, action| note.scan(regex){|m| action.call(m, obj)}}
  980.         load_params(note, holder)
  981.       end
  982.      
  983.       def load_params(note, holder)
  984.         @params.each do
  985.           |name, param|
  986.           val = param.load(note)
  987.           holder[name] = val unless val == nil            
  988.         end
  989.         holder
  990.       end
  991.      
  992.      
  993.      
  994.     end #Loader
  995.    
  996.    
  997.     #===============================================================
  998.    
  999.     class Manager
  1000.       @@instances = []
  1001.       @classes = []
  1002.       def initialize(klass)
  1003.         @@instances << self
  1004.         @note_class = klass
  1005.         @loaders = []
  1006.         @shared_accs = {}
  1007.       end
  1008.      
  1009.       module NoteClass
  1010.         def create_ljnt_manager
  1011.           @manager = Manager.new(self)
  1012.         end
  1013.        
  1014.         def note_manager
  1015.           @manager
  1016.         end
  1017.        
  1018.         def load_ljnt(obj)
  1019.           note_manager.load(obj)
  1020.         end
  1021.        
  1022.         def accumulate_param(name, *values)
  1023.           note_manager.accumulate_param(name, values)
  1024.         end
  1025.        
  1026.         def accumulate_param_obj(name, *objs)
  1027.           note_manager.accumulate_param(name,
  1028.             objs.compact.collect{|obj| obj.get_param(name)}.compact)
  1029.         end
  1030.        
  1031.       end
  1032.      
  1033.       module NoteClassInstance
  1034.        
  1035.         def load_ljnt
  1036.           @ljntholder = self.class.load_ljnt(self)
  1037.         end
  1038.        
  1039.         def get_param(name)
  1040.           @ljntholder[name]
  1041.         end
  1042.        
  1043.         def method_missing(method, *opts)
  1044.           m = method.to_sym
  1045.           res = get_param(m)
  1046.           return res unless res == nil
  1047.           super
  1048.         end
  1049.       end
  1050.      
  1051.       def self.add_class(note_class)
  1052.        
  1053.         unless @classes.include? note_class
  1054.           note_class.extend(NoteClass)
  1055.           note_class.send(:include, NoteClassInstance)
  1056.           note_class.create_ljnt_manager
  1057.           @classes << note_class
  1058.         end
  1059.       end
  1060.      
  1061.       def self.classes
  1062.         @classes
  1063.       end
  1064.      
  1065.       def self.register_parsers
  1066.         @@instances.each{|x| x.prepare}
  1067.       end
  1068.      
  1069.       def prepare
  1070.        
  1071.         LJ::NOTETAGS.get_exts.each do
  1072.           |ext|
  1073.           ext.get_blocks.select{|key, val| key == @note_class}.each do
  1074.             |key, blocks|
  1075.             blocks.each do
  1076.               |block|
  1077.               loader = Loader.new(ext, block)
  1078.               @loaders << loader
  1079.               loader.shared_accs.each do
  1080.                 |key, val|
  1081.                 @shared_accs[key] = val
  1082.               end
  1083.             end
  1084.           end
  1085.         end
  1086.       end
  1087.      
  1088.       def load(obj)
  1089.         @loaders.inject({}){|holder, loader| loader.load(obj, holder)}
  1090.       end
  1091.      
  1092.       def accumulate_param(name, values)
  1093.         acc = @shared_accs[name]
  1094.         if acc
  1095.           values.inject(&acc)
  1096.         else
  1097.           values.last
  1098.         end
  1099.        
  1100.       end
  1101.        
  1102.     end # MANAGER
  1103.    
  1104.   end #NOTETAGS
  1105. end #LJ
  1106.  
  1107.  
  1108. module DataManager
  1109.  
  1110.   class <<self; alias init_ljnt init; end
  1111.   def self.init
  1112.     if $BTEST
  1113.       $BTEST = false
  1114.       init_ljnt
  1115.       load_ljnotetags
  1116.       $BTEST = true
  1117.       setup_battle_test
  1118.     else
  1119.       init_ljnt
  1120.       load_ljnotetags
  1121.     end
  1122.   end
  1123.  
  1124.   def self.load_ljnotetags
  1125.     LJ::NOTETAGS::Manager.register_parsers
  1126.     LJ::NOTETAGS::Manager.classes.each do
  1127.       |x|
  1128.       ObjectSpace.each_object x do
  1129.         |obj|
  1130.         obj.load_ljnt unless obj.nil?
  1131.       end      
  1132.     end
  1133.   end
  1134.  
  1135. end
  1136.  
  1137. class Game_Battler < Game_BattlerBase
  1138.  
  1139.   def get_feature(name)
  1140.   end
  1141.  
  1142.  
  1143.   def method_missing(method, *opts)
  1144.     m = method.to_sym
  1145.     res = get_feature(m)
  1146.     return res unless res == nil
  1147.     super
  1148.   end
  1149. end
  1150.  
  1151. class Game_Actor < Game_Battler
  1152.  
  1153.   def get_feature(name)
  1154.     RPG::Actor.accumulate_param_obj(name,
  1155.     self.class,
  1156.     actor,
  1157.     *equips,
  1158.     *states
  1159.     )
  1160.   end
  1161.  
  1162. end
  1163.  
  1164. class Game_Enemy < Game_Battler
  1165.   def get_feature(name)
  1166.     RPG::Enemy.accumulate_param_obj(name,
  1167.     enemy,
  1168.     *states
  1169.     )
  1170.   end
  1171. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement