# filters for transforming an argument to something else. class Filter include Singleton def filt_to_itype str found = query_parse(str, $item_types, false, {:name=>:to_s, :id=>:__id__}) if found.empty? return nil end return found.collect{|t| item_attribute(t) } end def filt_to_area str, namespace=nil found = Tag.find_any_obj str if !found return nil end return found[0] end def filt_to_int str, namespace=nil return Integer(str) rescue nil end def filt_to_tag str, namespace=nil s = str.derive_tag.revert_tag # hack to make sure we don't allow name spaces. It's not preserved over the conversion. return [s, namespace] end def filt_to_flag str, key s = str.multi_args # into each word return nil if s[0] == nil || key.include?(s[0].downcase.to_sym) == false [s[0].downcase.to_sym, s[1]] # return a valid flag and an optional value to set it to. end def filt_to_exit old s = old.split if s[0] == nil || s[0].downcase.exit_code_to_i == nil return nil end [s[0].downcase.exit_code_to_i, s[1]] end def filt_none old return old end def filt_to_sect old if Sector.lookup(old) # returns nil on a fail Sector.lookup(old).symbol else nil end end end EditorFilters = Filter.instance ### Attached to any class that can be edited automatically with the variable "editor_interface" class Editor attr :lookup @@editor_list = {} ### stored across all editors in existance. Elegant way to have something to check input against. def initialize name, p, p_on_exit, c @lookup = p @on_exit = p_on_exit @@editor_list[name] = self @editor_name = name ### the editors name, such as redit @editor_commands = [EditorCommand.new("show", nil, :arg_none, :filt_none, proc{|ed, ch| ch.text_to_player("#{ed.display_values ch.editing}") },nil,nil, self), EditorCommand.new("commands", nil, :arg_none, :filt_none, proc{|ed, ch| ch.text_to_player("#{ed.commands_list_get}" + ENDL)}, nil,nil, self), EditorCommand.new("done", nil, :arg_none, :filt_none, proc{|ed, ch| ch.text_to_player("Leaving editor."+ENDL);e = ch.editing.shift; @on_exit.call(e) if @on_exit}, nil,nil, self)] end def add_command command_arg @editor_commands << command_arg end def self.list @@editor_list end # return a string to display the current values in the object being edited. def display_values objs obj = objs[0] a = @editor_commands.collect do |c| s = nil if c.function != nil s = "#R[#{mxptag('send "&text;" prompt')}#W#{c.name}#{mxptag('/send')}#R]:" + ' '*(20 - c.name.length - 3) if c.pword_hidden s << " #W*****" else case c.type when :flags then s << "#W#{obj.instance_variable_get("@#{c.name}").display_flags(c.key, c.name, 20)}" when :namespace then s << "#W#{obj.namespace}" else s << " #W#{obj.instance_variable_get("@#{c.name}")}" end end end s end z = @editor_commands.select {|com| com.proc_display != nil}.collect { |c| c.call_display nil, obj } if !z.empty? a << "#R==========================================================================" a += z end str = '#R__________________________________________________________________________' + ENDL if obj.is_a?(String) str<<("#R_%s_" % "#{@editor_name}: #{obj[0..30]}[...]").ljust(74, '_') + ENDL else str<<("#R_%s_" % "#{@editor_name}: #{obj}".strip_mxp!.upcase).ljust(74, '_') + ENDL end a.compact! str += a.join(ENDL) + ENDL str +="#R==========================================================================" + ENDL str +="#R[#{mxp('send')}#Wdone#{mxp('/send')}#R]#n" + ENDL end def commands_list_get @editor_commands.collect { |c| c.name } end ### selects all commands that match arg even partially. def find_command arg @editor_commands.select {|c| c.name==arg} end end # a single command in the editor_commands tables per Editor created. class EditorCommand attr :name, :function, :arg_type, :proc_fun, :proc_display, :key, :type, :pword_hidden def initialize name, function, arg_type, filter, p, d,key, editor, hidden = false, type=:set, pword_hidden=false @key = key # for passing optional filter arguments. For example, the correct table for the :filter_flag filter. @name = name @function = function @arg_type = arg_type @filter = filter @hidden = hidden @proc_fun = p @proc_display = d @editor = editor @type = type @pword_hidden = pword_hidden end def to_str "EditorCommand: #{name}" end # use this commands overall filter to return the correct type. def filter arg, player=nil if @type == :vtag return EditorFilters.send(@filter, arg, nil) end if @key != nil EditorFilters.send(@filter, arg, @key) else EditorFilters.send(@filter, arg) end end def call_display ch, obj if @proc_display @proc_display.call obj end end def call_fun ch, obj, arg if @proc_fun != nil @proc_fun.call @editor, ch, obj, arg else ch.text_to_player "Value set." + ENDL obj.send(@function, arg) end end end ### filters class String ### take a string and return a filtered string. Should really take no modifications. def str_to_str self end end $editor_lookup_procs = {} # map of editor to procs for looking up values. # this is initialized when you construct the editor. $loadable_classes = {} #meta programming to define our editor functions and accessors. class Class # defines that this class can be created with the create command. def define_creatable log :debug, "Creatable class: #{self.to_s.downcase}=>#{self}" $editable_classes[self.to_s.downcase] = self # all classes that may be edited. end # defines that this class can be loaded with the load command. def define_loadable log :debug, "Loadable class: #{self.to_s.downcase}=>#{self}" $loadable_classes[self.to_s.downcase] = self end def define_editor sym=:none, h={} p = h[:lookup] p_on_exit = h[:on_exit] class_variable_set("@@class_editor", Editor.new(sym.to_s, p, p_on_exit, self)) define_method("class_editor") do self.class.class_variable_get(:@@class_editor) end if p ### adds the editor name to the class. For example "redit" $editor_lookup_procs[sym] = p ### add command to global command table for wizards. # $tabWizCmd << Command.new(sym.to_s, [[:arg_none], [:arg_int!]]) # Player.send(:define_method, "cmd_#{sym}") do |tab_entry, arg| # begin # found = $editor_lookup_procs[sym].call(arg, self) # call the proc defined to lookup values. # rescue Exception=>e # log_exception e # text_to_player "Failed on lookup." # end # return if found == nil # a = instance_variable_get(:@editing) || [] # a << found # instance_variable_set(:@editing,a) # text_to_player "Success!! You're currently editing #{@editing[0]}." + ENDL # execute_command("show") # end end end def define_editor_field(*accessors) accessors.each do |each_hash| a_symbol = each_hash[:name] # The name of the variable arg_type = each_hash[:arg_type] || :arg_str # Type of argument that is expected to be supplied. filter = each_hash[:filter] # filter to use p = each_hash[:proc_fun] # if this isn't nil we should use it instead of defining a method. d = each_hash[:display] key = each_hash[:filter_key] type = each_hash[:type] || :set hidden_value = each_hash[:hidden] || false temp = class_variable_get(:@@class_editor); e = temp if p temp.add_command EditorCommand.new(a_symbol, nil, arg_type, filter, p, d, key, e, false, type, hidden_value) else temp.add_command EditorCommand.new(a_symbol, "edit_#{a_symbol}".to_sym, arg_type, filter, p, d, key, e, false, type, hidden_value) case type when :vtag define_method("edit_#{a_symbol}".to_sym) do |val| #we expect val to be a tag. I.e. a single word # possibly: a.simple.tag if val[1] == nil send(:assign_tag, val[0], instance_variable_get('@namespace')) # object must mix-in virtual tags else send(:assign_tag, val[0], val[1]) end true end when :flags define_method("edit_#{a_symbol}".to_sym) do |val| # we expect val to be an array with a flag and an optional value. # If the value is nil we toggle the flag. If the value is not nil we set the flag to that value. temp = instance_variable_get("@#{a_symbol}") if val[1] == nil if temp == nil temp = {} temp.toggle(val[0]) instance_variable_set("@#{a_symbol}", temp) else temp.toggle val[0] end else temp[val[0]] = val[1] true end # true returned if flag is set. false if flag is off. end when :namespace define_method("edit_#{a_symbol}".to_sym) do |val| # We can assume the data is already correct coming in. reassociate_tag(val) # true end when :set # room.edit_name "Name of a Room" define_method("edit_#{a_symbol}".to_sym) do |val| # We can assume the data is already correct coming in. instance_variable_set("@#{a_symbol}", val) true end end end end end end