Module: Lich::DragonRealms::DRParser
- Defined in:
- documented/dragonrealms/drinfomon/drparser.rb
Overview
Parser for DragonRealms server output. Processes game lines and updates global game state objects (DRStats, DRRoom, DRSkill, DRSpells, etc.).
Handles event flag registration, game shutdown announcements, experience modifier tracking, and ability/spell parsing for all character types (mages, barbarians, thieves).
Defined Under Namespace
Modules: Pattern Classes: InventoryItemSax
Constant Summary collapse
- @@parsing_exp_mods_output =
Class variables for parsing state (must be @@ not @ for module-level state)
false- @@parsing_inventory_get =
false- @@shutdown_at =
Wall-clock time the game is expected to go down for maintenance, set from a shutdown announcement. nil when no shutdown is pending.
nil
Class Method Summary collapse
-
.check_events(server_string) ⇒ String
Checks server output against registered Flag matchers.
-
.check_exp_mods(server_string) ⇒ String
Parses 'exp mods' output and updates DRSkill.exp_modifiers.
-
.check_game_shutdown(line) ⇒ void
Detects scheduled maintenance shutdown notices and records the target time, so any script can read DRParser.shutting_down? and DRParser.shutdown_minutes to wind down cleanly before the disconnect.
-
.check_known_barbarian_abilities(server_string) ⇒ String
Parses 'ability' command output for Barbarians.
-
.check_known_spells(server_string) ⇒ String
Parses 'spells' command output for magic users.
-
.check_known_thief_khri(server_string) ⇒ String
Parses 'ability' command output for Thieves.
-
.parse(line) ⇒ void
Main parser entry point.
-
.populate_inventory_get(server_string) ⇒ String
Parses inventory search output and populates GameObj inventory.
-
.shutdown_minutes ⇒ Integer?
Minutes remaining until the announced shutdown, counted down in real time (never negative).
-
.shutting_down? ⇒ Boolean
True once a maintenance shutdown has been announced.
Class Method Details
.check_events(server_string) ⇒ String
Checks server output against registered Flag matchers. Updates Flags.flags hash when a pattern matches.
102 103 104 105 106 107 108 109 110 111 112 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 102 def self.check_events(server_string) Flags.matchers.each do |key, regexes| regexes.each do |regex| if (matches = server_string.match(regex)) Flags.flags[key] = matches break end end end server_string end |
.check_exp_mods(server_string) ⇒ String
Parses 'exp mods' output and updates DRSkill.exp_modifiers. Called for each line when @@parsing_exp_mods_output is true.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 276 def self.check_exp_mods(server_string) # This method parses the output from `exp mods` command # and updates the DRSkill.exp_modifiers hash with the skill and value. # This is primarily used by the `skill-recorder` script. # # Example output without any modifiers: # The following skills are currently under the influence of a modifier: # <output class="mono"/> # None # <output class=""/> # # Example output with modifiers (XML format): # The following skills are currently under the influence of a modifier: # <output class="mono"/> # <preset id="speech">+75 Athletics</preset> # <preset id="thought">--10 Evasion</preset> # <output class=""/> # # Zero or more skills may be listed between the <output> tags # but exactly one skill and its skill modifier are listed per line. # Positive modifiers use <preset id="speech"> with single + sign. # Negative modifiers use <preset id="thought"> with double -- sign. # case server_string when Pattern::OutputClassEmpty if @@parsing_exp_mods_output @@parsing_exp_mods_output = false end else if @@parsing_exp_mods_output # Sample lines: # <preset id="speech">+79 Attunement</preset> (positive, single +) # <preset id="thought">--10 Evasion</preset> (negative, double --) if (match = server_string.strip.match(Pattern::ExpModLine)) skill = match[:skill].strip sign = match[:sign] value = match[:value].to_i value = -value if sign == '--' DRSkill.update_mods(skill, value) end end end server_string end |
.check_game_shutdown(line) ⇒ void
This method returns an undefined value.
Detects scheduled maintenance shutdown notices and records the target time, so any script can read DRParser.shutting_down? and DRParser.shutdown_minutes to wind down cleanly before the disconnect. Recomputing the target on every announcement keeps the estimate accurate as the warnings count down; a nil count (a final notice with no number) means shutdown is now.
122 123 124 125 126 127 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 122 def self.check_game_shutdown(line) return unless (match = line.match(Pattern::GameShutdown)) minutes = match[:minutes]&.to_i @@shutdown_at = minutes ? Time.now + (minutes * 60) : Time.now end |
.check_known_barbarian_abilities(server_string) ⇒ String
Parses 'ability' command output for Barbarians. Populates DRSpells.known_spells (abilities) and DRSpells.known_feats (masteries).
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 428 def self.(server_string) # This method parses the output from `ability` command for Barbarians # and populates the known spells/feats based on the known abilities/masteries. # # The XML stream for DragonRealms is whack at best. # # Examples of the data we're looking for: # You know the Berserks:<pushBold/> Avalanche, Drought. # <popBold/>You know the Forms:<pushBold/> Monkey. # <popBold/>You know the Roars:<pushBold/> Anger the Earth. # <popBold/>You know the Meditations:<pushBold/> Flame, Power, Contemplation. # <popBold/>You know the Masteries:<pushBold/> Juggernaut, Duelist. # <popBold/> # You recall that you have 0 training sessions remaining with the Guild. case server_string when Pattern::BarbarianAbility if DRSpells. server_string .sub(Pattern::BarbarianAbility, '') .sub('.', '') .split(',') .map(&:strip) .reject { |ability| ability.nil? || ability.empty? } .each { |ability| DRSpells.known_spells[ability] = true } end when Pattern::BarbarianMastery # Barbarian masteries are the equivalent of magical feats. if DRSpells. server_string .sub(Pattern::BarbarianMastery, '') .sub('.', '') .split(',') .map(&:strip) .reject { |mastery| mastery.nil? || mastery.empty? } .each { |mastery| DRSpells.known_feats[mastery] = true } end when Pattern::BarbarianTrainingRemaining DRSpells. = false end server_string end |
.check_known_spells(server_string) ⇒ String
Parses 'spells' command output for magic users. Populates DRSpells.known_spells and DRSpells.known_feats. Handles both column-formatted and non-column output formats.
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 326 def self.check_known_spells(server_string) # This method parses the output from `spells` command for magic users # and populates the known spells/feats based on the output. # # As of June 2022, There are two different output formats: column-formatted and non-column. # https://elanthipedia.play.net/Post:Tuesday_Tidings_-_120_-_Spells_-_06/07/2022_-_18:34 # # The XML stream for DragonRealms is whack at best. # # Examples of non-column output: # You recall the spells you have learned from your training. # In the chapter entitled "Analogous Patterns", you have notes on the Manifest Force [maf] and Gauge Flow [gaf] spells. # You have temporarily memorized the Tailwind [tw] spell. # You recall proficiency with the magic feats of Sorcerous Patterns, Alternate Preparation and Augmentation Mastery. # You are NOT currently set to recognize known spells when prepared by someone else in the area. (Use SPELL RECOGNIZE ON to change this.) # You are currently set to display full cast messaging. (Use SPELL BRIEFMSG ON to change this.) # You are currently attempting to hide your spell preparing. (Use PREPARE /HIDE to change this.) # You can use SPELL STANCE [HELP] to view or modify your spellcasting preferences. # # Examples of column-formatted output: # You recall the spells you have learned from your training. # <output class="mono"/> # <pushBold/> # Analogous Patterns: # <popBold/> maf Manifest Force Slot(s): 1 Min Prep: 1 Max Prep: 100 # gaf Gauge Flow Slot(s): 2 Min Prep: 5 Max Prep: 100 # <pushBold/> # Synthetic Creation: # <popBold/> acs Acid Splash Slot(s): 1 Min Prep: 1 Max Prep: 50 # vs Viscous Solution Slot(s): 2 Min Prep: 10 Max Prep: 66 # <output class=""/> # <output class="mono"/> # <pushBold/> # Temporarily Memorized: # <popBold/> tw Tailwind Slot(s): 1 Min Prep: 5 Max Prep: 100 # <output class=""/> # You recall proficiency with the magic feats of Sorcerous Patterns, Alternate Preparation and Augmentation Mastery. # You are NOT currently set to recognize known spells when prepared by someone else in the area. (Use SPELL RECOGNIZE ON to change this.) # You are currently set to display full cast messaging. (Use SPELL BRIEFMSG ON to change this.) # You are currently attempting to hide your spell preparing. (Use PREPARE /HIDE to change this.) # You can use SPELL STANCE [HELP] to view or modify your spellcasting preferences. # # One or more spells may be listed between a <popBold/> <pushBold/> pair, # but only one spell and its information are ever listed per line. case server_string when Pattern::OutputClassMono # Matched an xml tag while parsing spells, must be column-formatted output if DRSpells.grabbing_known_spells DRSpells.spellbook_format = 'column-formatted' end when Pattern::SpellbookName # Matched the spellbook name in column-formatted output, ignore when Pattern::SpellSlotInfo # Matched the spell info in column-formatted output, parse if DRSpells.grabbing_known_spells && DRSpells.spellbook_format == 'column-formatted' spell = server_string .sub(Pattern::PopBoldTag, '') # remove xml tag at start of some lines .slice(10, 32) # grab the spell name, after the alias and before Slots .strip DRSpells.known_spells[spell] = true unless spell.empty? end # Preserve the pop bold command we removed from start of spell line # otherwise lots of game text suddenly are highlighted yellow when Pattern::SpellChapterStart if DRSpells.grabbing_known_spells server_string .sub(Pattern::ChapterEntitled, '') .sub(Pattern::TemporarilyMemorized, '') .sub(Pattern::ApprenticeshipPractice, '') .sub(Pattern::SpellSuffix, '') .sub(Pattern::CommaAnd, ',') .split(',') .map { |mapped_spell| mapped_spell.include?('[') ? mapped_spell.slice(0, mapped_spell.index('[')) : mapped_spell } .map(&:strip) .reject { |rejected_spell| rejected_spell.nil? || rejected_spell.empty? } .each { |each_spell| DRSpells.known_spells[each_spell] = true } end when Pattern::SpellFeatsStart if DRSpells.grabbing_known_spells # The feats are listed without the Oxford comma separating the last item. # This makes splitting the string by comma difficult because the next to last and last # items would be captured together. The workaround is we'll replace ' and ' with a comma # and hope no feats ever have the word 'and' in them... server_string .sub(Pattern::SpellFeatsStart, '') .sub(Pattern::CommaAnd, ',') .sub('.', '') .split(',') .map(&:strip) .reject { |feat| feat.nil? || feat.empty? } .each { |feat| DRSpells.known_feats[feat] = true } end when Pattern::SpellsEnd DRSpells.grabbing_known_spells = false end server_string end |
.check_known_thief_khri(server_string) ⇒ String
Parses 'ability' command output for Thieves. Populates DRSpells.known_spells with known khri abilities.
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 474 def self.check_known_thief_khri(server_string) # This method parses the output from `ability` command for Thieves # and populates the known spells/feats based on the known khri. # # The XML stream for DragonRealms is whack at best. # # Examples of the data we're looking for: # From the Subtlety tree, you know the following khri: Darken (Aug), Dampen (Util/Ward), Strike (Aug), Silence (Util), Shadowstep (Util), Harrier (Aug) # From the Finesse tree, you know the following khri: Hasten (Util), Safe (Aug), Avoidance (Aug), Plunder (Aug), Flight (Aug/Ward), Elusion (Aug), Slight (Util) # From the Potence tree, you know the following khri: Focus (Aug), Prowess (Debil), Sight (Aug), Calm (Util), Steady (Aug), Eliminate (Debil), Serenity (Ward), Sagacity (Ward), Terrify (Debil) # You have 7 available slots. case server_string when Pattern::ThiefKhriTree if DRSpells.grabbing_known_khri server_string .sub(Pattern::ThiefKhriTree, '') .sub('.', '') .gsub(Pattern::KhriType, '') .split(',') .map(&:strip) .reject { |ability| ability.nil? || ability.empty? } .each { |ability| DRSpells.known_spells[ability] = true } end when Pattern::ThiefAvailableSlots DRSpells.grabbing_known_khri = false end server_string end |
.parse(line) ⇒ void
This method returns an undefined value.
Main parser entry point. Processes a line of server output and updates various game state objects (DRStats, DRRoom, DRSkill, etc.).
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 507 def self.parse(line) check_events(line) begin check_game_shutdown(line) if Pattern::InventoryGetStart.match?(line) GameObj.clear_inv GameObj.clear_all_containers @@parsing_inventory_get = true elsif (match = line.match(Pattern::GenderAgeCircle)) DRStats.gender = match[:gender] DRStats.age = match[:age].to_i DRStats.circle = match[:circle].to_i elsif (match = line.match(Pattern::NameRaceGuild)) DRStats.race = match[:race] DRStats.guild = match[:guild] elsif (match = line.match(Pattern::EncumbranceValue)) DRStats.encumbrance = match[:encumbrance] elsif (match = line.match(Pattern::LuckValue)) DRStats.luck = match[:luck].to_i elsif Pattern::StatValue.match?(line) line.scan(Pattern::StatValue) do |stat, value| DRStats.send("#{stat.downcase}=", value.to_i) end elsif (match = line.match(Pattern::TDPValue)) DRStats.tdps = match[:tdp].to_i elsif (match = line.match(Pattern::BalanceValue)) DRStats.balance = DR_BALANCE_VALUES.index(match[:balance]) if (position_match = line.match(Pattern::PositionValue)) DRStats.position = DR_POSITION_VALUES[position_match[:position]] end elsif Pattern::RoomPlayersEmpty.match?(line) DRRoom.pcs = [] elsif (match = line.match(Pattern::RoomPlayers)) players = match[:players]&.dup || '' DRRoom.pcs = find_pcs(players) DRRoom.pcs_prone = find_pcs_prone(players) DRRoom.pcs_sitting = find_pcs_sitting(players) elsif (match = line.match(Pattern::RoomObjs)) objs = match[:objs]&.dup || '' DRRoom.npcs = find_npcs(objs) UserVars.npcs = DRRoom.npcs DRRoom.dead_npcs = find_dead_npcs(objs) DRRoom.room_objs = find_objects(objs) elsif Pattern::RoomObjsEmpty.match?(line) DRRoom.npcs = [] DRRoom.dead_npcs = [] DRRoom.room_objs = [] elsif Pattern::GroupMembersEmpty.match?(line) DRRoom.group_members = [] elsif (match = line.match(Pattern::GroupMembers)) DRRoom.group_members << match[:member] elsif (match = line.match(Pattern::BriefExpOn)) || (match = line.match(Pattern::BriefExpOff)) skill = match[:skill] rank = match[:rank].to_i rate_raw = match[:rate] rate = rate_raw.to_i > 0 ? rate_raw : DR_LEARNING_RATES.index(rate_raw) percent = match[:percent] DRSkill.update(skill, rank, rate, percent) # Inline display of cumulative gained experience (from DRExpMonitor) if DRExpMonitor.inline_display? if rate_raw.to_i > 0 # BRIEFEXP ON format (rate is numeric) line.replace(DRExpMonitor.format_briefexp_on(line, skill)) else # BRIEFEXP OFF format (rate is word like "learning", "pondering") line.replace(DRExpMonitor.format_briefexp_off(line, skill, rate_raw.strip)) end end elsif (match = line.match(Pattern::ExpClearMindstate)) skill = match[:skill] DRSkill.clear_mind(skill) elsif Pattern::ExpColumns.match?(line) line.scan(Pattern::ExpColumns) do |skill_value, rank_value, percent_value, rate_as_word| rate_as_number = DR_LEARNING_RATES.index(rate_as_word) # convert word to number DRSkill.update(skill_value, rank_value, rate_as_number, percent_value) end elsif Pattern::ExpModsStart.match?(line) @@parsing_exp_mods_output = true DRSkill.exp_modifiers.clear elsif (match = line.match(Pattern::SpellBookFormat)) # Parse `toggle spellbook` command DRSpells.spellbook_format = match[:format] elsif Pattern::KnownSpellsStart.match?(line) DRSpells.grabbing_known_spells = true DRSpells.known_spells.clear DRSpells.known_feats.clear DRSpells.spellbook_format = 'non-column' # assume original format elsif Pattern::BarbarianAbilitiesStart.match?(line) DRSpells. = true DRSpells.known_spells.clear DRSpells.known_feats.clear elsif Pattern::ThiefKhriStart.match?(line) DRSpells.grabbing_known_khri = true DRSpells.known_spells.clear DRSpells.known_feats.clear elsif (match = line.match(Pattern::PlayedAccount)) if Lich::Common::Account.name.nil? Lich::Common::Account.name = match[:account].upcase end elsif (match = line.match(Pattern::PlayedSubscription)) if Lich::Common::Account.subscription.nil? Lich::Common::Account.subscription = match[:subscription].gsub('Basic', 'Normal').gsub('F2P', 'Free').gsub('Platinum', 'Premium').upcase end UserVars.account_type = match[:subscription].gsub('Basic', 'Normal').gsub('F2P', 'Free').upcase if Lich::Common::Account.subscription == 'PREMIUM' || XMLData.game == 'DRX' || XMLData.game == 'DRF' UserVars.premium = true else UserVars.premium = false end elsif (match = line.match(Pattern::LastLogoff)) month = Date::ABBR_MONTHNAMES.find_index(match[:month]) weekdays = [nil, 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] weekday_index = weekdays.find_index(match[:weekday]) # Guard: only process if weekday is recognized if weekday_index dst_check = match[:day].to_i - weekday_index if month.between?(4, 10) || (month == 3 && dst_check >= 7) || (month == 11 && dst_check < 0) tz = '-0400' else tz = '-0500' end $last_logoff = Time.new(match[:year].to_i, month, match[:day].to_i, match[:hour].to_i, match[:minute].to_i, match[:second].to_i, tz).getlocal end elsif (match = line.match(Pattern::Rested_EXP)) DRSkill.update_rested_exp(match[:stored].strip, match[:usable].strip, match[:refresh].strip) elsif Pattern::Rested_EXP_F2P.match?(line) # f2p characters without brain boost don't get rested exp DRSkill.update_rested_exp('none', 'none', 'none') elsif (match = line.match(Pattern::TDPValue_XPWindow)) DRStats.tdps = match[:tdp].to_i elsif (match = line.match(Pattern::FavorValue_XPWindow)) DRStats.favors = match[:favor].to_i end populate_inventory_get(line) if @@parsing_inventory_get check_exp_mods(line) if @@parsing_exp_mods_output (line) if DRSpells. check_known_thief_khri(line) if DRSpells.grabbing_known_khri check_known_spells(line) if DRSpells.grabbing_known_spells # Parse bank transactions passively Lich::DragonRealms::DRBanking.parse(line) rescue StandardError => e Lich::Messaging.msg("bold", "DRParser: error in parse: #{e.}") Lich::Messaging.msg("bold", "DRParser: line: #{line}") Lich.log "error: DRParser.parse: #{e.}\n\t#{e.backtrace.join("\n\t")}" Lich.log "error: line: #{line}\n\t" end end |
.populate_inventory_get(server_string) ⇒ String
Parses inventory search output and populates GameObj inventory. Called for each line when @@parsing_inventory_get is true.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 212 def self.populate_inventory_get(server_string) case server_string when Pattern::OutputClassEmpty if @@parsing_inventory_get @@parsing_inventory_get = false end else # This block parses a single line from the output of the `inv search <string>` verb, # which lists items on your character. Each line is an XML-like string. # Example: <d cmd='get #12345'>a small pouch</d> if @@parsing_inventory_get && (stripped = server_string.strip).start_with?('<d cmd=') # Pull the cmd attribute and item name out of the line's leading <d> element # with a SAX handler. The element is captured as it streams in, before any # trailing prose (e.g. "... is in your right hand.") -- which is not valid XML # and would break a tree parse -- is reached. handler = InventoryItemSax.new # convert_special: false matches Game.process_xml_data: Ox never turns a # numeric entity into UTF-8. Ox leaves the standard entities literal, so # XmlEntities.decode restores them in the item name below. Ox.sax_parse(handler, stripped, convert_special: false, symbolize: false, skip: :skip_none) return server_string unless handler.cmd # Normalize the item name by removing leading articles ('a', 'an', 'some'). item_name = Lich::Common::XmlEntities.decode(handler.name.to_s).sub(/^(?:a|an|some)\s/, '').strip # Extract the command and the unique item ID from the 'cmd' attribute. cmd = handler.cmd.to_s.downcase.strip id_match = /get (?<itemID>#\d+)(?: in (?<container1>#\d+|[^']+))?(?: in (?<container2>#\d+|[^']+))?/.match(cmd) # <!-- Regex to capture item and container IDs: cmd='get (?<itemID>#\d+)(?: in (?<container1>#\d+|[^']+))?(?: in (?<container2>#\d+|[^']+))?' --> # <d cmd='get #8286821 in #8286816 in #8286762'>A papyrus parchment</d> is in a black winter cloak crafted from thick cashmere, which is in a scuffed traveler's pack. # <d cmd='get #8735861 in #8735860 in watery portal'>Some arzumodine cloth</d> is in a lumpy canvas sack, which is in an effervescent eddy of honey-hued light captured by a sungold frame. # <d cmd='get #8761784'>A seagull feather quill with dyed snowy white barbs</d> is lying at your feet. # <d cmd='get #8761784'>A seagull feather quill with dyed snowy white barbs</d> is in your right hand. if id_match id = id_match[:itemID].strip.delete('#').to_s noun = nil # This isn't exposed in the DR XML stream name = item_name container1 = id_match[:container1].strip.delete('#') if id_match[:container1] container2 = id_match[:container2].strip.delete('#') if id_match[:container2] container = container1 || nil before = cmd after = nil # Store the parsed item information. # DRItems.update_item(item, id, cmd, full_description) Lich.log("DRParser: Adding inventory item - ID: #{id}, Noun: #{noun}, Name: #{name}, Container: #{container}, Before: #{before}, After: #{after}") GameObj.new_inv(id, noun, name, container, before, after) if container2 before = cmd.sub(/get \#\d+ in/, "get") name = nil # We don't know the name of the item in container2 GameObj.new_inv(container1, noun, name, container2, before, after) end end end end server_string end |
.shutdown_minutes ⇒ Integer?
Minutes remaining until the announced shutdown, counted down in real time (never negative). nil when no shutdown is pending.
137 138 139 140 141 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 137 def self.shutdown_minutes return nil unless @@shutdown_at [(@@shutdown_at - Time.now) / 60.0, 0].max.ceil end |
.shutting_down? ⇒ Boolean
Returns true once a maintenance shutdown has been announced.
130 131 132 |
# File 'documented/dragonrealms/drinfomon/drparser.rb', line 130 def self.shutting_down? !@@shutdown_at.nil? end |