module Characterizable class Characteristic attr_reader :base, :name, :trumps, :prerequisite, :display, :options def initialize(base, name, options = {}, &block) @base = base @name = name @trumps = Array.wrap options.delete(:trumps) @prerequisite = options.delete(:prerequisite) @display = options.delete(:display) @options = options Blockenspiel.invoke block, self if block_given? end def as_json(*) { :name => name, :trumps => trumps, :prerequisite => prerequisite, :options => options } end def inspect "<Characterizable::Characteristic name=#{name.inspect} trumps=#{trumps.inspect} prerequisite=#{prerequisite.inspect} options=#{options.inspect}>" end def characteristics base.characteristics end def value(universe) case universe when Hash universe[name] else universe.send name if universe.respond_to?(name) end end def display(universe) val = value(universe) @display.call(val) if @display and val end def known?(universe) not value(universe).nil? end def potential?(universe) not known?(universe) and revealed? universe and not trumped? universe end def effective?(universe, ignoring = []) known?(universe) and revealed?(universe) and not trumped?(universe, ignoring) end def trumped?(universe, ignoring = []) characteristics.each do |_, other| next if ignoring.include?(other.name) if other.can_trump? self if can_trump?(other) return mutually_trumped?(universe, other, ignoring) elsif other.effective?(universe, ignoring + [name]) return true end end end false end def can_trump?(other) trumps.include?(other.name) end def mutually_trumped?(universe, other, ignoring) # special case: mutual trumping. current characteristic is trumped if its friend is otherwise effective and it is not otherwise effective other.effective?(universe, ignoring + [name]) and not effective?(universe, ignoring + [other.name]) end def revealed?(universe) return true if prerequisite.nil? characteristics[prerequisite].effective? universe end include Blockenspiel::DSL def reveals(other_name, other_options = {}, &block) base.has other_name, other_options.merge(:prerequisite => name), &block end def displays(&block) @display = block end end end