Permalink
Browse files

Initial commit, not importing from darcs repo.

  • Loading branch information...
0 parents commit f5dadda41233c684706fab2aab973aa387f655ac Henzell committed Apr 25, 2008
Showing with 5,014 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +12 −0 TODO
  3. +103 −0 commands.txt
  4. +232 −0 commands/apt-new.pl
  5. +203 −0 commands/apt.pl
  6. +31 −0 commands/cdoplayers.pl
  7. +26 −0 commands/chars.py
  8. +14 −0 commands/cmdinfo.py
  9. +36 −0 commands/commands.txt
  10. +98 −0 commands/currLeader.pl
  11. +50 −0 commands/deathsby.py
  12. +69 −0 commands/deathsin.py
  13. +16 −0 commands/dump.pl
  14. +59 −0 commands/ftw.pl
  15. +55 −0 commands/gamesby.pl
  16. +32 −0 commands/ghostkills.py
  17. +29 −0 commands/help.pl
  18. +256 −0 commands/helper.pl
  19. +435 −0 commands/helper.py
  20. +308 −0 commands/helper.rb
  21. +20 −0 commands/hsn.rb
  22. +26 −0 commands/idle.pl
  23. +39 −0 commands/killsby.py
  24. +16 −0 commands/lastgame.py
  25. +39 −0 commands/lastlog.pl
  26. +21 −0 commands/lastlog.rb
  27. +52 −0 commands/learn.pl
  28. +27 −0 commands/learn/add.pl
  29. +35 −0 commands/learn/delete.pl
  30. +81 −0 commands/learn/edit.pl
  31. +156 −0 commands/learn/helper.pl
  32. +63 −0 commands/learn/query.pl
  33. +20 −0 commands/listgame.rb
  34. +274 −0 commands/listgameold.py
  35. +26 −0 commands/lsa.py
  36. +23 −0 commands/message/all_input.pl
  37. +57 −0 commands/message/helper.pl
  38. +35 −0 commands/message/messages.pl
  39. +44 −0 commands/message/tell.pl
  40. +115 −0 commands/players.pl
  41. +16 −0 commands/rc.pl
  42. +151 −0 commands/rng.pl
  43. +29 −0 commands/screensize.pl
  44. +32 −0 commands/seen.pl
  45. +275 −0 commands/sqlhelper.rb
  46. +71 −0 commands/stats.rb
  47. +87 −0 commands/streak.py
  48. +6 −0 commands/test.py
  49. +65 −0 commands/whereis.py
  50. +102 −0 commands/won.rb
  51. +90 −0 commands/wtf.py
  52. +8 −0 commands/xlogtest.py
  53. +13 −0 commands_ideas.txt
  54. +65 −0 game_parser.pl
  55. +439 −0 henzell.pl
  56. +106 −0 launch_command.pl
  57. +13 −0 milestone_ideas.txt
  58. +210 −0 sqllog.pl
@@ -0,0 +1,3 @@
+nohup.*
+_darcs/
+t/
12 TODO
@@ -0,0 +1,12 @@
+* Have greensnark add realtime, possibly also number of monsters in sight, to each where file.
+
+* PM support.
+
+* doy (probably also other people) milestone idea: when HP drops below a certain percent (say, 10%).. probably also a minimum level cap so the milestone file doesn't get too large.
+
+* Message-leaving system needs some improvements before it can be called done
+ - really needs PM support
+ - limit of say, 5 messages
+ - when we get a seendb, limit message-target to someone who is in the seendb
+ - probably need to make sure the target is identified to nickserv as well
+
@@ -0,0 +1,103 @@
+ WRITING NEW HENZELL COMMANDS
+--------------------------------------------------------------------------------
+Henzell effectively accepts new commands written in any language. This is because commands are simply UNIX programs. Of course, the languages are limited to what the server is configured for.
+
+--------
+SYNOPSIS
+--------
+
+Someone types !command. Henzell forks and execs the script associated with that command. Henzell passes some relevant arguments and receives the command's output on STDOUT. That output is sent to the channel.
+
+-----
+INPUT
+-----
+
+Henzell passes five arguments to the command. Note that any single quotes are removed from the fields for security reasons. Consider if a player typed:
+
+!arbitrary_command '; rm -rf *; echo '
+
+If the single quotes were not removed, this would cause some (ahem) headaches.
+
+ARGUMENT THE FIRST
+
+What Henzell thinks the command is really targeting. Most commands should look only at this argument. This argument is for commands that request information about a player. If the speaker passed no arguments to your command, the speaker's nick is used in place. This argument is guaranteed to match the following regex:
+
+/^[a-zA-Z0-9]*?[a-zA-Z]+$/
+
+So in plain English: any amount of alphanumeric characters followed by at least one alphabetical character. (This is because Crawl does not support names ending with numbers, so they're stripped off -- consider aristotle73 typing "!gamesby".. the command should target his account "aristotle")
+
+ARGUMENT THE SECOND
+
+The person who is issuing the command. I'm not sure if it's in the IRC RFC that nicks cannot contain single quotes, but in either case any single quotes will be stripped off the nick.
+
+ARGUMENT THE THIRD
+
+The verbatim command exactly as the user typed it, minus single quotes. If you need to look at just the arguments that the user provided, strip off the first word-thing (and probably a space, because it's required for commands) like so (again, Perl):
+
+$ARGV[2] =~ s/^\S+ //;
+
+ARGUMENT THE FOURTH
+
+This is used to tell the command whether or not to print help information. Ordinarily this is a simple empty string. However, if !help !yourcommand is used, this becomes 1. In this case you should print help text and exit. Note that you have to be alert for multiple commands in the same file. Generally you figure out which command the person is using, and then see if help mode is on. You do not need to put the command name in the output; !help does that for you. The !help command simply passes its own arguments along, with three exceptions: the fourth argument (which was the empty string) becomes 1, the third argument (verbatim text the user typed) has the following substitution applied to it (to make it easy for command authors):
+
+$ARGV[2] =~ s/^!help\s+//i;
+
+and the third change is $ARGV[2] has an exclamation point prepended to it if there is not one already. (this makes it so "!help stats" does the right thing even if stats is in a multi-command file)
+
+ARGUMENT THE FIFTH
+
+This is used to tell the command whether the command came from the channel, a private message, or a notice. For all intents and purposes, PMs and notices should be treated equally. But who knows, you might have some use. This argument is empty, '', if the command came from the channel. This argument is '1' if it was a PM, or '2' if it was a notice. The following test could be used to exit if the command only works if it was issued in the channel (probably done the same in no_pm() in your language's helper library):
+
+if ($ARGV[4])
+{
+ printf "This command cannot be used in a %s.\n",
+ $ARGV[4] eq '1' ? 'private message' : 'notice';
+ exit;
+}
+
+------
+OUTPUT
+------
+
+Henzell currently accepts two forms of output. The exit code of the script and STDERR are (mostly) ignored. The STDERR of any script is logged.
+
+Henzell truncates all output to 400 characters (after any processing). Future versions might support longer lines which are broken up before outputting (a la Rodney3).
+
+NORMAL OUTPUT
+
+This is to be used for most commands. Simply print the output to STDOUT. Henzell currently only looks at the first line of output, but in the future he may pay attention to subsequent lines. Henzell simply echoes this output to whatever medium he received the command over (whether it be a channel or, in the future, a private message or notice)
+
+LOGFILE OUTPUT
+
+This is used for when you want Henzell to "pretty print" a logfile line. This should be used for any command that displays a logfile line, so that consistency is maintained. To use the logfile output mode you print to STDOUT just like in normal output mode, except you begin with an "\n". Henzell will then look at the next line and try to parse it as a logfile entry. Logfile entries begin and end with a colon. Henzell will strip off any text before the first colon in the line and prepend it to the pretty-printed logfile entry. Similarly for any text after the last colon. This means you cannot include a colon in the pre-text or post-text. Note that in the new 0.2.x logfile format, you have to specifically wrap the xlogline in colons.
+
+------------
+COMMON USAGE
+------------
+
+Unfortunately since Henzell commands are external scripts, they cannot make use of standard utility functions (like finding the games for a player or building a more suitable data structure from a logfile line). However, for some languages (currently Perl, Python, and Ruby) we have helper scripts that contain useful utility functions and constant definitions. Use these whenever possible (again for consistency, but also because that's just a good coding practice). A fringe benefit of writing commands this way (as external programs) is that they're very easy to test. The real reason commands are external programs is because they're easier to update (no need to reboot Henzell) and being able to be written in multiple languages is a boon for getting new functionality for Henzell.
+
+Anyway, the helper scripts should make writing new commands very painless. Here's a somewhat simplified version of !hsn in Perl.
+
+#!/usr/bin/perl
+do 'commands/helper.pl';
+print "List a player's high scoring game." and exit if $ARGV[3];
+my $nick = shift;
+my $games_ref = games_by($nick);
+my $hsn_ref = (sort { $b->{score} <=> $a->{score} } @$games_ref)[0];
+print "\n" . munge_game($hsn_ref);
+
+If you're going to write new helper scripts (or simply extend an existing helper script) please use the same external interface as used in other helper scripts (except where it makes sense to diverge.. for example the Perl helper script uses references where possible to save time and space in passing things around).
+
+-----------------------
+CAVEATS FOR CONSISTENCY
+-----------------------
+
+1. When writing a command, where possible use the same messages as other commands (for example, "No games for NICK." instead of "NICK has played no games.").
+2. When printing out the resulting nickname ("Eidolos has played X games..."), where possible use a nickname directly from the logfile. So (in Perl), use $games[0]{name} not $nick (which would be from user input). This is so "!gamesby EIDOLOS" ends up with the correct case. (Rodney in #nethack does not do this: most logfile commands have the player name in lowercase regardless of the actual capitalization). Yes this means if you're doing an victory-based command you may have to look at all games (not just victories.. but you were going to anyway, to distinguish between "No games for NICK." versus "No victories for NICK.", right?).
+3. If you're printing a floating point number, please use a printf (or similar) so that the appropriate amount of trailing zeros are included (so printf '%.2f%%', 100*$vics/$games instead of print int(10000*$vics/$games)/100 -- the former will always print two digits after the decimal point, the latter will print zero, one, or two). The exact precision used isn't much of an issue, though (but prefer two places after the decimal.. any more and it gets a bit clunky).
+4. Output should (almost) always begin with a capital letter. One exception is when output begins with a player name and that player name is not capitalized.
+5. If you're printing a frequency table (such as the output of !won), sort based on frequency (whether ascending or descending) and then by the item name (ascending). In Perl, that's:
+ sort { $won{$b} <=> $won{$a} || $a cmp $b } @races;
+6. If your command takes a player name and additional arguments, then those additional arguments should be formed such that an argument cannot be confused for a nickname. For example, let's pretend the !won command is extended to accept a race name. So a player can type !won NICK RACE. Now suppose there's someone with the nickname "Human" on akrasiac. What should "!won Human" produce -- the human victories of the person typing the command, or all the victories of this Human account? The answer is the former. The RACE argument should (for example) be prepended with a - so it's completely unambiguous. As a guideline, !command <args> should produce the exact same results as !command SPEAKERNICK <args>. Note that since Crawl nicks cannot contain only numbers so something like !game_number 10 is unambiguous (whereas in NetHack it isn't, so Rodney3 requires the number argument be prepended with a #)
+
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+do 'commands/helper.pl';
+help("Looks up aptitudes for specified race/skill combination.");
+
+our (%fullDB, %transRaceDB, %skillList, %bestApt, %dracColours, @gameOrder);
+sub buildTransDB # {{{
+{
+ %dracColours = (red=>"SP_RED_DRACONIAN", white=>"SP_WHITE_DRACONIAN",
+ green=>"SP_GREEN_DRACONIAN", yellow=>"SP_YELLOW_DRACONIAN",
+ grey=>"SP_GREY_DRACONIAN", black=>"SP_BLACK_DRACONIAN",
+ purple=>"SP_PURPLE_DRACONIAN", mottled=>"SP_MOTTLED_DRACONIAN",
+ pale=>"SP_PALE_DRACONIAN");
+ @gameOrder = ("SK_FIGHTING", "SK_SHORT_BLADES", "SK_LONG_BLADES", "SK_AXES",
+ "SK_MACES_FLAILS", "SK_POLEARMS", "SK_STAVES", "SK_UNARMED_COMBAT",
+ "SK_THROWING", "SK_SLINGS", "SK_BOWS", "SK_CROSSBOWS", "SK_DARTS",
+ "SK_ARMOUR", "SK_DODGING", "SK_STEALTH", "SK_STABBING", "SK_SHIELDS", "SK_TRAPS_DOORS",
+ "SK_SPELLCASTING", "SK_CONJURATIONS", "SK_ENCHANTMENTS", "SK_SUMMONINGS",
+ "SK_NECROMANCY", "SK_TRANSLOCATIONS", "SK_TRANSMIGRATION", "SK_DIVINATIONS",
+ "SK_FIRE_MAGIC", "SK_ICE_MAGIC", "SK_AIR_MAGIC", "SK_EARTH_MAGIC", "SK_POISON_MAGIC",
+ "SK_INVOCATIONS", "SK_EVOCATIONS");
+ %skillList = ("SK_FIGHTING"=>"Fighting", "SK_SHORT_BLADES"=>"Short",
+ "SK_LONG_BLADES"=>"Long", "SK_AXES"=>"Axes", "SK_MACES_FLAILS"=>"Maces",
+ "SK_POLEARMS"=>"Polearms", "SK_STAVES"=>"Staves", "SK_SLINGS"=>"Slings",
+ "SK_BOWS"=>"Bows", "SK_CROSSBOWS"=>"Crossbows", "SK_DARTS"=>"Darts",
+ "SK_THROWING"=>"Throw", "SK_ARMOUR"=>"Armour",
+ "SK_DODGING"=>"Dodge", "SK_STEALTH"=>"Stealth", "SK_STABBING"=>"Stab",
+ "SK_SHIELDS"=>"Shields", "SK_TRAPS_DOORS"=>"Traps",
+ "SK_UNARMED_COMBAT"=>"Unarmed", "SK_SPELLCASTING"=>"Spellcasting",
+ "SK_CONJURATIONS"=>"Conj", "SK_ENCHANTMENTS"=>"Ench",
+ "SK_SUMMONINGS"=>"Summ", "SK_NECROMANCY"=>"Nec",
+ "SK_TRANSLOCATIONS"=>"Tloc", "SK_TRANSMIGRATION"=>"Tmig",
+ "SK_DIVINATIONS"=>"Div", "SK_FIRE_MAGIC"=>"Fire", "SK_ICE_MAGIC"=>"Ice",
+ "SK_AIR_MAGIC"=>"Air", "SK_EARTH_MAGIC"=>"Earth",
+ "SK_POISON_MAGIC"=>"Poison", "SK_INVOCATIONS"=>"Inv",
+ "SK_EVOCATIONS"=>"Evo");
+ %transRaceDB = (Hu=>"SP_HUMAN",
+ HE=>"SP_HIGH_ELF",
+ GE=>"SP_GREY_ELF",
+ DE=>"SP_DEEP_ELF",
+ SE=>"SP_SLUDGE_ELF",
+ MD=>"SP_MOUNTAIN_DWARF",
+ Ha=>"SP_HALFLING",
+ HO=>"SP_HILL_ORC",
+ Ko=>"SP_KOBOLD",
+ Mu=>"SP_MUMMY",
+ Na=>"SP_NAGA",
+ Gn=>"SP_GNOME",
+ Og=>"SP_OGRE",
+ Tr=>"SP_TROLL",
+ OM=>"SP_OGRE_MAGE",
+ Dr=>"SP_BASE_DRACONIAN",
+ Ce=>"SP_CENTAUR",
+ DG=>"SP_DEMIGOD",
+ Sp=>"SP_SPRIGGAN",
+ Mi=>"SP_MINOTAUR",
+ DS=>"SP_DEMONSPAWN",
+ Gh=>"SP_GHOUL",
+ Ke=>"SP_KENKU",
+ Mf=>"SP_MERFOLK",
+ Vp=>"SP_VAMPIRE");
+} # }}}
+sub parseSkillsFile # {{{
+{
+ open my $infile, "<", "db.cc";
+ my $currRace;
+ while(<$infile>)
+ {
+ # Determine race
+ if(m#\{\s*// ([A-Z\(\)0-9_]+)#)
+ {
+ $currRace=$1 if(m#\{\s*// ([A-Z\(\)0-9_]+)#);
+ }
+
+ # Determine attribute and aptitude
+ if(m#^\s*([ 0-9-\+\(\)/\*]+),\s+// ([A-Z0-9_]+)#)
+ {
+ my $evaled = (eval $1);
+ if( defined($currRace) ) # This figures out what the best
+ { # aptitudes are.
+ if( defined($bestApt{$2}) ) # Check if the old value is better
+ {
+ $bestApt{$2}=$evaled if($evaled < $bestApt{$2});
+ }
+ else # If there is no old value, just store
+ {
+ $bestApt{$2}=$evaled;
+ }
+ $fullDB{$currRace}{$2}=$evaled if( defined($currRace) );
+ }
+ }
+ }
+} # }}}
+
+# Prepare DB's
+buildTransDB();
+parseSkillsFile();
+$_ = $ARGV[2];
+
+chomp;
+s/^!apt\s+(.*)$/$1/;
+my ($race, $skill, $sort, $colour);
+my @args = split / /;
+
+# parse arguments
+foreach (@args)
+{
+ if(/r=([A-Za-z]{2})/) {$race=$1;} # -race=Sp
+ elsif(/s=([A-Z_]*)/) {$skill=$1;} # -skill=SK_DODGING
+ elsif(/so=([a-z]*)/) {$sort=$1;} # -sort=alph
+ elsif(/c=([a-z]*)/) {$colour=$1;} # -colour=red
+}
+
+if( defined($race) ) # atleast $race is defined
+{
+ if( defined($skill) ) # $race && $skill are defined {{{
+ {
+ if( defined($colour) ) # $race && $skill && $colour are defined
+ {
+ # checking for invalid arguments
+ unless( defined($transRaceDB{$race}) ) { print "Not a valid race.\n"; next; }
+ unless( defined($skillList{$skill}) ) { print "Not a valid skill.\n"; next; }
+ unless( defined($dracColours{$colour})) { print "Non valid colour.\n"; next; }
+
+ # Check for dracs
+ if($race eq "Dr")
+ {
+ my $fullRace = $dracColours{$colour};
+ print "Dr[$colour]($skill)=", $fullDB{$fullRace}{$skill};
+ print "!" if($fullDB{$fullRace}{$skill} == $bestApt{$skill});
+ print "\n";
+ } else { print "Only draconians get colours.\n"; next; }
+ }
+ else
+ {
+ # checking for invalid arguments
+ unless( defined($transRaceDB{$race}) ) { print "Not a valid race.\n"; next; }
+ unless( defined($skillList{$skill}) ) { print "Not a valid skill.\n"; next; }
+
+ my $fullRace = $transRaceDB{$race};
+ print "$race($skill)=", $fullDB{$fullRace}{$skill};
+ print "!" if($fullDB{$fullRace}{$skill} == $bestApt{$skill});
+ print "\n";
+ }
+ } # }}}
+ else # $race is defined {{{
+ {
+ # valid race
+ unless( defined($transRaceDB{$race}) ) { print "Not a valid race.\n"; next; }
+
+ if( defined($colour) ) # -colour=red{{{
+ {
+ unless($race eq "Dr") { print "Only draconians get colours.\n"; next;}
+ unless( defined($dracColours{$colour})) { print "Not a valid colour.\n"; next; }
+
+ my $fullRace = $dracColours{$colour};
+ my %tempDB = %{ $fullDB{$fullRace} };
+ my ($ref, @tempVar);
+
+ if( defined($sort) && $sort eq "alpha" ) {
+ @tempVar = (sort keys %tempDB);
+ $ref = \@tempVar;
+ }
+ else {
+ $ref = \@gameOrder;
+ }
+
+ my $output;
+ foreach my $k (@$ref)
+ {
+ my $v = $tempDB{$k};
+ unless($k eq "SK_UNUSED_1" || $k eq "undefined")
+ {
+ $output .= $skillList{$k} . ":" . $v;
+ $output .= "!" if($v == $bestApt{$k});
+ $output .= ", ";
+ }
+ }
+ chop $output; chop $output;
+ print "$output\n";
+ } # }}}
+ else
+ {
+ # Do reference magic here
+ my $fullRace = $transRaceDB{$race};
+ my %tempDB = %{ $fullDB{$fullRace} };
+ my ($output, $ref, @tempVar);
+
+ if( defined($sort) && $sort eq "alpha" ) {
+ @tempVar = (sort keys %tempDB);
+ $ref = \@tempVar;
+ }
+ else {
+ $ref = \@gameOrder;
+ }
+ foreach my $k (@$ref)
+ {
+ my $v = $tempDB{$k};
+ unless($k eq "SK_UNUSED_1" || $k eq "undefined")
+ {
+ $output .= $skillList{$k} . ":" . $v;
+ $output .= "!" if($v == $bestApt{$k});
+ $output .= ", ";
+ }
+ }
+ chop $output; chop $output;
+ print "$output\n";
+ }
+ } # }}}
+}
+elsif( defined($skill) ) # only $skill is defined {{{
+{
+ unless( defined($skillList{$skill}) ) { print "Not a valid skill.\n"; next; }
+
+ my $output;
+ foreach my $k (sort keys %transRaceDB)
+ {
+ my $v = $transRaceDB{$k};
+ $output .= "$k=";
+ $output .= $fullDB{$v}{$skill};
+ $output .= "!" if($bestApt{$skill}==$fullDB{$v}{$skill});
+ $output .= ", ";
+ }
+ chop $output; chop $output;
+ print "$output\n";
+} # }}}
+else # !($skill && $race) {{{
+{
+ print "Neither the s nor the r parameters have been set.\n";
+} # }}}
Oops, something went wrong.

0 comments on commit f5dadda

Please sign in to comment.