summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/rbot/plugins/weather.rb666
-rw-r--r--data/rbot/plugins/wow.rb123
2 files changed, 188 insertions, 601 deletions
diff --git a/data/rbot/plugins/weather.rb b/data/rbot/plugins/weather.rb
index f2c3e368..3570aa8e 100644
--- a/data/rbot/plugins/weather.rb
+++ b/data/rbot/plugins/weather.rb
@@ -1,605 +1,68 @@
-# This is nasty-ass. I hate writing parsers.
-class Metar
- attr_reader :decoded
- attr_reader :input
- attr_reader :date
- attr_reader :nodata
- def initialize(string)
- str = nil
- @nodata = false
- string.each_line {|l|
- if str == nil
- # grab first line (date)
- @date = l.chomp.strip
- str = ""
- else
- if(str == "")
- str = l.chomp.strip
- else
- str += " " + l.chomp.strip
+#
+# Weather plugin for rbot
+# by MrChucho (mrchucho@mrchucho.net)
+# Copyright (C) 2006 Ralph M. Churchill
+#
+require 'open-uri'
+require 'rexml/document'
+
+class CurrentConditions
+ def initialize(station)
+ @station = station
+ @url = "http://www.nws.noaa.gov/data/current_obs/#{@station.upcase}.xml"
+ @etag = String.new
+ @mtime = Time.mktime(0)
+ @current_conditions = String.new
+ @iscached = false
+ end
+ def update
+ begin
+ open(@url,"If-Modified-Since" => @mtime.rfc2822) do |feed|
+ # open(@url,"If-None-Match"=>@etag) do |feed|
+ @etag = feed.meta['etag']
+ @mtime = feed.last_modified
+ cc_doc = (REXML::Document.new feed).root
+ @iscached = false
+ @current_conditions = parse(cc_doc)
+ end
+ rescue OpenURI::HTTPError => e
+ case e
+ when /304/:
+ @iscached = true
+ when /404/:
+ raise "Data for #{@station} not found"
+ else
+ raise "Error retrieving data: #{e}"
+ end
end
- end
- }
- if @date && @date =~ /^(\d+)\/(\d+)\/(\d+) (\d+):(\d+)$/
- # 2002/02/26 05:00
- @date = Time.gm($1, $2, $3, $4, $5, 0)
- else
- @date = Time.now
- end
- @input = str.chomp
- @cloud_layers = 0
- @cloud_coverage = {
- 'SKC' => '0',
- 'CLR' => '0',
- 'VV' => '8/8',
- 'FEW' => '1/8 - 2/8',
- 'SCT' => '3/8 - 4/8',
- 'BKN' => '5/8 - 7/8',
- 'OVC' => '8/8'
- }
- @wind_dir_texts = [
- 'North',
- 'North/Northeast',
- 'Northeast',
- 'East/Northeast',
- 'East',
- 'East/Southeast',
- 'Southeast',
- 'South/Southeast',
- 'South',
- 'South/Southwest',
- 'Southwest',
- 'West/Southwest',
- 'West',
- 'West/Northwest',
- 'Northwest',
- 'North/Northwest',
- 'North'
- ]
- @wind_dir_texts_short = [
- 'N',
- 'N/NE',
- 'NE',
- 'E/NE',
- 'E',
- 'E/SE',
- 'SE',
- 'S/SE',
- 'S',
- 'S/SW',
- 'SW',
- 'W/SW',
- 'W',
- 'W/NW',
- 'NW',
- 'N/NW',
- 'N'
- ]
- @weather_array = {
- 'MI' => 'Mild ',
- 'PR' => 'Partial ',
- 'BC' => 'Patches ',
- 'DR' => 'Low Drifting ',
- 'BL' => 'Blowing ',
- 'SH' => 'Shower(s) ',
- 'TS' => 'Thunderstorm ',
- 'FZ' => 'Freezing',
- 'DZ' => 'Drizzle ',
- 'RA' => 'Rain ',
- 'SN' => 'Snow ',
- 'SG' => 'Snow Grains ',
- 'IC' => 'Ice Crystals ',
- 'PE' => 'Ice Pellets ',
- 'GR' => 'Hail ',
- 'GS' => 'Small Hail and/or Snow Pellets ',
- 'UP' => 'Unknown ',
- 'BR' => 'Mist ',
- 'FG' => 'Fog ',
- 'FU' => 'Smoke ',
- 'VA' => 'Volcanic Ash ',
- 'DU' => 'Widespread Dust ',
- 'SA' => 'Sand ',
- 'HZ' => 'Haze ',
- 'PY' => 'Spray',
- 'PO' => 'Well-Developed Dust/Sand Whirls ',
- 'SQ' => 'Squalls ',
- 'FC' => 'Funnel Cloud Tornado Waterspout ',
- 'SS' => 'Sandstorm/Duststorm '
- }
- @cloud_condition_array = {
- 'SKC' => 'clear',
- 'CLR' => 'clear',
- 'VV' => 'vertical visibility',
- 'FEW' => 'a few',
- 'SCT' => 'scattered',
- 'BKN' => 'broken',
- 'OVC' => 'overcast'
- }
- @strings = {
- 'mm_inches' => '%s mm (%s inches)',
- 'precip_a_trace' => 'a trace',
- 'precip_there_was' => 'There was %s of precipitation ',
- 'sky_str_format1' => 'There were %s at a height of %s meters (%s feet)',
- 'sky_str_clear' => 'The sky was clear',
- 'sky_str_format2' => ', %s at a height of %s meter (%s feet) and %s at a height of %s meters (%s feet)',
- 'sky_str_format3' => ' and %s at a height of %s meters (%s feet)',
- 'clouds' => ' clouds',
- 'clouds_cb' => ' cumulonimbus clouds',
- 'clouds_tcu' => ' towering cumulus clouds',
- 'visibility_format' => 'The visibility was %s kilometers (%s miles).',
- 'wind_str_format1' => 'blowing at a speed of %s meters per second (%s miles per hour)',
- 'wind_str_format2' => ', with gusts to %s meters per second (%s miles per hour),',
- 'wind_str_format3' => ' from the %s',
- 'wind_str_calm' => 'calm',
- 'precip_last_hour' => 'in the last hour. ',
- 'precip_last_6_hours' => 'in the last 3 to 6 hours. ',
- 'precip_last_24_hours' => 'in the last 24 hours. ',
- 'precip_snow' => 'There is %s mm (%s inches) of snow on the ground. ',
- 'temp_min_max_6_hours' => 'The maximum and minimum temperatures over the last 6 hours were %s and %s degrees Celsius (%s and %s degrees Fahrenheit).',
- 'temp_max_6_hours' => 'The maximum temperature over the last 6 hours was %s degrees Celsius (%s degrees Fahrenheit). ',
- 'temp_min_6_hours' => 'The minimum temperature over the last 6 hours was %s degrees Celsius (%s degrees Fahrenheit). ',
- 'temp_min_max_24_hours' => 'The maximum and minimum temperatures over the last 24 hours were %s and %s degrees Celsius (%s and %s degrees Fahrenheit). ',
- 'light' => 'Light ',
- 'moderate' => 'Moderate ',
- 'heavy' => 'Heavy ',
- 'mild' => 'Mild ',
- 'nearby' => 'Nearby ',
- 'current_weather' => 'Current weather is %s. ',
- 'pretty_print_metar' => '%s on %s, the wind was %s at %s. The temperature was %s degrees Celsius (%s degrees Fahrenheit), and the pressure was %s hPa (%s inHg). The relative humidity was %s%%. %s %s %s %s %s'
- }
-
- parse
- end
-
- def store_speed(value, windunit, meterspersec, knots, milesperhour)
- # Helper function to convert and store speed based on unit.
- # &$meterspersec, &$knots and &$milesperhour are passed on
- # reference
- if (windunit == 'KT')
- # The windspeed measured in knots:
- @decoded[knots] = sprintf("%.2f", value)
- # The windspeed measured in meters per second, rounded to one decimal place:
- @decoded[meterspersec] = sprintf("%.2f", value.to_f * 0.51444)
- # The windspeed measured in miles per hour, rounded to one decimal place: */
- @decoded[milesperhour] = sprintf("%.2f", value.to_f * 1.1507695060844667)
- elsif (windunit == 'MPS')
- # The windspeed measured in meters per second:
- @decoded[meterspersec] = sprintf("%.2f", value)
- # The windspeed measured in knots, rounded to one decimal place:
- @decoded[knots] = sprintf("%.2f", value.to_f / 0.51444)
- #The windspeed measured in miles per hour, rounded to one decimal place:
- @decoded[milesperhour] = sprintf("%.1f", value.to_f / 0.51444 * 1.1507695060844667)
- elsif (windunit == 'KMH')
- # The windspeed measured in kilometers per hour:
- @decoded[meterspersec] = sprintf("%.1f", value.to_f * 1000 / 3600)
- @decoded[knots] = sprintf("%.1f", value.to_f * 1000 / 3600 / 0.51444)
- # The windspeed measured in miles per hour, rounded to one decimal place:
- @decoded[milesperhour] = sprintf("%.1f", knots.to_f * 1.1507695060844667)
+ @current_conditions # +" Cached? "+ ((@iscached) ? "Y" : "N")
end
- end
-
- def parse
- @decoded = Hash.new
- puts @input
- @input.split(" ").each {|part|
- if (part == 'METAR')
- # Type of Report: METAR
- @decoded['type'] = 'METAR'
- elsif (part == 'SPECI')
- # Type of Report: SPECI
- @decoded['type'] = 'SPECI'
- elsif (part == 'AUTO')
- # Report Modifier: AUTO
- @decoded['report_mod'] = 'AUTO'
- elsif (part == 'NIL')
- @nodata = true
- elsif (part =~ /^\S{4}$/ && ! (@decoded.has_key?('station')))
- # Station Identifier
- @decoded['station'] = part
- elsif (part =~ /([0-9]{2})([0-9]{2})([0-9]{2})Z/)
- # ignore this bit, it's useless without month/year. some of these
- # things are hideously out of date.
- # now = Time.new
- # time = Time.gm(now.year, now.month, $1, $2, $3, 0)
- # Date and Time of Report
- # @decoded['time'] = time
- elsif (part == 'COR')
- # Report Modifier: COR
- @decoded['report_mod'] = 'COR'
- elsif (part =~ /([0-9]{3}|VRB)([0-9]{2,3}).*(KT|MPS|KMH)/)
- # Wind Group
- windunit = $3
- # now do ereg to get the actual values
- part =~ /([0-9]{3}|VRB)([0-9]{2,3})((G[0-9]{2,3})?#{windunit})/
- if ($1 == 'VRB')
- @decoded['wind_deg'] = 'variable directions'
- @decoded['wind_dir_text'] = 'variable directions'
- @decoded['wind_dir_text_short'] = 'VAR'
- else
- @decoded['wind_deg'] = $1
- @decoded['wind_dir_text'] = @wind_dir_texts[($1.to_i/22.5).round]
- @decoded['wind_dir_text_short'] = @wind_dir_texts_short[($1.to_i/22.5).round]
- end
- store_speed($2, windunit,
- 'wind_meters_per_second',
- 'wind_knots',
- 'wind_miles_per_hour')
-
- if ($4 != nil)
- # We have a report with information about the gust.
- # First we have the gust measured in knots
- if ($4 =~ /G([0-9]{2,3})/)
- store_speed($1,windunit,
- 'wind_gust_meters_per_second',
- 'wind_gust_knots',
- 'wind_gust_miles_per_hour')
- end
- end
- elsif (part =~ /([0-9]{3})V([0-9]{3})/)
- # Variable wind-direction
- @decoded['wind_var_beg'] = $1
- @decoded['wind_var_end'] = $2
- elsif (part == "9999")
- # A strange value. When you look at other pages you see it
- # interpreted like this (where I use > to signify 'Greater
- # than'):
- @decoded['visibility_miles'] = '>7';
- @decoded['visibility_km'] = '>11.3';
- elsif (part =~ /^([0-9]{4})$/)
- # Visibility in meters (4 digits only)
- # The visibility measured in kilometers, rounded to one decimal place.
- @decoded['visibility_km'] = sprintf("%.1f", $1.to_i / 1000)
- # The visibility measured in miles, rounded to one decimal place.
- @decoded['visibility_miles'] = sprintf("%.1f", $1.to_i / 1000 / 1.609344)
- elsif (part =~ /^[0-9]$/)
- # Temp Visibility Group, single digit followed by space
- @decoded['temp_visibility_miles'] = part
- elsif (@decoded['temp_visibility_miles'] && (@decoded['temp_visibility_miles']+' '+part) =~ /^M?(([0-9]?)[ ]?([0-9])(\/?)([0-9]*))SM$/)
- # Visibility Group
- if ($4 == '/')
- vis_miles = $2.to_i + $3.to_i/$5.to_i
- else
- vis_miles = $1.to_i;
- end
- if (@decoded['temp_visibility_miles'][0] == 'M')
- # The visibility measured in miles, prefixed with < to indicate 'Less than'
- @decoded['visibility_miles'] = '<' + sprintf("%.1f", vis_miles)
- # The visibility measured in kilometers. The value is rounded
- # to one decimal place, prefixed with < to indicate 'Less than' */
- @decoded['visibility_km'] = '<' . sprintf("%.1f", vis_miles * 1.609344)
- else
- # The visibility measured in mile.s */
- @decoded['visibility_miles'] = sprintf("%.1f", vis_miles)
- # The visibility measured in kilometers, rounded to one decimal place.
- @decoded['visibility_km'] = sprintf("%.1f", vis_miles * 1.609344)
- end
- elsif (part =~ /^(-|\+|VC|MI)?(TS|SH|FZ|BL|DR|BC|PR|RA|DZ|SN|SG|GR|GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$/)
- # Current weather-group
- @decoded['weather'] = '' unless @decoded.has_key?('weather')
- if (part[0].chr == '-')
- # A light phenomenon
- @decoded['weather'] += @strings['light']
- part = part[1,part.length]
- elsif (part[0].chr == '+')
- # A heavy phenomenon
- @decoded['weather'] += @strings['heavy']
- part = part[1,part.length]
- elsif (part[0,2] == 'VC')
- # Proximity Qualifier
- @decoded['weather'] += @strings['nearby']
- part = part[2,part.length]
- elsif (part[0,2] == 'MI')
- @decoded['weather'] += @strings['mild']
- part = part[2,part.length]
- else
- # no intensity code => moderate phenomenon
- @decoded['weather'] += @strings['moderate']
- end
-
- while (part && bite = part[0,2]) do
- # Now we take the first two letters and determine what they
- # mean. We append this to the variable so that we gradually
- # build up a phrase.
-
- @decoded['weather'] += @weather_array[bite]
- # Here we chop off the two first letters, so that we can take
- # a new bite at top of the while-loop.
- part = part[2,-1]
- end
- elsif (part =~ /(SKC|CLR)/)
- # Cloud-layer-group.
- # There can be up to three of these groups, so we store them as
- # cloud_layer1, cloud_layer2 and cloud_layer3.
-
- @cloud_layers += 1;
- # Again we have to translate the code-characters to a
- # meaningful string.
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_condition'] = @cloud_condition_array[$1]
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_coverage'] = @cloud_coverage[$1]
- elsif (part =~ /^(VV|FEW|SCT|BKN|OVC)([0-9]{3})(CB|TCU)?$/)
- # We have found (another) a cloud-layer-group. There can be up
- # to three of these groups, so we store them as cloud_layer1,
- # cloud_layer2 and cloud_layer3.
- @cloud_layers += 1;
- # Again we have to translate the code-characters to a meaningful string.
- if ($3 == 'CB')
- # cumulonimbus (CB) clouds were observed. */
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_condition'] =
- @cloud_condition_array[$1] + @strings['clouds_cb']
- elsif ($3 == 'TCU')
- # towering cumulus (TCU) clouds were observed.
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_condition'] =
- @cloud_condition_array[$1] + @strings['clouds_tcu']
- else
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_condition'] =
- @cloud_condition_array[$1] + @strings['clouds']
+ def parse(cc_doc)
+ cc = Hash.new
+ cc_doc.elements.each do |c|
+ cc[c.name.to_sym] = c.text
end
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_coverage'] = @cloud_coverage[$1]
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_altitude_ft'] = $2.to_i * 100
- @decoded['cloud_layer'+ (@cloud_layers.to_s) +'_altitude_m'] = ($2.to_f * 30.48).round
- elsif (part =~ /^T([0-9]{4})$/)
- store_temp($1,'temp_c','temp_f')
- elsif (part =~ /^T?(M?[0-9]{2})\/(M?[0-9\/]{1,2})?$/)
- # Temperature/Dew Point Group
- # The temperature and dew-point measured in Celsius.
- @decoded['temp_c'] = sprintf("%d", $1.tr('M', '-'))
- if $2 == "//" || !$2
- @decoded['dew_c'] = 0
+ "At #{cc[:observation_time_rfc822]}, the wind was #{cc[:wind_string]} at #{cc[:location]} (#{cc[:station_id]}). The temperature was #{cc[:temperature_string]}#{heat_index_or_wind_chill(cc)}, and the pressure was #{cc[:pressure_string]}. The relative humidity was #{cc[:relative_humidity]}%. Current conditions are #{cc[:weather]} with #{cc[:visibility_mi]}mi visibility."
+ end
+private
+ def heat_index_or_wind_chill(cc)
+ hi = cc[:heat_index_string]
+ wc = cc[:windchill_string]
+ if hi != 'NA' then
+ " with a heat index of #{hi}"
+ elsif wc != 'NA' then
+ " with a windchill of #{wc}"
else
- @decoded['dew_c'] = sprintf("%.1f", $2.tr('M', '-'))
+ ""
end
- # The temperature and dew-point measured in Fahrenheit, rounded to
- # the nearest degree.
- @decoded['temp_f'] = ((@decoded['temp_c'].to_f * 9 / 5) + 32).round
- @decoded['dew_f'] = ((@decoded['dew_c'].to_f * 9 / 5) + 32).round
- elsif(part =~ /A([0-9]{4})/)
- # Altimeter
- # The pressure measured in inHg
- @decoded['altimeter_inhg'] = sprintf("%.2f", $1.to_i/100)
- # The pressure measured in mmHg, hPa and atm
- @decoded['altimeter_mmhg'] = sprintf("%.1f", $1.to_f * 0.254)
- @decoded['altimeter_hpa'] = sprintf("%d", ($1.to_f * 0.33863881578947).to_i)
- @decoded['altimeter_atm'] = sprintf("%.3f", $1.to_f * 3.3421052631579e-4)
- elsif(part =~ /Q([0-9]{4})/)
- # Altimeter
- # This is strange, the specification doesnt say anything about
- # the Qxxxx-form, but it's in the METARs.
- # The pressure measured in hPa
- @decoded['altimeter_hpa'] = sprintf("%d", $1.to_i)
- # The pressure measured in mmHg, inHg and atm
- @decoded['altimeter_mmhg'] = sprintf("%.1f", $1.to_f * 0.7500616827)
- @decoded['altimeter_inhg'] = sprintf("%.2f", $1.to_f * 0.0295299875)
- @decoded['altimeter_atm'] = sprintf("%.3f", $1.to_f * 9.869232667e-4)
- elsif (part =~ /^T([0-9]{4})([0-9]{4})/)
- # Temperature/Dew Point Group, coded to tenth of degree.
- # The temperature and dew-point measured in Celsius.
- store_temp($1,'temp_c','temp_f')
- store_temp($2,'dew_c','dew_f')
- elsif (part =~ /^1([0-9]{4}$)/)
- # 6 hour maximum temperature Celsius, coded to tenth of degree
- store_temp($1,'temp_max6h_c','temp_max6h_f')
- elsif (part =~ /^2([0-9]{4}$)/)
- # 6 hour minimum temperature Celsius, coded to tenth of degree
- store_temp($1,'temp_min6h_c','temp_min6h_f')
- elsif (part =~ /^4([0-9]{4})([0-9]{4})$/)
- # 24 hour maximum and minimum temperature Celsius, coded to
- # tenth of degree
- store_temp($1,'temp_max24h_c','temp_max24h_f')
- store_temp($2,'temp_min24h_c','temp_min24h_f')
- elsif (part =~ /^P([0-9]{4})/)
- # Precipitation during last hour in hundredths of an inch
- # (store as inches)
- @decoded['precip_in'] = sprintf("%.2f", $1.to_f/100)
- @decoded['precip_mm'] = sprintf("%.2f", $1.to_f * 0.254)
- elsif (part =~ /^6([0-9]{4})/)
- # Precipitation during last 3 or 6 hours in hundredths of an
- # inch (store as inches)
- @decoded['precip_6h_in'] = sprintf("%.2f", $1.to_f/100)
- @decoded['precip_6h_mm'] = sprintf("%.2f", $1.to_f * 0.254)
- elsif (part =~ /^7([0-9]{4})/)
- # Precipitation during last 24 hours in hundredths of an inch
- # (store as inches)
- @decoded['precip_24h_in'] = sprintf("%.2f", $1.to_f/100)
- @decoded['precip_24h_mm'] = sprintf("%.2f", $1.to_f * 0.254)
- elsif(part =~ /^4\/([0-9]{3})/)
- # Snow depth in inches
- @decoded['snow_in'] = sprintf("%.2f", $1);
- @decoded['snow_mm'] = sprintf("%.2f", $1.to_f * 25.4)
- else
- # If we couldn't match the group, we assume that it was a
- # remark.
- @decoded['remarks'] = '' unless @decoded.has_key?("remarks")
- @decoded['remarks'] += ' ' + part;
- end
- }
-
- # Relative humidity
- # p @decoded['dew_c'] # 11.0
- # p @decoded['temp_c'] # 21.0
- # => 56.1
- @decoded['rel_humidity'] = sprintf("%.1f",100 *
- (6.11 * (10.0**(7.5 * @decoded['dew_c'].to_f / (237.7 + @decoded['dew_c'].to_f)))) / (6.11 * (10.0 ** (7.5 * @decoded['temp_c'].to_f / (237.7 + @decoded['temp_c'].to_f))))) if @decoded.has_key?('dew_c')
- end
-
- def store_temp(temp,temp_cname,temp_fname)
- # Given a numerical temperature temp in Celsius, coded to tenth of
- # degree, store in @decoded[temp_cname], convert to Fahrenheit
- # and store in @decoded[temp_fname]
- # Note: temp is converted to negative if temp > 100.0 (See
- # Federal Meteorological Handbook for groups T, 1, 2 and 4)
-
- # Temperature measured in Celsius, coded to tenth of degree
- temp = temp.to_f/10
- if (temp >100.0)
- # first digit = 1 means minus temperature
- temp = -(temp - 100.0)
end
- @decoded[temp_cname] = sprintf("%.1f", temp)
- # The temperature in Fahrenheit.
- @decoded[temp_fname] = sprintf("%.1f", (temp * 9 / 5) + 32)
- end
-
- def pretty_print_precip(precip_mm, precip_in)
- # Returns amount if $precip_mm > 0, otherwise "trace" (see Federal
- # Meteorological Handbook No. 1 for code groups P, 6 and 7) used in
- # several places, so standardized in one function.
- if (precip_mm.to_i > 0)
- amount = sprintf(@strings['mm_inches'], precip_mm, precip_in)
- else
- amount = @strings['a_trace']
- end
- return sprintf(@strings['precip_there_was'], amount)
- end
-
- def pretty_print
- if @nodata
- return "The weather stored for #{@decoded['station']} consists of the string 'NIL' :("
- end
-
- ["temp_c", "altimeter_hpa"].each {|key|
- if !@decoded.has_key?(key)
- return "The weather stored for #{@decoded['station']} could not be parsed (#{@input})"
- end
- }
-
- mins_old = ((Time.now - @date.to_i).to_f/60).round
- if (mins_old <= 60)
- weather_age = mins_old.to_s + " minutes ago,"
- elsif (mins_old <= 60 * 25)
- weather_age = (mins_old / 60).to_s + " hours, "
- weather_age += (mins_old % 60).to_s + " minutes ago,"
- else
- # return "The weather stored for #{@decoded['station']} is hideously out of date :( (Last update #{@date})"
- weather_age = "The weather stored for #{@decoded['station']} is hideously out of date :( here it is anyway:"
- end
-
- if(@decoded.has_key?("cloud_layer1_altitude_ft"))
- sky_str = sprintf(@strings['sky_str_format1'],
- @decoded["cloud_layer1_condition"],
- @decoded["cloud_layer1_altitude_m"],
- @decoded["cloud_layer1_altitude_ft"])
- else
- sky_str = @strings['sky_str_clear']
- end
-
- if(@decoded.has_key?("cloud_layer2_altitude_ft"))
- if(@decoded.has_key?("cloud_layer3_altitude_ft"))
- sky_str += sprintf(@strings['sky_str_format2'],
- @decoded["cloud_layer2_condition"],
- @decoded["cloud_layer2_altitude_m"],
- @decoded["cloud_layer2_altitude_ft"],
- @decoded["cloud_layer3_condition"],
- @decoded["cloud_layer3_altitude_m"],
- @decoded["cloud_layer3_altitude_ft"])
- else
- sky_str += sprintf(@strings['sky_str_format3'],
- @decoded["cloud_layer2_condition"],
- @decoded["cloud_layer2_altitude_m"],
- @decoded["cloud_layer2_altitude_ft"])
- end
- end
- sky_str += "."
-
- if(@decoded.has_key?("visibility_miles"))
- visibility = sprintf(@strings['visibility_format'],
- @decoded["visibility_km"],
- @decoded["visibility_miles"])
- else
- visibility = ""
- end
-
- if (@decoded.has_key?("wind_meters_per_second") && @decoded["wind_meters_per_second"].to_i > 0)
- wind_str = sprintf(@strings['wind_str_format1'],
- @decoded["wind_meters_per_second"],
- @decoded["wind_miles_per_hour"])
- if (@decoded.has_key?("wind_gust_meters_per_second") && @decoded["wind_gust_meters_per_second"].to_i > 0)
- wind_str += sprintf(@strings['wind_str_format2'],
- @decoded["wind_gust_meters_per_second"],
- @decoded["wind_gust_miles_per_hour"])
- end
- wind_str += sprintf(@strings['wind_str_format3'],
- @decoded["wind_dir_text"])
- else
- wind_str = @strings['wind_str_calm']
- end
-
- prec_str = ""
- if (@decoded.has_key?("precip_in"))
- prec_str += pretty_print_precip(@decoded["precip_mm"], @decoded["precip_in"]) + @strings['precip_last_hour']
- end
- if (@decoded.has_key?("precip_6h_in"))
- prec_str += pretty_print_precip(@decoded["precip_6h_mm"], @decoded["precip_6h_in"]) + @strings['precip_last_6_hours']
- end
- if (@decoded.has_key?("precip_24h_in"))
- prec_str += pretty_print_precip(@decoded["precip_24h_mm"], @decoded["precip_24h_in"]) + @strings['precip_last_24_hours']
- end
- if (@decoded.has_key?("snow_in"))
- prec_str += sprintf(@strings['precip_snow'], @decoded["snow_mm"], @decoded["snow_in"])
- end
-
- temp_str = ""
- if (@decoded.has_key?("temp_max6h_c") && @decoded.has_key?("temp_min6h_c"))
- temp_str += sprintf(@strings['temp_min_max_6_hours'],
- @decoded["temp_max6h_c"],
- @decoded["temp_min6h_c"],
- @decoded["temp_max6h_f"],
- @decoded["temp_min6h_f"])
- else
- if (@decoded.has_key?("temp_max6h_c"))
- temp_str += sprintf(@strings['temp_max_6_hours'],
- @decoded["temp_max6h_c"],
- @decoded["temp_max6h_f"])
- end
- if (@decoded.has_key?("temp_min6h_c"))
- temp_str += sprintf(@strings['temp_max_6_hours'],
- @decoded["temp_min6h_c"],
- @decoded["temp_min6h_f"])
- end
- end
- if (@decoded.has_key?("temp_max24h_c"))
- temp_str += sprintf(@strings['temp_min_max_24_hours'],
- @decoded["temp_max24h_c"],
- @decoded["temp_min24h_c"],
- @decoded["temp_max24h_f"],
- @decoded["temp_min24h_f"])
- end
-
- if (@decoded.has_key?("weather"))
- weather_str = sprintf(@strings['current_weather'], @decoded["weather"])
- else
- weather_str = ''
- end
-
- return sprintf(@strings['pretty_print_metar'],
- weather_age,
- @date,
- wind_str, @decoded["station"], @decoded["temp_c"],
- @decoded["temp_f"], @decoded["altimeter_hpa"],
- @decoded["altimeter_inhg"],
- @decoded["rel_humidity"], sky_str,
- visibility, weather_str, prec_str, temp_str).strip
- end
-
- def to_s
- @input
- end
end
-
-class WeatherPlugin < Plugin
+class MyWeatherPlugin < Plugin
def help(plugin, topic="")
- "weather <ICAO> => display the current weather at the location specified by the ICAO code [Lookup your ICAO code at http://www.nws.noaa.gov/tg/siteloc.shtml - this will also store the ICAO against your nick, so you can later just say \"weather\", weather => display the current weather at the location you last asked for"
- end
-
- def get_metar(station)
- station.upcase!
-
- result = @bot.httputil.get(URI.parse("http://weather.noaa.gov/pub/data/observations/metar/stations/#{station}.TXT"))
- return nil unless result
- return Metar.new(result)
+ "weather <STATION> => display the current conditions at the location specified by the STATION code [Lookup your STATION code at http://www.nws.noaa.gov/data/current_obs/ - this will also store the STATION against your nick, so you can later just say \"weather\", weather => display the current weather at the location you last asked for"
end
-
def initialize
super
@@ -612,20 +75,21 @@ class WeatherPlugin < Plugin
val
end
end
- @metar_cache = Hash.new
+ @cc_cache = Hash.new
end
def describe(m, where)
- if @metar_cache.has_key?(where) &&
- Time.now - @metar_cache[where].date < 3600
- met = @metar_cache[where]
+ if @cc_cache.has_key?(where) then
+ met = @cc_cache[where]
else
- met = get_metar(where)
+ met = CurrentConditions.new(where)
end
-
if met
- m.reply met.pretty_print
- @metar_cache[where] = met
+ # begin
+ m.reply met.update
+ @cc_cache[where] = met
+ # rescue
+ # end
else
m.reply "couldn't find weather data for #{where}"
end
@@ -640,10 +104,10 @@ class WeatherPlugin < Plugin
where = @registry[m.sourcenick]
describe(m,where)
else
- m.reply "I don't know where you are yet! Lookup your code at http://www.nws.noaa.gov/tg/siteloc.shtml and tell me 'weather <code>', then I'll know."
+ m.reply "I don't know where you are yet! Lookup your station at http://www.nws.noaa.gov/data/current_obs/ and tell me 'weather <station>', then I'll know."
end
end
end
end
-plugin = WeatherPlugin.new
+plugin = MyWeatherPlugin.new
plugin.map 'weather :where', :defaults => {:where => false}
diff --git a/data/rbot/plugins/wow.rb b/data/rbot/plugins/wow.rb
new file mode 100644
index 00000000..4faadaf4
--- /dev/null
+++ b/data/rbot/plugins/wow.rb
@@ -0,0 +1,123 @@
+#
+# World of Warcraft Realm Status plugin for rbot
+# by MrChucho (mrchucho@mrchucho.net)
+# Copyright (C) 2006 Ralph M. Churchill
+#
+# Requires: insatiable appetite for World of Warcraft
+#
+require 'open-uri'
+require 'rexml/document'
+
+class Realm
+ attr_accessor :name,:status,:type,:pop
+ def initialize(name,status,type,pop)
+ self.name = pretty_realm(name)
+ self.status = pretty_status(status)
+ self.type = pretty_type(type)
+ self.pop = pretty_pop(pop)
+ end
+ def Realm.get_realm_status(realm_name)
+ begin
+ open("http://www.worldofwarcraft.com/realmstatus/status.xml") do |xmldoc|
+ realm_list = (REXML::Document.new xmldoc).root
+ realm_data = realm_list.elements["r[@n=\"#{realm_name}\"]"]
+ if realm_data and realm_data.attributes.any? then
+ realm = Realm.new(
+ realm_data.attributes['n'],
+ realm_data.attributes['s'].to_i,
+ realm_data.attributes['t'].to_i,
+ realm_data.attributes['l'].to_i)
+ else
+ "Realm, #{realm_name}, not found."
+ end
+ end
+ rescue => err
+ "Error retrieving realm status: #{err}"
+ end
+ end
+ def to_s
+ "#{name} (#{type}) Status: #{status} Population: #{pop}"
+ end
+ # just a longer, tabluar format
+ # might be good if displaying multiple realms
+ def _to_s
+ sprintf("%-8s %-20s %-8s %-9s\n%-11s %-22s %-8s %-9s",
+ "Status","Realm","Type","Population",
+ status,name,type,pop)
+ end
+private
+ def pretty_status(status)
+ case status
+ when 1
+ "3Up"
+ when 2
+ "5Down"
+ end
+ end
+ def pretty_pop(pop)
+ case pop
+ when 1
+ "3Low"
+ when 2
+ "7Medium"
+ when 3
+ "4High"
+ when 4
+ "5Max(Queued)"
+ end
+ end
+ def pretty_realm(realm)
+ "#{realm}"
+ end
+ def pretty_type(type)
+ case type
+ when 0
+ 'RP-PVP'
+ when 1
+ 'Normal'
+ when 2
+ 'PVP'
+ when 3
+ 'RP'
+ end
+ end
+end
+
+class RealmPlugin < Plugin
+ USAGE="realm <realm> => determine the status of a Warcraft realm"
+ def initialize
+ super
+ class << @registry
+ def store(val)
+ val
+ end
+ def restore(val)
+ val
+ end
+ end
+ end
+ def help(plugin,topic="")
+ USAGE
+ end
+ def usage(m,params={})
+ m.reply USAGE
+ end
+ def realm(m,params)
+ if params[:realm_name] and params[:realm_name].any?
+ realm_name = params[:realm_name].collect{|tok|
+ tok.capitalize
+ }.join(' ')
+ @registry[m.sourcenick] = realm_name
+ m.reply Realm.get_realm_status(realm_name)
+ else
+ if @registry.has_key?(m.sourcenick)
+ realm_name = @registry[m.sourcenick]
+ m.reply Realm.get_realm_status(realm_name)
+ else
+ m.reply "I don't know which realm you want.\n#{USAGE}"
+ end
+ end
+ end
+end
+plugin = RealmPlugin.new
+plugin.map 'realm *realm_name', :defaults => {:realm_name => false}