) { chomp; $completed{$_}++; } close(QUESTS);
my %found_completed; # completed quest IDs found on Alla (for later comparison).
# all our starting init crap. yawn.
my $browser = LWP::UserAgent->new;
my %headers = ('User-Agent' => 'Mozilla/5.0 Gecko/2008090512 Firefox/3.0.2');
my $root_url = 'http://wow.allakhazam.com';
my $quests_url = 'http://wow.allakhazam.com/db/questlist.html';
my $side_filter = '?side=' . ($options{'side'} eq 'Alliance' ? 1 : 2);
# we use allakhazam's master listing of quests because it'll actually be
# cheaper, bandwidth-wise, then hitting each individual zone + "next" pages.
my %quests; # master list of all quests sorted by category. this'll be fun.
my $quests_per_page = 75; # number of quests per single page on the site.
my $current_page = 0; # current page that we're viewing; starts at 0.
my $last_page = 999; # discovered through a regex; last page available.
# grab all quests until the last page.
while ($current_page <= $last_page) {
my $current_url = $quests_url . $side_filter . '&start=' . ($current_page * $quests_per_page);
my $current_data = $browser->get($current_url, %headers); # ^^ OMG, MORBUS WROTE SOME MATH!
until ($current_data->is_success) { # keep trying until success.
print STDERR "Download failed. Retrying current page in 30 seconds.\n";
sleep(30); $current_data = $browser->get($current_url, %headers);
}
# we only do this once so it won't fail on the last page (which doesn't match the regex).
($last_page) = ($last_page != 999) ? $last_page : $current_data->content =~ m!">(\d{2,})!;
if ($current_page =~ /0/) { print STDERR "Downloading quest data (page $current_page of $last_page)...\n"; }
my @te_headers = ["Quest","Level","Side","Start","Reward","Category","Tags"];
my %te_config = (keep_html => 1, strip_html_on_match => 0); # bah.
my $te = HTML::TableExtract->new(headers=>@te_headers, %te_config);
$te->parse($current_data->content);
foreach my $ts ($te->table_states) {
foreach my $r ($ts->rows) {
my ($category_url) = $r->[5] =~ m!.*?!;
$r->[5] =~ s/<(.*?)>//g; my $category_name = $r->[5];
$category_url = $category_url ? $category_url : '';
if (!$quests{$category_name}) { # create this new category...
$quests{$category_name} = { 'name' => $category_name, 'url' => $category_url };
} # which we'll deliciously fill with quests. MmmM. yumMMmy quests.
($r->[7]) = $r->[0] =~ m!{'name'} cmp $quests{$b}->{'name'} } keys %quests) {
print "\n\n";
print " | ID | Name | Starts in | ".
"Level | Start NPC | Side |
\n";
foreach my $quest (sort { $a->[7] cmp $b->[7] } @{$quests{$category}{'quests'}}) {
my $s = ''; # will contain an asterisk for "we did it!"
my ($id) = $quest->[0] =~ m!wquest=(\d+)!; next unless $id;
$quest->[0] =~ s/"> <\/a>/">???<\/a>/; # no Name, but link?
$quest->[0] =~ s/(\/db.*)/$root_url$1/g; # make a full URL.
$quest->[0] =~ s/
//gi; # no images please. ty.
$quest->[2] = $quest->[2] ? $quest->[2] : '???'; # no Side?
$quest->[3] = $quest->[3] ? $quest->[3] : '???'; # no NPC?
if ($category eq 'Seasonal' && $quest->[2] eq '???' && $quest->[3] eq '???') {
next; # there are a kazillion bum quests in the Seasonal database. ignore 'em.
}
$total_category++; # we can do this quest, so count it, eh?
if ($completed{$id}) { $completed_category++; $s = '*'; }
if ($completed{$id}) { $found_completed{$id}++; } # later.
if ($quest->[1] != -1) { # some quests are set as -1.
next if $quest->[1] <= $options{'minlevel'};
next if $quest->[1] >= $options{'maxlevel'};
} # only filter those that are positive. ish.
print "$s | $id | ".
"$quest->[0] | $quest->[5] | $quest->[1] | ".
"$quest->[3] | $quest->[2] |
\n";
} print "
"; # all done this category, so print out some stats.
print "Listed quests matching our side: $total_category. "; # stat one. mmMm.
print "Quests completed for this category: $completed_category.
\n"; # stat two.
$completed_total += $completed_category; $completed_category = 0; # SupPpeERR.
$total_side += $total_category; $total_category = 0; # BOoirring.
}
# check reported player completions (in %completed) vs. the quest IDs we've
# found (in %found_completed) on the remote site and report discrepancies.
print STDERR "Looking for quest IDs not in active data (potential error in data).\n";
foreach my $completed (sort keys %completed) { if (!$found_completed{$completed}) {
print STDERR "Quest ID $completed not found in active data.\n";
} }
# HTML footer and final counts. cos counting is fun.
print "\nTotal listed quests matching our side: $total_side. ";
print "Total quests completed: $completed_total.
";
print STDERR "Done.\n";
print footer();
################################################################
# HTML headers and footers. nothing too exciting here. #
################################################################
sub header {
my $updated = localtime(time);
return <
World of Warcraft Quest Tracker
World of Warcraft Quest Tracker ($options{side})
The below contains a listing for all known World
of Warcraft quests available to the $options{side}, and was last generated
$updated. It was created
by a Perl script from Morbus Iff that collects quest and category data from the
Allakhazam World of Warcraft site. Quests
with asterisks next to them have been completed for this particular character.
EVIL_HEREDOC_HEADER_OF_ORMS_BY_GORE
}
sub footer { return ""; }