Initial commit 0.001
authorMarius Gavrilescu <marius@ieval.ro>
Thu, 2 Jul 2015 10:16:09 +0000 (13:16 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Thu, 2 Jul 2015 10:16:09 +0000 (13:16 +0300)
15 files changed:
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
app.psgi [new file with mode: 0644]
lib/App/NAOdash.pm [new file with mode: 0644]
lib/App/Web/NAOdash.pm [new file with mode: 0644]
lib/NetHack/NAOdash.pm [new file with mode: 0644]
naodash [new file with mode: 0755]
t/NetHack-NAOdash.t [new file with mode: 0644]
t/perlcritic.t [new file with mode: 0644]
t/perlcriticrc [new file with mode: 0644]
t/xlogfile [new file with mode: 0644]
web/dash.css [new file with mode: 0644]
web/dash.html [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..0a325ce
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension NetHack::NAOdash.
+
+0.001 2015-07-02T13:16+03:00
+  - Initial release
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..f7f2c14
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,15 @@
+app.psgi
+Changes
+lib/App/NAOdash.pm
+lib/App/Web/NAOdash.pm
+lib/NetHack/NAOdash.pm
+Makefile.PL
+MANIFEST
+naodash
+README
+t/NetHack-NAOdash.t
+t/perlcriticrc
+t/perlcritic.t
+t/xlogfile
+web/dash.css
+web/dash.html
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..fb9e176
--- /dev/null
@@ -0,0 +1,28 @@
+use 5.014000;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+       NAME             => 'NetHack::NAOdash',
+       VERSION_FROM     => 'lib/NetHack/NAOdash.pm',
+       ABSTRACT_FROM    => 'lib/NetHack/NAOdash.pm',
+       AUTHOR           => 'Marius Gavrilescu <marius@ieval.ro>',
+       EXE_FILES        => ['naodash'],
+       MIN_PERL_VERSION => '5.14.0',
+       LICENSE          => 'perl',
+       SIGN             => 1,
+       PREREQ_PM        => {
+               qw/File::Slurp       0
+                  HTML::TreeBuilder 0
+                  JSON::MaybeXS     0
+                  List::MoreUtils   0
+                  Plack::Component  0
+                  Term::ANSIColor   0
+                  Text::XLogfile    0/,
+       },
+       META_ADD         => {
+               dynamic_config => 0,
+               resources      => {
+                       repository   => 'https://git.ieval.ro/?p=nethack-naodash.git',
+               },
+       }
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3f57d70
--- /dev/null
+++ b/README
@@ -0,0 +1,44 @@
+NetHack-NAOdash version 0.001
+=============================
+
+NetHack is a roguelike (a kind of video game) and NAO
+(http://alt.org/nethack/) is a popular NetHack public server.
+
+NetHack::NAOdash is a library that analyzes the games played by a user
+on NAO and extracts some statistics from them. One use case is
+answering the question "What should I play in NetHack now?". Besides
+NAO, it works on any NetHack installation that supports extended
+logfiles.
+
+This distribution also includes a web interface to the library
+(App::Web::NAOdash) and a command-line interface (App::NAOdash).
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+* File::Slurp
+* HTML::TreeBuilder
+* JSON::MaybeXS
+* Plack
+* Term::ANSIColor
+* Text::XLogfile
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/app.psgi b/app.psgi
new file mode 100644 (file)
index 0000000..a71a3cf
--- /dev/null
+++ b/app.psgi
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+use 5.014000;
+use warnings;
+
+use App::Web::NAOdash;
+use Plack::Builder;
+
+builder {
+       mount '/dash/' => App::Web::NAOdash->new->to_app;
+       mount '/json/' => App::Web::NAOdash->new(json => 1)->to_app;
+       mount '/ok' => sub { [200, [], []] };
+       mount '/' => sub { App::Web::NAOdash::reply(404, 'Try /dash/USERNAME or /json/USERNAME')};
+}
diff --git a/lib/App/NAOdash.pm b/lib/App/NAOdash.pm
new file mode 100644 (file)
index 0000000..78428a3
--- /dev/null
@@ -0,0 +1,162 @@
+package App::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use utf8;
+
+our $VERSION = '0.001';
+
+use Encode qw/encode/;
+use File::Slurp;
+use NetHack::NAOdash;
+use Term::ANSIColor ':constants';
+
+my @order = qw/
+achieve_sokoban achieve_luckstone achieve_medusa achieve_bell achieve_gehennom achieve_candelabrum achieve_book achieve_invocation achieve_amulet achieve_endgame achieve_astral achieve_ascended
+
+combo_arc_hum_law combo_arc_hum_neu combo_arc_dwa_law combo_arc_gno_neu
+combo_bar_hum_neu combo_bar_hum_cha combo_bar_orc_cha
+combo_cav_hum_law combo_cav_hum_neu combo_cav_dwa_law combo_cav_gno_neu
+combo_hea_hum_neu combo_hea_gno_neu
+combo_kni_hum_law
+combo_mon_hum_law combo_mon_hum_neu combo_mon_hum_cha
+combo_pri_hum_law combo_pri_hum_neu combo_pri_hum_cha combo_pri_elf_cha
+combo_ran_hum_neu combo_ran_hum_cha combo_ran_elf_cha combo_ran_gno_neu combo_ran_orc_cha
+combo_rog_hum_cha combo_rog_orc_cha
+combo_sam_hum_law
+combo_tou_hum_neu
+combo_val_hum_law combo_val_hum_neu combo_val_dwa_law
+combo_wiz_hum_neu combo_wiz_hum_cha combo_wiz_elf_cha combo_wiz_gno_neu combo_wiz_orc_cha
+
+conduct_foodless conduct_vegan conduct_vegetarian conduct_atheist conduct_weaponless conduct_pacifist conduct_illiterate conduct_genocideless conduct_polypileless conduct_polyselfless conduct_wishless conduct_artiwishless
+
+uconduct_survivor uconduct_boneless uconduct_minscore/;
+
+sub naodash_to_ansi {
+       my ($dash) = @_;
+       my @checks = @{$dash->{checks}};
+       my %numbers = %{$dash->{numbers}};
+
+       my $base = <<"EOF";
+ACHIEVEMENTS
+============
+#Sokoban #Luckstone  #Medusa #Bell    #Gehennom #Candelabrum
+#Book    #Invocation #Amulet #Endgame #Astral   #Ascended
+
+STARTING COMBOS
+===============
+#Arc-Hum-Law #Arc-Hum-Neu #Arc-Dwa-Law #Arc-Gno-Neu
+#Bar-Hum-Neu #Bar-Hum-Cha #Bar-Orc-Cha
+#Cav-Hum-Law #Cav-Hum-Neu #Cav-Dwa-Law #Cav-Gno-Neu
+#Hea-Hum-Neu #Hea-Gno-Neu
+#Kni-Hum-Law
+#Mon-Hum-Law #Mon-Hum-Neu #Mon-Hum-Cha
+#Pri-Hum-Law #Pri-Hum-Neu #Pri-Hum-Cha #Pri-Elf-Cha
+#Ran-Hum-Neu #Ran-Hum-Cha #Ran-Elf-Cha #Ran-Gno-Neu #Ran-Orc-Cha
+#Rog-Hum-Cha #Rog-Orc-Cha
+#Sam-Hum-Law
+#Tou-Hum-Neu
+#Val-Hum-Law #Val-Hum-Neu #Val-Dwa-Law
+#Wiz-Hum-Neu #Wiz-Hum-Cha #Wiz-Elf-Cha #Wiz-Gno-Neu #Wiz-Orc-Cha
+
+CONDUCTS
+========
+#Foodless     #Vegan        #Vegetarian #Atheist
+#Weaponless   #Pacifist     #Illiterate #Genocideless
+#Polypileless #Polyselfless #Wishless   #Artiwishless
+
+UNOFFICIAL CONDUCTS
+===================
+#Survivor #Boneless #Minscore
+
+NUMBERS
+=======
+Time played:   $numbers{totalrealtime}
+Games:         $numbers{games}
+Ascensions:    $numbers{ascensions}
+Most HP:       $numbers{maxhp}
+Most points:   $numbers{maxpoints}
+Most conducts: $numbers{maxconducts}
+Least turns:   $numbers{minturns}
+Least time:    $numbers{minrealtime}
+EOF
+
+       my $rst = RESET;
+       for my $check (@order) {
+               my $color = (grep { $_ eq $check } @checks) ? GREEN '✓' : RED '✗';
+               $base =~ s/#([a-zA-Z-]+)/$color$1$rst/;
+       }
+
+       $base
+}
+
+sub run {
+       my ($user_or_path) = @_;
+       my $stats;
+       if ($user_or_path =~ /^\w+$/) { # Looks like a user
+               $stats = naodash_user $user_or_path
+       } else {
+               $stats = naodash_xlog read_file $user_or_path
+       }
+       print encode 'UTF-8', naodash_to_ansi $stats ## no critic (RequireCheckedSyscalls)
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::NAOdash - Analyze NetHack xlogfiles and extract statistics (command-line interface)
+
+=head1 SYNOPSIS
+
+  use App::NAOdash;
+  App::NAOdash::run(@ARGV);
+
+=head1 DESCRIPTION
+
+App::NAOdash is the backend of the L<naodash> script, a command-line
+interface to L<NetHack::NAOdash>.
+
+It defines two functions:
+
+=over
+
+=item B<naodash_to_ansi>(I<$stats>)
+
+Takes the result of B<naodash_user> or B<naodash_xlog> and presents it
+in a text form, using ANSI color escape sequences and unicode ticks
+(✓) and X marks (✗) to indicate the presence/absence of checks.
+
+=item B<run>(I<$user_or_path>)
+
+Analyzes the xlogfile for the given user / at the given path, passes
+the result through B<naodash_to_ansi> and prints the result.
+
+If the argument contains non-word characters, it is interpreted as a
+path. Otherwise it is interpreted as a NAO username.
+
+=back
+
+=head1 SEE ALSO
+
+L<naodash>, L<NetHack::NAOdash>, L<App::Web::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/App/Web/NAOdash.pm b/lib/App/Web/NAOdash.pm
new file mode 100644 (file)
index 0000000..a9d0482
--- /dev/null
@@ -0,0 +1,148 @@
+package App::Web::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use parent qw/Plack::Component/;
+
+our $VERSION = '0.001';
+
+use Digest::SHA qw/sha256_base64/;
+use File::Slurp;
+use HTML::TreeBuilder;
+use JSON::MaybeXS qw/encode_json/;
+use NetHack::NAOdash qw/naodash_user/;
+
+my ($dash, $css, $css_hash);
+
+{
+       $css = read_file 'web/dash.css';
+       $css =~ y/\n\t//d;
+       $css =~ s/([):]) /$1/g;
+       $css =~ s/ ([{(])/$1/g;
+       $css_hash = 'sha256-' . sha256_base64($css) . '=';
+       my $tb = HTML::TreeBuilder->new;
+       $tb->ignore_unknown(0);
+       $dash = $tb->parse_file('web/dash.html');
+       $dash->find('link')->postinsert([style => $css])->detach;
+}
+
+sub format_time {
+       my ($time) = @_;
+       return unless defined $time;
+       my %units = (
+               s => 60,
+               m => 60,
+               h => 24,
+               d => 7,
+               w => 1e9,
+       );
+       my @parts;
+       for (qw/s m h d w/) {
+               use integer;
+               last unless $time;
+               unshift @parts, ($time % $units{$_}) . $_;
+               $time /= $units{$_};
+       }
+       join ' ', @parts;
+}
+
+sub make_html {
+       my ($name, $result) = @_;
+       my @checks = @{$result->{checks}};
+       my %numbers = %{$result->{numbers}};
+       $numbers{totalrealtime} = format_time $numbers{totalrealtime};
+       $numbers{minrealtime} = format_time $numbers{minrealtime};
+
+       my $tree = $dash->clone;
+       $tree->find('title')->delete_content->push_content("Dashboard for $name");
+       $tree->find('a')->attr(href => $tree->find('a')->attr('href') . $name);
+       $tree->find('a')->delete_content->push_content($name);
+       for (@checks) {
+               my $el = $tree->look_down(id => $_);
+               warn "No element for check $_" unless $el; ## no critic (RequireCarping)
+               $el->attr(class => 'done') if $el;
+       }
+       while (my ($id, $num) = each %numbers) {
+               next unless defined $num;
+               my $el = $tree->look_down(id => $id);
+               warn "No element for check $id" unless $el; ## no critic (RequireCarping)
+               $el->delete_content->push_content($num);
+       }
+       $tree->as_HTML;
+}
+
+sub reply {
+       my ($code, $message, $type) = @_;
+       $type //= 'text/plain';
+       [$code, [
+               'Cache-Control' => ($code < 500 ? 'max-age=86400' : 'no-cache'),
+               'Content-Type' => "$type; charset=utf-8",
+               'Content-Length' => length $message,
+# Safari implements CSP Level 1 but not CSP Level 2
+#              'Content-Security-Policy' => "default-src 'none'; style-src '$css_hash';",
+       ], [$message]]
+}
+
+sub call {
+       my ($self, $env) = @_;
+       return reply 400, 'Bad request: user contains characters outside [a-zA-Z0-9_]' unless $env->{PATH_INFO} =~ m{^/(\w+)$};
+       my $name = $1;
+       my $result = eval { naodash_user $name } or return reply 500, $@;
+
+       return reply 200, encode_json($result), 'application/json' if $self->{json};
+       return reply 200, make_html($name, $result), 'text/html';
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+App::Web::NAOdash - Analyze NetHack xlogfiles and extract statistics (web interface)
+
+=head1 SYNOPSIS
+
+  # In app.psgi
+  use App::Web::NAOdash;
+  use Plack::Builder;
+
+  builder {
+    mount '/dash/' => App::Web::NAOdash->new->to_app;
+    mount '/json/' => App::Web::NAOdash->new(json => 1)->to_app;
+    ...
+  }
+
+=head1 DESCRIPTION
+
+App::Web::NAOdash is a web interface to L<NetHack::NAOdash>.
+
+It handles URLs of the form C</username>, where I<username> is a NAO
+username. It retrieves the xlogfile from NAO and returns the result of
+the analysis.
+
+The constructor takes a single named parameter, I<json>, that is false
+by default. The result will be returned as HTML is I<json> is false,
+as JSON if I<json> is true.
+
+=head1 SEE ALSO
+
+L<NetHack::NAOdash>, L<App::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/NetHack/NAOdash.pm b/lib/NetHack/NAOdash.pm
new file mode 100644 (file)
index 0000000..af574ef
--- /dev/null
@@ -0,0 +1,286 @@
+package NetHack::NAOdash;
+
+use 5.014000;
+use strict;
+use warnings;
+use re '/saa';
+use parent qw/Exporter/;
+
+our $VERSION = '0.001';
+our @EXPORT_OK = qw/naodash_xlog naodash_user/;
+our @EXPORT = @EXPORT_OK;
+
+use HTTP::Tiny;
+use List::Util qw/max min sum/;
+use List::MoreUtils qw/uniq/;
+use Text::XLogfile qw/parse_xlogline/;
+
+sub won_game {
+       my %game = @_;
+       $game{death} eq 'ascended'
+}
+
+our @check_subs = (
+       sub { # Combos
+               my %game = @_;
+               return unless won_game %game;
+               $game{align0} //= $game{align};
+               "combo_$game{role}_$game{race}_$game{align0}"
+       },
+
+       sub { # Achievements
+               my %game = @_;
+               my @achieves = qw/bell gehennom candelabrum book invocation amulet endgame astral ascended luckstone sokoban medusa/;
+               map { $game{achieve} & (1 << $_) ? "achieve_$achieves[$_]" : () } 0 .. $#achieves
+       },
+
+       sub { # Conducts
+               my %game = @_;
+               return unless won_game %game;
+               my @conducts = qw/foodless vegan vegetarian atheist weaponless pacifist illiterate polypileless polyselfless wishless artiwishless genocideless/;
+               map { $game{conduct} & (1 << $_) ? "conduct_$conducts[$_]" : () } 0 .. $#conducts
+       },
+
+       sub { # Unofficial conducts
+               my %game = @_;
+               return unless won_game %game;
+               my @uconducts;
+               push @uconducts, 'survivor' if $game{deaths} == 0;
+               push @uconducts, 'boneless' unless $game{flags} & 32;
+               push @uconducts, 'minscore' if $game{points} - 100 * ($game{maxlvl} - 45) == 24_400;
+               map { "uconduct_$_" } @uconducts
+       },
+);
+
+our %sum_subs = (
+       games => sub { 1 },
+       ascensions => sub {
+               my %game = @_;
+               !!won_game %game
+       },
+       totalrealtime => sub {
+               my %game = @_;
+               $game{realtime} // 0
+       },
+);
+
+sub make_attr_sub ($) { ## no critic (ProhibitSubroutinePrototypes)
+       my ($attr) = @_;
+       sub {
+               my %game = @_;
+               return unless won_game %game;
+               $game{$attr} // ()
+       },
+}
+
+our %max_subs = (
+       maxhp => make_attr_sub 'maxhp',
+       maxpoints => make_attr_sub 'points',
+       maxconducts => make_attr_sub 'nconducts',
+);
+
+our %min_subs = (
+       minturns => make_attr_sub 'turns',
+       minrealtime => make_attr_sub 'realtime',
+);
+
+sub naodash_xlog { ## no critic (RequireArgUnpacking)
+       my ($xlog) = join '', @_;
+       my %number_subs = (%sum_subs, %max_subs, %min_subs);
+
+       my @checks;
+       my %numbers = map { $_ => [] } keys %number_subs;
+
+       for my $logline (split /\n/, $xlog) {
+               my %game = %{parse_xlogline $logline};
+               for (keys %game) {
+                       delete $game{$_} if $game{$_} eq ''
+               }
+               next if $game{flags} & 3; # flag 0x01 is wizard mode, 0x02 is explore mode
+               push @checks, $_->(%game) for @check_subs;
+               push @{$numbers{$_}}, $number_subs{$_}->(%game) for keys %number_subs;
+       }
+
+       $numbers{$_} = sum @{$numbers{$_}} for keys %sum_subs;
+       $numbers{$_} = max @{$numbers{$_}} for keys %max_subs;
+       $numbers{$_} = min @{$numbers{$_}} for keys %min_subs;
+       @checks = uniq map { lc } @checks;
+
+       {checks => [sort @checks], numbers => \%numbers}
+}
+
+my $ht = HTTP::Tiny->new(agent => "NetHack-NAOdash/$VERSION ");
+
+sub naodash_user {
+       my ($name) = @_;
+       my $ret = $ht->get("http://alt.org/nethack/player-all-xlog.php?player=$name");
+       die 'Error while retrieving xlogfile from alt.org: ' . $ret->{status} . ' ' . $ret->{reason} . "\n" unless $ret->{success};
+       my ($xlog) = $ret->{content} =~ m{<pre>(.*)</pre>}i;
+       die "No xlogfile found for user $name\n" unless defined $xlog;
+       naodash_xlog $xlog;
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+NetHack::NAOdash - Analyze NetHack xlogfiles and extract statistics
+
+=head1 SYNOPSIS
+
+  use NetHack::NAOdash;
+  my $stats = naodash_user 'mgv'; # Retrieve and analyze mgv's xlogfile from alt.org
+  my @checks = @{$stats->{checks}}; # List of "achievements" obtained by mgv
+  my %checks = map { $_ => 1 } @checks;
+  say "mgv has ascended an orcish rogue" if $checks{combo_rog_orc_cha};
+  say "mgv has ascended an atheist character" if $checks{conduct_atheist};
+  my %numbers = %{$stats->{numbers}};
+  say "mgv has ascended $numbers{ascensions} out of $numbers{games} games";
+  say "mgv has spent $numbers{totalrealtime} seconds playing NetHack on NAO";
+
+  use File::Slurp;
+  $stats = naodash_xlog read_file 'path/to/my/xlogfile';
+  %checks = map { $_ => 1 } @{$stats->{checks}};
+  say "I have ascended a survivor" if $checks{uconduct_survivor};
+
+=head1 DESCRIPTION
+
+NetHack::NAOdash analyzes a NetHack xlogfile and reports statistics.
+There are two types of statistics: B<checks>, which are flags
+(booleans) and B<numbers> which are integers.
+
+The B<checks> are tracked across all games. That is, a B<check> will
+be true in the statistics if it is true in at least one game. Except
+for B<checks> in the I<Achievements> category, only games that end in
+an ascension are considered for awarding a B<check>.
+
+The B<checks>, sorted by category, are:
+
+=over
+
+=item B<Achievements>
+
+These start with C<achieve_> and represent significant milestones in a
+game. They are usually relevant only for users who never ascended, as
+a game that ends in an ascension generally meets all of them.
+
+  achieve_sokoban  achieve_luckstone   achieve_medusa achieve_bell
+  achieve_gehennom achieve_candelabrum achieve_book   achieve_invocation
+  achieve_amulet   achieve_endgame     achieve_astral achieve_ascended
+
+=item B<Starting Combos>
+
+These look like C<combo_role_race_alignment> and represent
+role/race/alignment combinations in ascended games. The starting
+alignment, not the alignment at the end of the game is considered. For
+example, C<cav_gno_neu> is true if the user ascended at least one
+gnomish caveman.
+
+=item B<Conducts>
+
+These start with C<conduct_> and represent the 12 officially tracked
+conducts.
+
+  conduct_foodless     conduct_vegan        conduct_vegetarian
+  conduct_atheist      conduct_weaponless   conduct_pacifist
+  conduct_illiterate   conduct_genocideless conduct_polypileless
+  conduct_polyselfless conduct_wishless     conduct_artiwishless
+
+=item B<Unofficial Conducts>
+
+These start with C<uconduct_> and represent conducts that are not
+officially tracked by the game.
+
+  uconduct_survivor uconduct_bones uconduct_minscore
+
+=back
+
+The numbers are:
+
+=over
+
+=item B<totalrealtime>
+
+The total time spent playing NetHack on NAO, in seconds.
+
+=item B<games>
+
+The number of games played.
+
+=item B<ascensions>
+
+The number of games played that ended in an ascension.
+
+=item B<maxhp>
+
+The highest maxHP at the end of an ascension.
+
+=item B<maxpoints>
+
+The highest score obtained at the end of an ascension.
+
+=item B<maxconducts>
+
+The maximum number of conducts at the end of an ascension.
+
+=item B<minturns>
+
+The minimum turns across ascended games.
+
+=item B<minrealtime>
+
+The minimum realtime across ascended games, in seconds.
+
+=back
+
+This module exports two functions:
+
+=over
+
+=item B<naodash_xlog>(I<@lines>)
+
+=item B<naodash_xlog>(I<$xlog>)
+
+Takes the contents of an xlogfile and returns the results of the
+analysis. The arguments are joined together then split by the newline
+character, so they can be specified as a single string, as a list of
+lines, or as a combination thereof.
+
+The return value is of the following form:
+
+  { checks => ['achieve_sokoban', 'achieve_luckstone', ...],
+    numbers => {totalrealtime => 12345, games => 2, ...} }
+
+In other words, C<< @{$result->{checks}} >> is an array of B<checks>
+that are true and C<< %{$result->{numbers}} >> is a hash of
+B<numbers>.
+
+=item B<naodash_user>(I<$nao_username>)
+
+Retrieves the xlogfile of a user from NAO and gives it to
+B<naodash_xlog>. Dies if no xlogfile is found or if the server cannot
+be contacted.
+
+=back
+
+=head1 SEE ALSO
+
+L<App::NAOdash>, L<App::Web::NAOdash>, L<http://alt.org/nethack/>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/naodash b/naodash
new file mode 100755 (executable)
index 0000000..47505de
--- /dev/null
+++ b/naodash
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+use 5.014000;
+use strict;
+use warnings;
+
+use App::NAOdash;
+
+App::NAOdash::run(@ARGV);
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+naodash - Analyze NetHack xlogfiles and extract statistics (command-line interface)
+
+=head1 SYNOPSIS
+
+  naodash mgv # Show statistics for the mgv user on NAO
+  naodash /path/to/xlogfile # Show statistics for a given xlogfile
+
+=head1 DESCRIPTION
+
+naodash is a command-line interface to L<NetHack::NAOdash>. It takes a
+NAO username or a path to an xlogfile, analyzes it, and prints the
+results of the analysis. A terminal with color and/or UTF-8 support is
+required. Do not parse this command's output. For computer-readable
+output, please use the L<NetHack::NAOdash> library directly.
+
+=head1 SEE ALSO
+
+L<NetHack::NAOdash>, L<http://alt.org/nethack/>, L<App::NAOdash>, L<App::Web::NAOdash>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/t/NetHack-NAOdash.t b/t/NetHack-NAOdash.t
new file mode 100644 (file)
index 0000000..7b5019a
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+use 5.014000;
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+BEGIN { use_ok 'NetHack::NAOdash' }
+
+open my $fh, '<', 't/xlogfile';
+my @xlog = <$fh>;
+close $fh;
+
+is_deeply naodash_xlog (@xlog), {
+       numbers => {
+               ascensions => 15,
+               games => 85,
+               maxconducts => 4,
+               maxhp => 422,
+               maxpoints => 3429164,
+               minrealtime => 43395,
+               minturns => 36028,
+               totalrealtime => 1483024,
+       },
+
+       checks => [qw/achieve_amulet achieve_ascended achieve_astral achieve_bell achieve_book achieve_candelabrum achieve_endgame achieve_gehennom achieve_invocation achieve_luckstone achieve_medusa achieve_sokoban combo_arc_dwa_law combo_bar_orc_cha combo_cav_gno_neu combo_hea_gno_neu combo_kni_hum_law combo_mon_hum_neu combo_pri_hum_law combo_pri_hum_neu combo_ran_elf_cha combo_rog_orc_cha combo_sam_hum_law combo_tou_hum_neu combo_val_dwa_law combo_wiz_elf_cha conduct_artiwishless conduct_atheist conduct_genocideless conduct_polypileless conduct_polyselfless conduct_vegetarian conduct_weaponless uconduct_boneless uconduct_survivor/]
+}, 'naodash_xlog';
diff --git a/t/perlcritic.t b/t/perlcritic.t
new file mode 100644 (file)
index 0000000..79e93dc
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use Test::More;
+
+BEGIN { plan skip_all => '$ENV{RELEASE_TESTING} is false' unless $ENV{RELEASE_TESTING} }
+use Test::Perl::Critic -profile => 't/perlcriticrc';
+
+all_critic_ok 'lib'
diff --git a/t/perlcriticrc b/t/perlcriticrc
new file mode 100644 (file)
index 0000000..5815f07
--- /dev/null
@@ -0,0 +1,36 @@
+severity = 1
+
+[-BuiltinFunctions::ProhibitComplexMappings]
+[-CodeLayout::RequireTidyCode]
+[-ControlStructures::ProhibitPostfixControls]
+[-ControlStructures::ProhibitUnlessBlocks]
+[-Documentation::PodSpelling]
+[-Documentation::RequirePodLinksIncludeText]
+[-InputOutput::RequireBracedFileHandleWithPrint]
+[-Modules::ProhibitAutomaticExportation]
+[-References::ProhibitDoubleSigils]
+[-RegularExpressions::ProhibitEnumeratedClasses]
+[-RegularExpressions::RequireLineBoundaryMatching]
+[-Subroutines::RequireFinalReturn]
+[-ValuesAndExpressions::ProhibitConstantPragma]
+[-ValuesAndExpressions::ProhibitEmptyQuotes]
+[-ValuesAndExpressions::ProhibitLeadingZeros]
+[-ValuesAndExpressions::ProhibitMagicNumbers]
+[-ValuesAndExpressions::ProhibitNoisyQuotes]
+[-Variables::ProhibitLocalVars]
+[-Variables::ProhibitPackageVars]
+[-Variables::ProhibitPunctuationVars]
+
+[BuiltinFunctions::ProhibitStringyEval]
+allow_includes = 1
+
+[RegularExpressions::RequireExtendedFormatting]
+minimum_regex_length_to_complain_about = 20
+
+[Documentation::RequirePodSections]
+lib_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+script_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+
+[Subroutines::RequireArgUnpacking]
+short_subroutine_statements = 5
+allow_subscripts = 1
diff --git a/t/xlogfile b/t/xlogfile
new file mode 100644 (file)
index 0000000..cc126a4
--- /dev/null
@@ -0,0 +1,85 @@
+version=3.4.3:points=1574:deathdnum=0:deathlev=4:maxlvl=5:hp=-4:maxhp=29:deaths=1:deathdate=20140316:birthdate=20140316:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a rothe:conduct=3968:turns=2482:achieve=0:nconducts=5:nachieves=0:realtime=1078:starttime=1394973862:endtime=1395008755:gamedelta=34893:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=1691:deathdnum=0:deathlev=4:maxlvl=4:hp=-6:maxhp=28:deaths=1:deathdate=20140317:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a rothe:conduct=4032:turns=1936:achieve=0:nconducts=6:nachieves=0:realtime=1298:starttime=1395061888:endtime=1395063195:gamedelta=1307:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=243:deathdnum=2:deathlev=3:maxlvl=3:hp=-2:maxhp=11:deaths=1:deathdate=20140317:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gnome:conduct=4040:turns=607:achieve=0:nconducts=7:nachieves=0:realtime=452:starttime=1395063210:endtime=1395063673:gamedelta=463:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2559688:deathdnum=7:deathlev=-5:maxlvl=49:hp=175:maxhp=231:deaths=1:deathdate=20140428:birthdate=20140317:uid=5:role=Wiz:race=Elf:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=1024:turns=64748:achieve=4095:nconducts=1:nachieves=12:realtime=112824:starttime=1395063679:endtime=1398673207:gamedelta=3609528:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2338:deathdnum=2:deathlev=5:maxlvl=5:hp=-5:maxhp=47:deaths=1:deathdate=20140430:birthdate=20140428:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a magic missile:conduct=3968:turns=2734:achieve=0:nconducts=5:nachieves=0:realtime=4683:starttime=1398673722:endtime=1398861401:gamedelta=187679:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=64:deathdnum=0:deathlev=1:maxlvl=1:hp=-2:maxhp=12:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a sewer rat:conduct=4047:turns=67:achieve=0:nconducts=10:nachieves=0:realtime=183:starttime=1398861455:endtime=1398861641:gamedelta=186:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=763:deathdnum=0:deathlev=4:maxlvl=4:hp=-2:maxhp=14:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Arc:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a little dog:conduct=4040:turns=920:achieve=0:nconducts=7:nachieves=0:realtime=633:starttime=1398861653:endtime=1398862299:gamedelta=646:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=138:deathdnum=0:deathlev=1:maxlvl=2:hp=0:maxhp=24:deaths=1:deathdate=20140430:birthdate=20140430:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a jackal, while reading a book:conduct=3976:turns=425:achieve=0:nconducts=6:nachieves=0:realtime=762:starttime=1398862499:endtime=1398863267:gamedelta=768:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=138584:deathdnum=0:deathlev=15:maxlvl=25:hp=-5:maxhp=101:deaths=1:deathdate=20140501:birthdate=20140430:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a mumak:conduct=3712:turns=15586:achieve=2048:nconducts=4:nachieves=1:realtime=22989:starttime=1398863275:endtime=1398970743:gamedelta=107468:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=1593:deathdnum=2:deathlev=5:maxlvl=5:hp=0:maxhp=40:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a dingo:conduct=3976:turns=2159:achieve=0:nconducts=6:nachieves=0:realtime=1705:starttime=1399046649:endtime=1399048359:gamedelta=1710:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=4:deathdnum=0:deathlev=1:maxlvl=1:hp=15:maxhp=15:deaths=0:deathdate=20140502:birthdate=20140502:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=quit:conduct=4095:turns=20:achieve=0:nconducts=12:nachieves=0:realtime=52:starttime=1399048363:endtime=1399048419:gamedelta=56:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=255:deathdnum=0:deathlev=4:maxlvl=4:hp=-2:maxhp=15:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a hobbit, while fainted from lack of food:conduct=3718:turns=1243:achieve=0:nconducts=6:nachieves=0:realtime=609:starttime=1399048429:endtime=1399049044:gamedelta=615:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=883:deathdnum=0:deathlev=4:maxlvl=4:hp=0:maxhp=36:deaths=1:deathdate=20140502:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a rothe, while sleeping:conduct=3976:turns=1354:achieve=0:nconducts=6:nachieves=0:realtime=732:starttime=1399049051:endtime=1399049786:gamedelta=735:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=1680:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=32:deaths=1:deathdate=20140506:birthdate=20140502:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a magic missile:conduct=3968:turns=3103:achieve=0:nconducts=5:nachieves=0:realtime=2662:starttime=1399049791:endtime=1399378898:gamedelta=329107:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=2281596:deathdnum=7:deathlev=-5:maxlvl=50:hp=132:maxhp=132:deaths=0:deathdate=20140830:birthdate=20140825:uid=5:role=Cav:race=Gno:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=256:turns=39454:achieve=3583:nconducts=1:nachieves=11:realtime=80436:starttime=1408969798:endtime=1409387505:gamedelta=417707:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=10568:deathdnum=2:deathlev=6:maxlvl=6:hp=0:maxhp=48:deaths=1:deathdate=20140831:birthdate=20140830:uid=5:role=Mon:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a bolt of cold:conduct=3990:turns=4933:achieve=0:nconducts=8:nachieves=0:realtime=7039:starttime=1409387614:endtime=1409472453:gamedelta=84839:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=16615:deathdnum=0:deathlev=9:maxlvl=9:hp=0:maxhp=84:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hallucinogen-distorted soldier ant:conduct=3968:turns=7403:achieve=0:nconducts=5:nachieves=0:realtime=9151:starttime=1409474095:endtime=1409492250:gamedelta=18155:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=520:deathdnum=2:deathlev=3:maxlvl=3:hp=-5:maxhp=23:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by Yeenoghu:conduct=3976:turns=1009:achieve=0:nconducts=6:nachieves=0:realtime=997:starttime=1409492260:endtime=1409493281:gamedelta=1021:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=6057:deathdnum=0:deathlev=6:maxlvl=7:hp=0:maxhp=62:deaths=1:deathdate=20140831:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3712:turns=4652:achieve=0:nconducts=4:nachieves=0:realtime=4235:starttime=1409493340:endtime=1409509834:gamedelta=16494:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=19357:deathdnum=0:deathlev=17:maxlvl=17:hp=-1:maxhp=70:deaths=1:deathdate=20140901:birthdate=20140831:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a Woodland-elf:conduct=3968:turns=10752:achieve=0:nconducts=5:nachieves=0:realtime=11762:starttime=1409509991:endtime=1409583170:gamedelta=73179:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=2163:deathdnum=2:deathlev=7:maxlvl=7:hp=-1:maxhp=48:deaths=1:deathdate=20140901:birthdate=20140901:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a gold golem:conduct=3968:turns=2368:achieve=0:nconducts=5:nachieves=0:realtime=2080:starttime=1409583188:endtime=1409585272:gamedelta=2084:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=18132:deathdnum=0:deathlev=5:maxlvl=6:hp=-7:maxhp=61:deaths=1:deathdate=20140903:birthdate=20140901:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=3968:turns=6850:achieve=0:nconducts=5:nachieves=0:realtime=11348:starttime=1409585279:endtime=1409739512:gamedelta=154233:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=46:deathdnum=0:deathlev=1:maxlvl=1:hp=-3:maxhp=16:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a bolt of cold:conduct=4087:turns=211:achieve=0:nconducts=11:nachieves=0:realtime=86:starttime=1409739520:endtime=1409739611:gamedelta=91:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2546:deathdnum=2:deathlev=8:maxlvl=8:hp=-2:maxhp=48:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by an ettin zombie:conduct=3968:turns=3064:achieve=0:nconducts=5:nachieves=0:realtime=2919:starttime=1409739667:endtime=1409742589:gamedelta=2922:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=6945:deathdnum=4:deathlev=5:maxlvl=7:hp=-3:maxhp=55:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3968:turns=4246:achieve=0:nconducts=5:nachieves=0:realtime=5091:starttime=1409742598:endtime=1409748872:gamedelta=6274:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2672:deathdnum=2:deathlev=7:maxlvl=7:hp=-1:maxhp=51:deaths=1:deathdate=20140903:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a little dog, while jumping around:conduct=3968:turns=3039:achieve=0:nconducts=5:nachieves=0:realtime=1295:starttime=1409748876:endtime=1409750175:gamedelta=1299:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=1845610:deathdnum=7:deathlev=-5:maxlvl=53:hp=113:maxhp=113:deaths=0:deathdate=20140906:birthdate=20140903:uid=5:role=Kni:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1024:turns=37986:achieve=4095:nconducts=1:nachieves=12:realtime=74502:starttime=1409750185:endtime=1410000662:gamedelta=250477:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=5852:deathdnum=0:deathlev=7:maxlvl=7:hp=-1:maxhp=67:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Tou:race=Hum:gender=Mal:align=Neu:name=mgv:death=poisoned by a killer bee:conduct=3968:turns=3667:achieve=0:nconducts=5:nachieves=0:realtime=2293:starttime=1410012348:endtime=1410014648:gamedelta=2300:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=3775:deathdnum=0:deathlev=8:maxlvl=9:hp=-3:maxhp=48:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a panther:conduct=3976:turns=2917:achieve=0:nconducts=6:nachieves=0:realtime=1636:starttime=1410014800:endtime=1410016443:gamedelta=1643:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=5595:deathdnum=0:deathlev=5:maxlvl=5:hp=-8:maxhp=62:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a bolt of cold:conduct=3976:turns=2990:achieve=0:nconducts=6:nachieves=0:realtime=1590:starttime=1410016463:endtime=1410018058:gamedelta=1595:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=4853:deathdnum=2:deathlev=6:maxlvl=6:hp=-2:maxhp=54:deaths=1:deathdate=20140906:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a soldier ant:conduct=3976:turns=2328:achieve=0:nconducts=6:nachieves=0:realtime=1517:starttime=1410018068:endtime=1410024764:gamedelta=6696:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=287599:deathdnum=1:deathlev=30:maxlvl=30:hp=-2:maxhp=100:deaths=1:deathdate=20140908:birthdate=20140906:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a stone golem:conduct=2304:turns=23103:achieve=3074:nconducts=2:nachieves=3:realtime=31860:starttime=1410024774:endtime=1410168612:gamedelta=143838:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2524230:deathdnum=7:deathlev=-5:maxlvl=51:hp=167:maxhp=204:deaths=0:deathdate=20140910:birthdate=20140908:uid=5:role=Pri:race=Hum:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=0:turns=44351:achieve=4095:nconducts=0:nachieves=12:realtime=52600:starttime=1410168699:endtime=1410385768:gamedelta=217069:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=1801:deathdnum=0:deathlev=5:maxlvl=5:hp=0:maxhp=39:deaths=1:deathdate=20140911:birthdate=20140911:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=killed by a housecat:conduct=3968:turns=2341:achieve=0:nconducts=5:nachieves=0:realtime=1717:starttime=1410455388:endtime=1410457112:gamedelta=1724:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=6436:deathdnum=0:deathlev=6:maxlvl=6:hp=0:maxhp=51:deaths=1:deathdate=20140912:birthdate=20140911:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=killed by a giant ant:conduct=3968:turns=3487:achieve=0:nconducts=5:nachieves=0:realtime=2001:starttime=1410457121:endtime=1410502968:gamedelta=45847:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2828716:deathdnum=7:deathlev=-5:maxlvl=45:hp=95:maxhp=138:deaths=2:deathdate=20140925:birthdate=20140912:uid=5:role=Rog:race=Orc:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=256:turns=44079:achieve=4095:nconducts=1:nachieves=12:realtime=63926:starttime=1410502985:endtime=1411665285:gamedelta=1162300:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=1818:deathdnum=2:deathlev=6:maxlvl=6:hp=-1:maxhp=41:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=poisoned by a little dart:conduct=3976:turns=1681:achieve=0:nconducts=6:nachieves=0:realtime=1064:starttime=1411746730:endtime=1411747812:gamedelta=1082:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=20623:deathdnum=0:deathlev=10:maxlvl=10:hp=0:maxhp=57:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=2432:turns=7562:achieve=0:nconducts=3:nachieves=0:realtime=6040:starttime=1411747821:endtime=1411759627:gamedelta=11806:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=1860:deathdnum=2:deathlev=6:maxlvl=6:hp=-5:maxhp=43:deaths=1:deathdate=20140926:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a wolf, while praying:conduct=3968:turns=1686:achieve=0:nconducts=5:nachieves=0:realtime=1010:starttime=1411760269:endtime=1411761350:gamedelta=1081:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=33002:deathdnum=4:deathlev=3:maxlvl=8:hp=0:maxhp=82:deaths=1:deathdate=20140928:birthdate=20140926:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a manes, while praying:conduct=3968:turns=9933:achieve=0:nconducts=5:nachieves=0:realtime=6683:starttime=1411761382:endtime=1411892399:gamedelta=131017:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=20253:deathdnum=0:deathlev=9:maxlvl=9:hp=-3:maxhp=59:deaths=1:deathdate=20140928:birthdate=20140928:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a crocodile:conduct=3968:turns=6982:achieve=0:nconducts=5:nachieves=0:realtime=4587:starttime=1411892564:endtime=1411897302:gamedelta=4738:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=670:deathdnum=2:deathlev=4:maxlvl=4:hp=-3:maxhp=31:deaths=1:deathdate=20141002:birthdate=20140928:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hill orc:conduct=3968:turns=1026:achieve=0:nconducts=5:nachieves=0:realtime=389:starttime=1411897345:endtime=1412255074:gamedelta=357729:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=7612:deathdnum=2:deathlev=11:maxlvl=11:hp=-3:maxhp=55:deaths=1:deathdate=20141002:birthdate=20141002:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an ettin zombie:conduct=3968:turns=4768:achieve=0:nconducts=5:nachieves=0:realtime=4228:starttime=1412255090:endtime=1412259385:gamedelta=4295:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=7127:deathdnum=2:deathlev=7:maxlvl=7:hp=0:maxhp=68:deaths=1:deathdate=20141120:birthdate=20141120:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a hallucinogen-distorted soldier ant:conduct=3968:turns=2576:achieve=0:nconducts=5:nachieves=0:realtime=2289:starttime=1416501954:endtime=1416504250:gamedelta=2296:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=85271:deathdnum=0:deathlev=12:maxlvl=13:hp=-3:maxhp=110:deaths=1:deathdate=20141125:birthdate=20141120:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an invisible sergeant:conduct=3200:turns=19073:achieve=0:nconducts=3:nachieves=0:realtime=22508:starttime=1416504271:endtime=1416905326:gamedelta=401055:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2614:deathdnum=2:deathlev=7:maxlvl=7:hp=0:maxhp=35:deaths=1:deathdate=20141125:birthdate=20141125:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a raven:conduct=3972:turns=3107:achieve=0:nconducts=6:nachieves=0:realtime=2949:starttime=1416905500:endtime=1416908452:gamedelta=2952:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=124804:deathdnum=0:deathlev=23:maxlvl=23:hp=-3:maxhp=112:deaths=1:deathdate=20141126:birthdate=20141125:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by an invisible stalker:conduct=3712:turns=24828:achieve=1024:nconducts=4:nachieves=1:realtime=26890:starttime=1416908461:endtime=1417017705:gamedelta=109244:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2682952:deathdnum=7:deathlev=-5:maxlvl=49:hp=384:maxhp=384:deaths=1:deathdate=20141130:birthdate=20141126:uid=5:role=Tou:race=Hum:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=0:turns=47585:achieve=4095:nconducts=0:nachieves=12:realtime=55676:starttime=1417017822:endtime=1417387940:gamedelta=370118:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=4172:deathdnum=2:deathlev=5:maxlvl=8:hp=0:maxhp=48:deaths=1:deathdate=20141201:birthdate=20141201:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a dwarf zombie, while frozen by a monster's gaze:conduct=3968:turns=2846:achieve=0:nconducts=5:nachieves=0:realtime=2263:starttime=1417417112:endtime=1417424607:gamedelta=7495:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=418339:deathdnum=0:deathlev=20:maxlvl=26:hp=-3:maxhp=93:deaths=1:deathdate=20141204:birthdate=20141201:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a troll, while unconscious from rotten food:conduct=1664:turns=30737:achieve=3584:nconducts=3:nachieves=3:realtime=44405:starttime=1417424641:endtime=1417711176:gamedelta=286535:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=64547:deathdnum=2:deathlev=12:maxlvl=12:hp=-3:maxhp=80:deaths=1:deathdate=20141206:birthdate=20141204:uid=5:role=Ran:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a lynx, while reading a book:conduct=2432:turns=17778:achieve=1536:nconducts=3:nachieves=2:realtime=23032:starttime=1417711383:endtime=1417853691:gamedelta=142308:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=140:deathdnum=0:deathlev=3:maxlvl=3:hp=-2:maxhp=10:deaths=1:deathdate=20141206:birthdate=20141206:uid=5:role=Hea:race=Gno:gender=Mal:align=Neu:name=mgv:death=killed by a boiling potion:conduct=3983:turns=447:achieve=0:nconducts=9:nachieves=0:realtime=355:starttime=1417853810:endtime=1417854174:gamedelta=364:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=2930688:deathdnum=7:deathlev=-5:maxlvl=51:hp=326:maxhp=334:deaths=0:deathdate=20141220:birthdate=20141206:uid=5:role=Hea:race=Gno:gender=Mal:align=Neu:name=mgv:death=ascended:conduct=256:turns=54221:achieve=4095:nconducts=1:nachieves=12:realtime=56624:starttime=1417854183:endtime=1419061983:gamedelta=1207800:gender0=Mal:align0=Neu:flags=0
+version=3.4.3:points=1090:deathdnum=2:deathlev=8:maxlvl=8:hp=-2:maxhp=20:deaths=1:deathdate=20141220:birthdate=20141220:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=killed by a giant spider:conduct=3968:turns=5272:achieve=0:nconducts=5:nachieves=0:realtime=6237:starttime=1419062033:endtime=1419070797:gamedelta=8764:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2683318:deathdnum=7:deathlev=-5:maxlvl=50:hp=407:maxhp=422:deaths=0:deathdate=20141222:birthdate=20141220:uid=5:role=Arc:race=Dwa:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1280:turns=49351:achieve=3071:nconducts=2:nachieves=11:realtime=64246:starttime=1419070817:endtime=1419254211:gamedelta=183394:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=33334:deathdnum=0:deathlev=8:maxlvl=8:hp=-2:maxhp=60:deaths=1:deathdate=20141223:birthdate=20141222:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by an ettin mummy:conduct=3968:turns=12157:achieve=1024:nconducts=5:nachieves=1:realtime=16233:starttime=1419262619:endtime=1419325395:gamedelta=62776:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=1124:deathdnum=2:deathlev=4:maxlvl=5:hp=-1:maxhp=39:deaths=1:deathdate=20141223:birthdate=20141223:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a fire ant:conduct=3968:turns=2261:achieve=0:nconducts=5:nachieves=0:realtime=3269:starttime=1419325436:endtime=1419328708:gamedelta=3272:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=28262:deathdnum=0:deathlev=6:maxlvl=8:hp=-3:maxhp=66:deaths=1:deathdate=20141224:birthdate=20141223:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a winter wolf, while frozen by a potion:conduct=3968:turns=11253:achieve=1024:nconducts=5:nachieves=1:realtime=15181:starttime=1419328718:endtime=1419406538:gamedelta=77820:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=506:deathdnum=2:deathlev=3:maxlvl=3:hp=-1:maxhp=21:deaths=1:deathdate=20141224:birthdate=20141224:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gnome lord:conduct=4040:turns=903:achieve=0:nconducts=7:nachieves=0:realtime=343:starttime=1419406548:endtime=1419406911:gamedelta=363:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=89736:deathdnum=0:deathlev=14:maxlvl=14:hp=82:maxhp=83:deaths=1:deathdate=20141224:birthdate=20141224:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=petrified by a chickatrice corpse:conduct=1792:turns=19468:achieve=1024:nconducts=3:nachieves=1:realtime=14484:starttime=1419406918:endtime=1419448155:gamedelta=41237:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=1495:deathdnum=2:deathlev=5:maxlvl=5:hp=-10:maxhp=37:deaths=1:deathdate=20141225:birthdate=20141225:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a bolt of cold:conduct=3968:turns=1818:achieve=0:nconducts=5:nachieves=0:realtime=947:starttime=1419494273:endtime=1419495223:gamedelta=950:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=39140:deathdnum=0:deathlev=10:maxlvl=10:hp=0:maxhp=95:deaths=1:deathdate=20141225:birthdate=20141225:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gargoyle:conduct=3968:turns=14552:achieve=1024:nconducts=5:nachieves=1:realtime=10904:starttime=1419495231:endtime=1419513464:gamedelta=18233:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=20944:deathdnum=4:deathlev=5:maxlvl=10:hp=0:maxhp=56:deaths=1:deathdate=20141227:birthdate=20141227:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a hell hound:conduct=3712:turns=7314:achieve=0:nconducts=4:nachieves=0:realtime=4502:starttime=1419678536:endtime=1419716191:gamedelta=37655:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=57399:deathdnum=2:deathlev=7:maxlvl=10:hp=-2:maxhp=66:deaths=1:deathdate=20141228:birthdate=20141227:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=killed by a gelatinous cube:conduct=3840:turns=18163:achieve=1024:nconducts=4:nachieves=1:realtime=13206:starttime=1419716255:endtime=1419787047:gamedelta=70792:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=2270808:deathdnum=7:deathlev=-5:maxlvl=50:hp=346:maxhp=347:deaths=0:deathdate=20141231:birthdate=20141229:uid=5:role=Ran:race=Elf:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=1024:turns=43334:achieve=2047:nconducts=1:nachieves=11:realtime=67591:starttime=1419838527:endtime=1420045200:gamedelta=206673:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2515342:deathdnum=7:deathlev=-5:maxlvl=50:hp=136:maxhp=300:deaths=0:deathdate=20150103:birthdate=20141231:uid=5:role=Mon:race=Hum:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=2448:turns=36028:achieve=3583:nconducts=4:nachieves=11:realtime=43868:starttime=1420045271:endtime=1420274165:gamedelta=228894:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2276534:deathdnum=7:deathlev=-5:maxlvl=49:hp=210:maxhp=279:deaths=0:deathdate=20150104:birthdate=20150103:uid=5:role=Sam:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=1280:turns=38395:achieve=3583:nconducts=2:nachieves=11:realtime=43395:starttime=1420274625:endtime=1420407069:gamedelta=132444:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=1199780:deathdnum=1:deathlev=27:maxlvl=27:hp=258:maxhp=258:deaths=1:deathdate=20150111:birthdate=20150105:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=petrified by a cockatrice:conduct=1536:turns=46138:achieve=2050:nconducts=2:nachieves=2:realtime=53085:starttime=1420466437:endtime=1420971804:gamedelta=505367:gender0=Mal:align0=Cha:flags=0
+version=3.4.3:points=3429164:deathdnum=7:deathlev=-5:maxlvl=50:hp=218:maxhp=267:deaths=0:deathdate=20150116:birthdate=20150111:uid=5:role=Bar:race=Orc:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=3456:turns=54089:achieve=3583:nconducts=4:nachieves=11:realtime=68260:starttime=1420977142:endtime=1421444562:gamedelta=467420:gender0=Mal:align0=Cha:flags=32
+version=3.4.3:points=2865500:deathdnum=7:deathlev=-5:maxlvl=47:hp=400:maxhp=400:deaths=0:deathdate=20150119:birthdate=20150117:uid=5:role=Val:race=Dwa:gender=Mal:align=Law:name=mgv:death=ascended:conduct=2048:turns=38549:achieve=3583:nconducts=1:nachieves=11:realtime=53826:starttime=1421480609:endtime=1421681276:gamedelta=200667:gender0=Fem:align0=Law:flags=32
+version=3.4.3:points=11731:deathdnum=2:deathlev=5:maxlvl=8:hp=0:maxhp=53:deaths=1:deathdate=20150119:birthdate=20150119:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a gray unicorn:conduct=3976:turns=6641:achieve=0:nconducts=6:nachieves=0:realtime=2828:starttime=1421701566:endtime=1421704416:gamedelta=2850:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=2877:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=41:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a rothe:conduct=3976:turns=2041:achieve=0:nconducts=6:nachieves=0:realtime=3094:starttime=1421738623:endtime=1421741735:gamedelta=3112:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=9558:deathdnum=0:deathlev=4:maxlvl=6:hp=0:maxhp=56:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a Woodland-elf:conduct=3976:turns=5389:achieve=0:nconducts=6:nachieves=0:realtime=2765:starttime=1421741744:endtime=1421745095:gamedelta=3351:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=6280:deathdnum=2:deathlev=5:maxlvl=5:hp=28:maxhp=70:deaths=0:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=quit:conduct=3968:turns=4366:achieve=0:nconducts=5:nachieves=0:realtime=3049:starttime=1421745102:endtime=1421748153:gamedelta=3051:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=893:deathdnum=0:deathlev=3:maxlvl=4:hp=0:maxhp=36:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a brown mold:conduct=3976:turns=2039:achieve=0:nconducts=6:nachieves=0:realtime=762:starttime=1421748176:endtime=1421748941:gamedelta=765:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2282:deathdnum=2:deathlev=5:maxlvl=5:hp=-2:maxhp=59:deaths=1:deathdate=20150120:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3976:turns=1835:achieve=0:nconducts=6:nachieves=0:realtime=893:starttime=1421748958:endtime=1421749853:gamedelta=895:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=11176:deathdnum=0:deathlev=13:maxlvl=13:hp=-10:maxhp=41:deaths=1:deathdate=20150121:birthdate=20150120:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a wand:conduct=3976:turns=7112:achieve=0:nconducts=6:nachieves=0:realtime=4630:starttime=1421749861:endtime=1421846411:gamedelta=96550:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=159:deathdnum=0:deathlev=1:maxlvl=1:hp=14:maxhp=14:deaths=0:deathdate=20150121:birthdate=20150121:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=quit:conduct=4032:turns=166:achieve=0:nconducts=6:nachieves=0:realtime=199:starttime=1421846431:endtime=1421846632:gamedelta=201:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=6804:deathdnum=2:deathlev=5:maxlvl=6:hp=-1:maxhp=68:deaths=1:deathdate=20150124:birthdate=20150121:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a jaguar:conduct=3976:turns=3752:achieve=0:nconducts=6:nachieves=0:realtime=3581:starttime=1421846639:endtime=1422090230:gamedelta=243591:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=113905:deathdnum=0:deathlev=26:maxlvl=26:hp=84:maxhp=84:deaths=1:deathdate=20150127:birthdate=20150124:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=drowned in a pool of water by an electric eel:conduct=3720:turns=18464:achieve=1024:nconducts=5:nachieves=1:realtime=23801:starttime=1422090240:endtime=1422395519:gamedelta=305279:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=80743:deathdnum=0:deathlev=15:maxlvl=18:hp=-5:maxhp=84:deaths=1:deathdate=20150204:birthdate=20150130:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a giant mummy:conduct=3720:turns=17783:achieve=0:nconducts=5:nachieves=0:realtime=25745:starttime=1422624841:endtime=1423076735:gamedelta=451894:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=3591:deathdnum=2:deathlev=5:maxlvl=5:hp=-4:maxhp=61:deaths=1:deathdate=20150208:birthdate=20150204:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=killed by a soldier ant:conduct=3976:turns=3172:achieve=0:nconducts=6:nachieves=0:realtime=2767:starttime=1423076771:endtime=1423382793:gamedelta=306022:gender0=Mal:align0=Law:flags=0
+version=3.4.3:points=2903014:deathdnum=7:deathlev=-5:maxlvl=52:hp=311:maxhp=397:deaths=0:deathdate=20150627:birthdate=20150208:uid=5:role=Pri:race=Hum:gender=Mal:align=Law:name=mgv:death=ascended:conduct=2440:turns=37729:achieve=4095:nconducts=4:nachieves=12:realtime=86482:starttime=1423382814:endtime=1435429536:gamedelta=12046722:gender0=Mal:align0=Law:flags=32
+version=3.4.3:points=17192:deathdnum=0:deathlev=6:maxlvl=6:hp=0:maxhp=64:deaths=1:deathdate=20150627:birthdate=20150627:uid=5:role=Mon:race=Hum:gender=Mal:align=Neu:name=mgv:death=killed by a rabid rat, while frozen by a monster's gaze:conduct=3988:turns=7550:achieve=1024:nconducts=7:nachieves=1:realtime=7266:starttime=1435431361:endtime=1435438629:gamedelta=7268:gender0=Mal:align0=Neu:flags=32
+version=3.4.3:points=2765250:deathdnum=7:deathlev=-5:maxlvl=47:hp=264:maxhp=295:deaths=0:deathdate=20150701:birthdate=20150627:uid=5:role=Mon:race=Hum:gender=Mal:align=Cha:name=mgv:death=ascended:conduct=2436:turns=40262:achieve=4095:nconducts=4:nachieves=12:realtime=53850:starttime=1435438727:endtime=1435752162:gamedelta=313435:gender0=Mal:align0=Neu:flags=32
diff --git a/web/dash.css b/web/dash.css
new file mode 100644 (file)
index 0000000..8bd91e7
--- /dev/null
@@ -0,0 +1,95 @@
+html {
+       color: #DDD;
+       background-color: #000;
+       margin: 0;
+       padding: 0 2% 1%;
+       line-height: 1.5;
+}
+
+h2 {
+       text-align: center;
+       display: table;
+       white-space: nowrap;
+       margin: 0.5em;
+       text-transform: uppercase;
+       font-family: monospace;
+       font-size: 1.5em;
+       font-weight: 100;
+}
+
+h2:before,
+h2:after {
+       content: ' ';
+       display: table-cell;
+       position: relative;
+       top: 0.55em;
+       width: 48%;
+       border-top: 1px dashed #BBB;
+}
+
+h2:before {
+       right: 1.5%;
+}
+
+h2:after {
+       left: 1.5%;
+}
+
+#title {
+       text-align: center;
+}
+
+span[title] {
+       color: #F66;
+       font-family: monospace;
+       font-size: 1.25em;
+       margin-right: 1.5em;
+}
+
+
+span[title].done {
+       color: #7E7;
+}
+
+dl {
+       font-family: monospace;
+       font-size: 1.25em;
+       margin-top: 0;
+}
+
+dt {
+       font-weight: bold;
+       float: left;
+       clear: left;
+}
+
+dt:after {
+       content: ":";
+}
+
+dd {
+       float: left;
+       margin-left: 1em;
+}
+
+footer {
+       margin-top: 1em;
+       text-align: center;
+       clear: both;
+}
+
+a:link {
+       color: #66F;
+       text-decoration: none;
+}
+
+a:visited {
+       color: #84B;
+}
+
+@media (min-width: 500px) {
+       .cols {
+               -moz-columns: 2;
+               -webkit-columns: 2;
+       }
+}
diff --git a/web/dash.html b/web/dash.html
new file mode 100644 (file)
index 0000000..3131fc7
--- /dev/null
@@ -0,0 +1,132 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>NAO dashboard for NAME</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="dash.css">
+
+<h1 id="title">NAO dashboard for <a href="http://alt.org/nethack/plr.php?player=">NAME</a></h1>
+
+<div id="achievements">
+<h2>Achievements</h2>
+<span id="achieve_sokoban" title="Finished Sokoban">Sokoban</span>
+<span id="achieve_luckstone" title="Got the luckstone at the Mine's End">Luckstone</span>
+<span id="achieve_medusa" title="Killed Medusa">Medusa</span>
+<span id="achieve_bell" title="Got the Bell of Opening">Bell</span>
+<span id="achieve_gehennom" title="Reached Gehennom">Gehennom</span>
+<span id="achieve_candelabrum" title="Got the Candelabrum of Invocation">Candelabrum</span>
+<span id="achieve_book" title="Got the Book of the Dead">Book</span>
+<span id="achieve_invocation" title="Performed the Invocation">Invocation</span>
+<span id="achieve_amulet" title="Got the Amulet of Yendor">Amulet</span>
+<span id="achieve_endgame" title="Reached the Endgame">Endgame</span>
+<span id="achieve_astral" title="Reached the Astral Plane">Astral</span>
+<span id="achieve_ascended" title="Ascended">Ascended</span>
+</div>
+
+<div id="combos">
+<h2>Starting Combos</h2>
+<div class="cols">
+<span id="combo_arc_hum_law" title="">Arc-Hum-Law</span>
+<span id="combo_arc_hum_neu" title="">Arc-Hum-Neu</span>
+<span id="combo_arc_dwa_law" title="">Arc-Dwa-Law</span>
+<span id="combo_arc_gno_neu" title="">Arc-Gno-Neu</span>
+<br>
+
+<span id="combo_bar_hum_neu" title="">Bar-Hum-Neu</span>
+<span id="combo_bar_hum_cha" title="">Bar-Hum-Cha</span>
+<span id="combo_bar_orc_cha" title="">Bar-Orc-Cha</span>
+<br>
+
+<span id="combo_cav_hum_law" title="">Cav-Hum-Law</span>
+<span id="combo_cav_hum_neu" title="">Cav-Hum-Neu</span>
+<span id="combo_cav_dwa_law" title="">Cav-Dwa-Law</span>
+<span id="combo_cav_gno_neu" title="">Cav-Gno-Neu</span>
+<br>
+
+<span id="combo_hea_hum_neu" title="">Hea-Hum-Neu</span>
+<span id="combo_hea_gno_neu" title="">Hea-Gno-Neu</span>
+<br>
+
+<span id="combo_kni_hum_law" title="">Kni-Hum-Law</span>
+<br>
+
+<span id="combo_mon_hum_law" title="">Mon-Hum-Law</span>
+<span id="combo_mon_hum_neu" title="">Mon-Hum-Neu</span>
+<span id="combo_mon_hum_cha" title="">Mon-Hum-Cha</span>
+<br>
+
+<span id="combo_pri_hum_law" title="">Pri-Hum-Law</span>
+<span id="combo_pri_hum_neu" title="">Pri-Hum-Neu</span>
+<span id="combo_pri_hum_cha" title="">Pri-Hum-Cha</span>
+<span id="combo_pri_elf_cha" title="">Pri-Elf-Cha</span>
+<br>
+
+<span id="combo_ran_hum_neu" title="">Ran-Hum-Neu</span>
+<span id="combo_ran_hum_cha" title="">Ran-Hum-Cha</span>
+<span id="combo_ran_elf_cha" title="">Ran-Elf-Cha</span>
+<span id="combo_ran_gno_neu" title="">Ran-Gno-Neu</span>
+<span id="combo_ran_orc_cha" title="">Ran-Orc-Cha</span>
+<br>
+
+<span id="combo_rog_hum_cha" title="">Rog-Hum-Cha</span>
+<span id="combo_rog_orc_cha" title="">Rog-Orc-Cha</span>
+<br>
+
+<span id="combo_sam_hum_law" title="">Sam-Hum-Law</span>
+<br>
+
+<span id="combo_tou_hum_neu" title="">Tou-Hum-Neu</span>
+<br>
+
+<span id="combo_val_hum_law" title="">Val-Hum-Law</span>
+<span id="combo_val_hum_neu" title="">Val-Hum-Neu</span>
+<span id="combo_val_dwa_law" title="">Val-Dwa-Law</span>
+<br>
+
+<span id="combo_wiz_hum_neu" title="">Wiz-Hum-Neu</span>
+<span id="combo_wiz_hum_cha" title="">Wiz-Hum-Cha</span>
+<span id="combo_wiz_elf_cha" title="">Wiz-Elf-Cha</span>
+<span id="combo_wiz_gno_neu" title="">Wiz-Gno-Neu</span>
+<span id="combo_wiz_orc_cha" title="">Wiz-Orc-Cha</span>
+</div>
+</div>
+
+<div id="conducts">
+<h2>Conducts</h2>
+<span id="conduct_foodless" title="You have gone without food">Foodless</span>
+<span id="conduct_vegan" title="You have followed a strict vegan diet">Vegan</span>
+<span id="conduct_vegetarian" title="You have been vegetarian">Vegetarian</span>
+<span id="conduct_atheist" title="You have been an atheist">Atheist</span>
+<span id="conduct_weaponless" title="You have never hit with a wielded weapon">Weaponless</span>
+<span id="conduct_pacifist" title="You have been a pacifist">Pacifist</span>
+<span id="conduct_illiterate" title="You have been illiterate">Illiterate</span>
+<span id="conduct_genocideless" title="You have never genocided any monsters">Genocideless</span>
+<span id="conduct_polypileless" title="You have never polymorphed an object">Polypileless</span>
+<span id="conduct_polyselfless" title="You have never changed form">Polyselfless</span>
+<span id="conduct_wishless" title="You used no wishes">Wishless</span>
+<span id="conduct_artiwishless" title="You have not wished for any artifacts">Artiwishless</span>
+</div>
+
+<div id="unofficial_conducts">
+<h2>Unofficial conducts</h2>
+<span id="uconduct_survivor" title="You survived">Survivor</span>
+<span id="uconduct_boneless" title="You never used bones">Boneless</span>
+<span id="uconduct_minscore" title="You got the minimum possible score for your dungeon">Minscore</span>
+</div>
+
+<div id="numbers">
+<h2>Numbers</h2>
+<div class="cols">
+<dl>
+<dt>Time played<dd id="totalrealtime">
+<dt>Games<dd id="games">
+<dt>Ascensions<dd id="ascensions">
+<dt>Most HP<dd id="maxhp">
+<dt>Most points<dd id="maxpoints">
+<dt>Most conducts<dd id="maxconducts">
+<dt>Least turns<dd id="minturns">
+<dt>Least time<dd id="minrealtime">
+</dl>
+</div>
+</div>
+
+<footer><small><a href="https://git.ieval.ro/?p=nethack-naodash.git">Code repository</a> &bull; <a href="https://metacpan.org/release/NetHack-NAOdash">MetaCPAN release page</a> &bull; Send feedback and patches to <a href="mailto:marius@ieval.ro">marius@ieval.ro</a> or mgv @ <a href="https://freenode.net/">Freenode</a></small></footer>
This page took 0.02869 seconds and 4 git commands to generate.