Module: Lich::Common::MapBase::InstanceMethods
- Defined in:
- documented/common/map/map_base.rb
Overview
Instance methods for Room/Map objects
Instance Method Summary collapse
-
#desc ⇒ Object
Deprecated methods for backward compatibility.
-
#dijkstra(destination = nil) ⇒ Array<Hash>?
(also: #dijkstra_hashes)
Run Dijkstra's algorithm from this room.
-
#find_all_nearest_by_tag(tag_name) ⇒ Array<Integer>
Find all rooms with a specific tag, sorted by distance.
-
#find_nearest(target_list) ⇒ Integer?
Find nearest room from a list.
-
#find_nearest_by_tag(tag_name) ⇒ Integer?
Find nearest room with a specific tag.
-
#geo ⇒ nil
Placeholder for game-specific geographic metadata.
-
#inside? ⇒ Boolean
Check if room is indoors.
-
#inspect ⇒ Object
Inspect room details.
-
#json_extra_fields ⇒ Object
Override in subclasses to add game-specific fields to JSON output.
-
#map_name ⇒ String?
Returns the map image filename for this room.
-
#map_roomsize ⇒ Integer?
Returns the width of this room's bounding box on the map image.
-
#map_x ⇒ Integer?
Returns the center X coordinate on the map image for this room.
-
#map_y ⇒ Integer?
Returns the center Y coordinate on the map image for this room.
-
#outside? ⇒ Boolean
Check if room is outdoors Works for both GemStone and DragonRealms: - "Obvious paths:" indicates outdoor - "Obvious exits:" indicates indoor.
-
#path_to(destination) ⇒ Array<Integer>?
Find path from this room to destination.
-
#tags=(value) ⇒ nil
Replace this room's tags and drop the tag index.
-
#to_i ⇒ Object
Convert room to integer (room ID).
-
#to_json(*_args) ⇒ Object
Convert room to JSON.
Instance Method Details
#desc ⇒ Object
Deprecated methods for backward compatibility
947 948 949 |
# File 'documented/common/map/map_base.rb', line 947 def desc @description end |
#dijkstra(destination = nil) ⇒ Array<Hash>? Also known as: dijkstra_hashes
Run Dijkstra's algorithm from this room.
Returns Hashes keyed by room id. These were Arrays indexed by room id until 5.20.0: the conversion allocated two Arrays sized by the highest room id reached, which dominated the cost on a sparse map and gained nothing, since every caller only ever indexes by room id. Access is unchanged - previous and distances read the same either way, and an unreached room still yields nil. #size and #length now count the rooms actually reached rather than the highest id plus one, and iteration yields pairs rather than slots.
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 |
# File 'documented/common/map/map_base.rb', line 808 def dijkstra(destination = nil) self.class.load unless self.class.loaded? source = @id visited = {} shortest_distances_hash = {} previous_hash = {} pq = MinHeap.new pq.push(0, source) shortest_distances_hash[source] = 0 check_destination = proc do |v, dist| case destination when Integer v == destination when Array destination.include?(v) && dist < 20 else false end end until pq.empty? current_dist, v = pq.pop next if visited[v] break if check_destination.call(v, current_dist) visited[v] = true # A wayto edge can name a room that is gone. Under the NilClass # patch the enumeration was simply skipped; without it the raise # would be rescued below and lose the whole search. room = self.class.list[v] next if room.nil? room.wayto.keys.each do |adj_room| adj_room_i = adj_room.to_i next if visited[adj_room_i] edge_weight = if room.timeto[adj_room].is_a?(StringProc) room.timeto[adj_room].call else room.timeto[adj_room] end next unless edge_weight new_distance = current_dist + edge_weight if !shortest_distances_hash[adj_room_i] || shortest_distances_hash[adj_room_i] > new_distance shortest_distances_hash[adj_room_i] = new_distance previous_hash[adj_room_i] = v pq.push(new_distance, adj_room_i) end end end [previous_hash, shortest_distances_hash] rescue StandardError => e echo "Map.dijkstra: error: #{e}" respond e.backtrace nil end |
#find_all_nearest_by_tag(tag_name) ⇒ Array<Integer>
Find all rooms with a specific tag, sorted by distance
921 922 923 924 925 926 927 928 |
# File 'documented/common/map/map_base.rb', line 921 def find_all_nearest_by_tag(tag_name) target_list = self.class.rooms_by_tag(tag_name) _, shortest_distances = dijkstra return [] if shortest_distances.nil? target_list.delete_if { |room_num| shortest_distances[room_num].nil? } target_list.sort { |a, b| shortest_distances[a] <=> shortest_distances[b] } end |
#find_nearest(target_list) ⇒ Integer?
Find nearest room from a list
933 934 935 936 937 938 939 940 941 942 943 944 |
# File 'documented/common/map/map_base.rb', line 933 def find_nearest(target_list) target_list = target_list.collect(&:to_i) if target_list.include?(@id) @id else _, shortest_distances = dijkstra(target_list) return nil if shortest_distances.nil? valid_rooms = target_list.select { |room_num| shortest_distances[room_num].is_a?(Numeric) } valid_rooms.min_by { |room_num| shortest_distances[room_num] } end end |
#find_nearest_by_tag(tag_name) ⇒ Integer?
Find nearest room with a specific tag
907 908 909 910 911 912 913 914 915 916 |
# File 'documented/common/map/map_base.rb', line 907 def find_nearest_by_tag(tag_name) target_list = self.class.rooms_by_tag(tag_name) return @id if target_list.include?(@id) _, shortest_distances = dijkstra(target_list) return nil if shortest_distances.nil? target_list.delete_if { |room_num| shortest_distances[room_num].nil? } target_list.sort { |a, b| shortest_distances[a] <=> shortest_distances[b] }.first end |
#geo ⇒ nil
Placeholder for game-specific geographic metadata.
998 999 1000 |
# File 'documented/common/map/map_base.rb', line 998 def geo nil end |
#inside? ⇒ Boolean
Check if room is indoors
754 755 756 |
# File 'documented/common/map/map_base.rb', line 754 def inside? !outside? end |
#inspect ⇒ Object
Inspect room details
759 760 761 762 763 |
# File 'documented/common/map/map_base.rb', line 759 def inspect instance_variables.collect do |var| "#{var}=#{instance_variable_get(var).inspect}" end.join("\n") end |
#json_extra_fields ⇒ Object
Override in subclasses to add game-specific fields to JSON output. Must return a Hash. Nil/empty values are filtered automatically.
767 768 769 |
# File 'documented/common/map/map_base.rb', line 767 def json_extra_fields {} end |
#map_name ⇒ String?
Returns the map image filename for this room.
Provided for backward compatibility. Equivalent to the @image attribute.
956 957 958 |
# File 'documented/common/map/map_base.rb', line 956 def map_name @image end |
#map_roomsize ⇒ Integer?
989 990 991 992 993 |
# File 'documented/common/map/map_base.rb', line 989 def map_roomsize return nil if @image_coords.nil? image_coords[2] - image_coords[0] end |
#map_x ⇒ Integer?
Returns the center X coordinate on the map image for this room.
Computes the midpoint of the image_coords bounding box. Provided for backward compatibility.
966 967 968 969 970 |
# File 'documented/common/map/map_base.rb', line 966 def map_x return nil if @image_coords.nil? ((image_coords[0] + image_coords[2]) / 2.0).round end |
#map_y ⇒ Integer?
Returns the center Y coordinate on the map image for this room.
Computes the midpoint of the image_coords bounding box. Provided for backward compatibility.
978 979 980 981 982 |
# File 'documented/common/map/map_base.rb', line 978 def map_y return nil if @image_coords.nil? ((image_coords[1] + image_coords[3]) / 2.0).round end |
#outside? ⇒ Boolean
Check if room is outdoors Works for both GemStone and DragonRealms:
- "Obvious paths:" indicates outdoor
- "Obvious exits:" indicates indoor
746 747 748 749 750 |
# File 'documented/common/map/map_base.rb', line 746 def outside? return false if @paths.nil? || @paths.empty? @paths.last =~ /^Obvious paths:/ ? true : false end |
#path_to(destination) ⇒ Array<Integer>?
Find path from this room to destination
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 |
# File 'documented/common/map/map_base.rb', line 879 def path_to(destination) self.class.load unless self.class.loaded? destination = destination.to_i previous, = dijkstra(destination) # dijkstra returns nil when the search itself failed. return nil if previous.nil? return nil unless previous[destination] path = [destination] seen = { destination => true } until previous[path[-1]] == @id step = previous[path[-1]] # A chain that never reaches this room is not a usable path. The # hash yields nil for a missing predecessor, and a chain that # revisits a room is a cycle; either would loop forever. Dijkstra # should not produce either, but path_to is a public entry point and # dijkstra is overridable. return nil if step.nil? || seen[step] seen[step] = true path.push(step) end path.reverse end |
#tags=(value) ⇒ nil
Replace this room's tags and drop the tag index
731 732 733 734 |
# File 'documented/common/map/map_base.rb', line 731 def (value) @tags = TagList.new(value, self.class) self.class.reset_tag_index end |
#to_i ⇒ Object
Convert room to integer (room ID)
737 738 739 |
# File 'documented/common/map/map_base.rb', line 737 def to_i @id end |
#to_json(*_args) ⇒ Object
Convert room to JSON
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
# File 'documented/common/map/map_base.rb', line 772 def to_json(*_args) mapjson = { id: @id, title: @title, description: @description, paths: @paths, location: @location, climate: @climate, terrain: @terrain, wayto: @wayto&.sort_by { |k, _v| k.to_i }&.to_h, timeto: @timeto&.sort_by { |k, _v| k.to_i }&.to_h, image: @image, image_coords: @image_coords, tags: @tags&.sort_by { |tag| [tag.downcase, tag] }, check_location: @check_location, unique_loot: @unique_loot, uid: @uid } mapjson.merge!(json_extra_fields) mapjson.delete_if { |_a, b| b.nil? || (b.is_a?(Array) && b.empty?) } JSON.pretty_generate(mapjson) end |