From 01ba3ddc757514e3474b1c79855de5fea5da1445 Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Thu, 2 Jul 2015 13:16:09 +0300 Subject: [PATCH 1/1] Initial commit --- Changes | 4 + MANIFEST | 15 +++ Makefile.PL | 28 ++++ README | 44 +++++++ app.psgi | 13 ++ lib/App/NAOdash.pm | 162 +++++++++++++++++++++++ lib/App/Web/NAOdash.pm | 148 +++++++++++++++++++++ lib/NetHack/NAOdash.pm | 286 +++++++++++++++++++++++++++++++++++++++++ naodash | 48 +++++++ t/NetHack-NAOdash.t | 27 ++++ t/perlcritic.t | 10 ++ t/perlcriticrc | 36 ++++++ t/xlogfile | 85 ++++++++++++ web/dash.css | 95 ++++++++++++++ web/dash.html | 132 +++++++++++++++++++ 15 files changed, 1133 insertions(+) create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 Makefile.PL create mode 100644 README create mode 100644 app.psgi create mode 100644 lib/App/NAOdash.pm create mode 100644 lib/App/Web/NAOdash.pm create mode 100644 lib/NetHack/NAOdash.pm create mode 100755 naodash create mode 100644 t/NetHack-NAOdash.t create mode 100644 t/perlcritic.t create mode 100644 t/perlcriticrc create mode 100644 t/xlogfile create mode 100644 web/dash.css create mode 100644 web/dash.html diff --git a/Changes b/Changes new file mode 100644 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 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 index 0000000..fb9e176 --- /dev/null +++ b/Makefile.PL @@ -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 ', + 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 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 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 index 0000000..78428a3 --- /dev/null +++ b/lib/App/NAOdash.pm @@ -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 script, a command-line +interface to L. + +It defines two functions: + +=over + +=item B(I<$stats>) + +Takes the result of B or B 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(I<$user_or_path>) + +Analyzes the xlogfile for the given user / at the given path, passes +the result through B 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, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 index 0000000..a9d0482 --- /dev/null +++ b/lib/App/Web/NAOdash.pm @@ -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. + +It handles URLs of the form C, where I 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, that is false +by default. The result will be returned as HTML is I is false, +as JSON if I is true. + +=head1 SEE ALSO + +L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 index 0000000..af574ef --- /dev/null +++ b/lib/NetHack/NAOdash.pm @@ -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{
(.*)
}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, which are flags +(booleans) and B which are integers. + +The B are tracked across all games. That is, a B will +be true in the statistics if it is true in at least one game. Except +for B in the I category, only games that end in +an ascension are considered for awarding a B. + +The B, sorted by category, are: + +=over + +=item B + +These start with C 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 + +These look like C 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 is true if the user ascended at least one +gnomish caveman. + +=item B + +These start with C 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 + +These start with C and represent conducts that are not +officially tracked by the game. + + uconduct_survivor uconduct_bones uconduct_minscore + +=back + +The numbers are: + +=over + +=item B + +The total time spent playing NetHack on NAO, in seconds. + +=item B + +The number of games played. + +=item B + +The number of games played that ended in an ascension. + +=item B + +The highest maxHP at the end of an ascension. + +=item B + +The highest score obtained at the end of an ascension. + +=item B + +The maximum number of conducts at the end of an ascension. + +=item B + +The minimum turns across ascended games. + +=item B + +The minimum realtime across ascended games, in seconds. + +=back + +This module exports two functions: + +=over + +=item B(I<@lines>) + +=item B(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 +that are true and C<< %{$result->{numbers}} >> is a hash of +B. + +=item B(I<$nao_username>) + +Retrieves the xlogfile of a user from NAO and gives it to +B. Dies if no xlogfile is found or if the server cannot +be contacted. + +=back + +=head1 SEE ALSO + +L, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 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. 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 library directly. + +=head1 SEE ALSO + +L, L, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 index 0000000..7b5019a --- /dev/null +++ b/t/NetHack-NAOdash.t @@ -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 index 0000000..79e93dc --- /dev/null +++ b/t/perlcritic.t @@ -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 index 0000000..5815f07 --- /dev/null +++ b/t/perlcriticrc @@ -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 index 0000000..cc126a4 --- /dev/null +++ b/t/xlogfile @@ -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 index 0000000..8bd91e7 --- /dev/null +++ b/web/dash.css @@ -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 index 0000000..3131fc7 --- /dev/null +++ b/web/dash.html @@ -0,0 +1,132 @@ + + +NAO dashboard for NAME + + + +

NAO dashboard for NAME

+ +
+

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
+
Games
+
Ascensions
+
Most HP
+
Most points
+
Most conducts
+
Least turns
+
Least time
+
+
+
+ + -- 2.39.2