diff --git a/cmd/roll.cc b/cmd/roll.cc
index 991a185..b1207e5 100644
--- a/cmd/roll.cc
+++ b/cmd/roll.cc
@@ -1,6 +1,6 @@
 /*
  * Lachesis, an IRCRPG combat engine - Dice roller interface
- * Copyright 2003-2004 M. Dennis
+ * Copyright 2003-2010 M. Dennis
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,8 +31,6 @@
 #include "../ircint.h"
 #include "../config.h"
 
-static char* id="@(#) $Id: roll.cc,v 1.1.1.1 2004/01/16 07:28:15 lachesis Exp $";
-
 extern CmdOpts options;
 extern char* irc_curchan;
 
@@ -48,9 +46,9 @@ void Cmd_roll_Init()
 
 void Cmd_Roll_Root(void *ticket, int auth, const char *str)
 {
-  unsigned long count, magnitude;
-  long floor;
-  char tstr[32];
+  unsigned long magnitude, base;
+  long count, floor, keep;
+  char tstr[32], sep[32];
   const char *temp, *ptr = str;
 #ifdef RPGSERV
 #ifndef ALLOW_ANY_TO_ROLL
@@ -62,15 +60,17 @@ void Cmd_Roll_Root(void *ticket, int auth, const char *str)
 #endif
 #endif
   if (str==NULL||!*str)
-    Auth_CmdResult(ticket, auth, "Usage: roll [#]d#[{+#|-#}]");
+    Auth_CmdResult(ticket, auth, "Usage: roll [#]d#[{+#|-#}][b#][{h#|l#}]");
   else {
+    Util_SepTo(sep, 32, &ptr, ' ');
+    ptr = sep;
     Util_SepTo(tstr, 32, &ptr, 'd');
     if (ptr==NULL) {
       Auth_CmdResult(ticket, auth, "Unrecognized roll format.");
       return ;
     }
     if (*tstr) {
-      if (*tstr<'0'||*tstr>'9') {
+      if (tstr[0] < '0' || tstr[0] > '9') {
 	Auth_CmdResult(ticket, auth, "Unrecognized roll format.");
 	return ;
       } else
@@ -86,7 +86,8 @@ void Cmd_Roll_Root(void *ticket, int auth, const char *str)
 	return ;
       }
       magnitude = strtoul(ptr, NULL, 10);
-      Cmd_Roll_DoRoll(ticket, auth, count, magnitude, 1);
+      floor = 0;
+      //Cmd_Roll_DoRoll(ticket, auth, count, magnitude, 1);
     } else {
       Util_SepTo(tstr, 32, &ptr, *temp);
       if (tstr[0]<'0'||tstr[0]>'9'||ptr[0]<'0'||ptr[0]>'9') {
@@ -95,8 +96,29 @@ void Cmd_Roll_Root(void *ticket, int auth, const char *str)
       }
       magnitude = strtoul(tstr, NULL, 10);
       floor = strtol(ptr-1, NULL, 10);
-      Cmd_Roll_DoRoll(ticket, auth, count, magnitude, 1+floor);
+      //Cmd_Roll_DoRoll(ticket, auth, count, magnitude, 1+floor);
+    }
+    Util_SepTo(tstr, 32, &ptr, 'b');
+    if (ptr==NULL) {
+      base = 10;
+      ptr = tstr;
+    } else
+      base = strtoul(ptr, NULL, 10);
+    temp = strchr(ptr, 'h');
+    if (temp==NULL)
+      temp = strchr(ptr, 'l');
+    if (temp==NULL)
+      keep = 0;
+    else {
+      if (temp[1]<'0'||temp[1]>'9') {
+	Auth_CmdResult(ticket, auth, "Unrecognized roll format.");
+	return;
+      }
+      keep = strtol(temp+1, NULL, 10);
+      if (temp[0]=='l')
+	keep=-keep;
     }
+    Cmd_Roll_DoRoll(ticket, auth, count, magnitude, 1+floor, base, keep, str);
   }
 }
 
@@ -135,18 +157,19 @@ void Cmd_WRoll_Root(void *ticket, int auth, const char *str)
       return ;
     }
     threshold = strtoul(ptr, NULL, 10);
-    Cmd_WRoll_DoRoll(ticket, auth, count, threshold);
+    Cmd_WRoll_DoRoll(ticket, auth, count, threshold, str);
   }
 }
 
-void Cmd_Roll_DoRoll(void *ticket, int auth, unsigned long count, 
-		     unsigned long magnitude, long floor)
+void Cmd_Roll_DoRoll(void *ticket, int auth, long count, 
+		     unsigned long magnitude, long floor,
+		     unsigned long base, long keep, const char *str)
 {
   unsigned long loop, temp;
   long *rolls;
   char **lfmt;
 
-  if (count==0||count>DICE_MAX) {
+  if (count<=0||count>DICE_MAX) {
     Auth_CmdResult(ticket, auth, "Invalid count.");
     return ;
   }
@@ -154,17 +177,82 @@ void Cmd_Roll_DoRoll(void *ticket, int auth, unsigned long count,
     Auth_CmdResult(ticket, auth, "Invalid magnitude.");
     return ;
   }
+  if (keep!=0 && (keep>=count || keep<=-count)) {
+    Auth_CmdResult(ticket, auth, "Invalid keep.");
+    return;
+  }
+  if (base!=10) {
+    //This is required for Maid RPG; specifically base 6
+    //Try to recode the numbers read meaningfully
+    unsigned newmag, newfloor, exp;
+    bool sign=false;
+    if (base>10 || base<2 || base%2) {
+      Auth_CmdResult(ticket, auth, "Invalid base.");
+      return ;
+    }
+    for (newmag=0,exp=1;magnitude>=base;exp*=base) {
+      newmag += magnitude % 10 % base * exp;
+      magnitude /= 10;
+    }
+    if (magnitude==0 && newmag==0)
+      newmag = exp;
+    else
+      newmag += magnitude % base * exp;
+    if (floor<0) {
+      sign=true;
+      floor=-floor;
+    }
+    for (newfloor=0,exp=1;floor>=base;exp*=base) {
+      newfloor += floor % 10 % base * exp;
+      floor /= 10;
+    }
+    if (floor==0 && newfloor==0)
+      newfloor = exp;
+    else
+      newfloor += floor % base * exp;
+    magnitude = newmag;
+    if (sign)
+      floor=-newfloor;
+    else
+      floor=newfloor;
+  }
   if (!Random_Roll(count, magnitude, floor, &rolls)) {
     Auth_CmdResult(ticket, auth, "Error performing dice roll.");
     return ;
   }
 
+  if (base!=10)
+    for (int c=0;c<(count>1?count+1:1);c++) {
+      long temp, exp;
+      unsigned long mag;
+      bool sign=false;
+      //Flooring is done a little differently here
+      if (--rolls[c]<0) {
+	sign=true;
+	rolls[c]=-rolls[c];
+      }
+      for (temp=0,exp=1,mag=magnitude;mag>1;exp*=10,mag/=base) {
+	temp += (rolls[c] % base + 1) * exp;
+	rolls[c] /= base;
+      }
+      rolls[c] = sign ? -temp : temp;
+    }
+  if (keep!=0) {
+    Util_heapsort(rolls+1, count);
+    rolls[0] = 0;
+    if (keep<0)
+      for (int k=0;k>keep;k--)
+	rolls[0] += rolls[1-k];
+    else
+      for (int k=0;keep>k;k++)
+	rolls[0] += rolls[count-k];
+  }
   switch(count) {
   case 1:
-    Cmd_Roll_Print(ticket, auth, Util_Format("roll is %d", rolls[0]));
+    Cmd_Roll_Print(ticket, auth, Util_Format("%s roll is %d", str, rolls[0]));
     break;
   case 2:
-    Cmd_Roll_Print(ticket, auth, Util_Format("roll is %d: %d and %d",
+    Cmd_Roll_Print(ticket, auth, Util_Format("%s roll is %d: %d and %d", str,
 					     rolls[0], rolls[1], rolls[2]));
     break;
   default:
@@ -180,17 +268,18 @@ void Cmd_Roll_DoRoll(void *ticket, int auth, unsigned long count,
       strcat(lfmt[0], lfmt[loop]);
       free(lfmt[loop]);
     }
-    Cmd_Roll_Print(ticket, auth, Util_Format("roll is %d: %s%d and %d",
-					     rolls[0], lfmt[0], 
+    Cmd_Roll_Print(ticket, auth, Util_Format("%s roll is %d: %s%d and %d",
+					     str, rolls[0], lfmt[0], 
 					     rolls[count-1], rolls[count])
 		   );
     delete [] lfmt[0];
     delete [] lfmt;
   }
+  delete [] rolls;
 }
 
 void Cmd_WRoll_DoRoll(void *ticket, int auth, unsigned long count, 
-		      unsigned long threshold)
+		      unsigned long threshold, const char *str)
 {
   unsigned long loop, temp;
   long *rolls;
@@ -212,27 +301,30 @@ void Cmd_WRoll_DoRoll(void *ticket, int auth, unsigned long count,
   switch(count) {
   case 1:
     if (rolls[0]>0)
-      Cmd_WRoll_Print(ticket, auth, Util_Format("succeeded: %d", rolls[1]));
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s succeeded: %d", str,
+						rolls[1]));
     else if (rolls[0]==0)
-      Cmd_WRoll_Print(ticket, auth, Util_Format("failed: %d", rolls[1]));
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s failed: %d", str,
+						rolls[1]));
     else
-      Cmd_WRoll_Print(ticket, auth, "botched it!");
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s botched it!", str));
     break;
   case 2:
     if (rolls[0]>1)
-      Cmd_WRoll_Print(ticket, auth, Util_Format("had %d successes: %d and %d",
-						rolls[0], rolls[1], rolls[2]));
+      Cmd_WRoll_Print(ticket, auth,
+		      Util_Format("%s had %d successes: %d and %d", str,
+				  rolls[0], rolls[1], rolls[2]));
     else if (rolls[0]==1)
       Cmd_WRoll_Print(ticket, auth, 
-		      Util_Format("succeeded once: %d and %d", rolls[1],
-				  rolls[2])
+		      Util_Format("%s succeeded once: %d and %d", str,
+				  rolls[1], rolls[2])
 		      );
     else if (rolls[0]==0)
-      Cmd_WRoll_Print(ticket, auth, Util_Format("failed: %d and %d", rolls[1],
-						rolls[2]));
-    else
-      Cmd_WRoll_Print(ticket, auth, Util_Format("botched it: %d and %d",
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s failed: %d and %d", str,
 						rolls[1], rolls[2]));
+    else
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s botched it: %d and %d",
+						str, rolls[1], rolls[2]));
     break;
   default:
     lfmt = new char*[count-1];
@@ -249,26 +341,29 @@ void Cmd_WRoll_DoRoll(void *ticket, int auth, unsigned long count,
     }
     if (rolls[0]>1)
       Cmd_WRoll_Print(ticket, auth, 
-		      Util_Format("had %d successes: %s%d and %d", rolls[0], 
-				  lfmt[0], rolls[count-1], rolls[count])
+		      Util_Format("%s had %d successes: %s%d and %d", str,
+				  rolls[0], lfmt[0], rolls[count-1],
+				  rolls[count])
 		      );
     else if (rolls[0]==1)
       Cmd_WRoll_Print(ticket, auth,
-		      Util_Format("succeeded once: %s%d and %d", lfmt[0],
-				  rolls[count-1], rolls[count])
+		      Util_Format("%s succeeded once: %s%d and %d", str,
+				  lfmt[0], rolls[count-1], rolls[count])
 		      );
     else if (rolls[0]==0)
-      Cmd_WRoll_Print(ticket, auth, Util_Format("failed: %s%d and %d", lfmt[0],
-						rolls[count-1], rolls[count])
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s failed: %s%d and %d",
+						str, lfmt[0], rolls[count-1],
+						rolls[count])
 		      );
     else
-      Cmd_WRoll_Print(ticket, auth, Util_Format("botched it: %s%d and %d",
-						lfmt[0], rolls[count-1],
+      Cmd_WRoll_Print(ticket, auth, Util_Format("%s botched it: %s%d and %d",
+						str, lfmt[0], rolls[count-1],
 						rolls[count])
 		      );
     delete [] lfmt[0];
     delete [] lfmt;
   }
+  delete [] rolls;
 }
 
 void Cmd_Roll_Print(void *ticket, int auth, const char *str)
diff --git a/cmd/roll.h b/cmd/roll.h
index 22dabe4..f87c449 100644
--- a/cmd/roll.h
+++ b/cmd/roll.h
@@ -2,10 +2,8 @@
 void Cmd_roll_Init();
 #endif
 void Cmd_Roll_Root(void *, int, const char *);
-void Cmd_Roll_DoRoll(void *, int, unsigned long, unsigned long, long);
+void Cmd_Roll_DoRoll(void *, int, long, unsigned long, long, unsigned long, long, const char *);
 void Cmd_Roll_Print(void *, int, const char *);
 void Cmd_WRoll_Root(void *, int, const char *);
-void Cmd_WRoll_DoRoll(void *, int, unsigned long, unsigned long);
+void Cmd_WRoll_DoRoll(void *, int, unsigned long, unsigned long, const char *);
 void Cmd_WRoll_Print(void *, int, const char *);
-
-/* @(#) $Id: roll.h,v 1.1.1.1 2004/01/16 07:28:15 lachesis Exp $ */
diff --git a/utils.c b/utils.c
index 868fadf..4a013fa 100644
--- a/utils.c
+++ b/utils.c
@@ -272,3 +272,31 @@ char Util_hex2dec(char val) {
 char Util_dec2hex(char val) {
   return ((val < 0 || val > 15) ? -1 : (val < 10 ? val + '0' : val + 'A' - 10));
 }
+
+void Util_heapsort_filterdown(long *arr, int size, int node)
+{
+  long temp;
+  if (arr[node]>arr[node*2]) {
+    temp = arr[node*2];
+    arr[node*2] = arr[node];
+    arr[node] = temp;
+    if (node*2<=(size-2)/2)
+      Util_heapsort_filterdown(arr, size, node*2);
+  }
+  if (arr[node]>arr[node*2+1]) {
+    temp = arr[node*2+1];
+    arr[node*2+1] = arr[node];
+    arr[node] = temp;
+    if (node*2+1<=(size-2)/2)
+      Util_heapsort_filterdown(arr, size, node*2+1);
+  }
+}
+
+void Util_heapsort(long *arr, int size)
+{
+  int c;
+  for (c=(size-2)/2;c>-1;c--)
+    Util_heapsort_filterdown(arr, size, c);
+  if (size>2)
+    Util_heapsort(arr+1, size-1);
+}
diff --git a/utils.h b/utils.h
index 5ff1385..fcb316b 100644
--- a/utils.h
+++ b/utils.h
@@ -47,6 +47,7 @@ const char * Util_CTCPFmt(const char *, const char *);
 const char * Util_CTCPFmtD(const char *, const char *);
 char Util_hex2dec(char);
 char Util_dec2hex(char);
+void Util_heapsort(long *, int);
 
 #ifdef __cplusplus
 }
