]> jfr.im git - irc/gameservirc.git/blobdiff - gameserv/gameserv.cpp
Added a help file for the set command
[irc/gameservirc.git] / gameserv / gameserv.cpp
index 3a9771d11ec0c40b1dc88c39418c905444d32ff6..8926afea894f02e69bf2a0c7060f613854ee213f 100644 (file)
@@ -3,6 +3,7 @@
 #include "extern.h"
 #include "flags.h"
 #include "list.h"
+#include "level.h"
 #include "sockhelp.h"
 
 #include <cctype>
@@ -22,18 +23,8 @@ using std::ios;
 
 #endif
 
-// this will be hash.cpp start
-// thank you wcampbel
-unsigned long sHASH(const unsigned char *name);
-unsigned long iHASH(const unsigned char *name);
-List<aClient> players[U_TABLE_SIZE];
-// this will be hash.cpp end
 
-
-Monster *monsters[LEVELS][MONSTERS];   // Monsters per level. Total = MONSTERS * LEVELS
-Monster boss;                          // The boss monster
-
-Monster *masters[LEVELS];              // A master for each level
+Level levels[LEVELS];                  // The newest way to store monsters
 
 // Database functions
 int save_gs_dbase();
@@ -50,7 +41,7 @@ int strnicmp(const char *s1, const char *s2, size_t len);
 
 /********** Password functions **********/
 
-bool passcmp(char *encrypted, char *plaintext); // Compares an encrypted pass with a plain text one
+bool passcmp(const char *encrypted, char *plaintext); // Compares an encrypted pass with a plain text one
 
 bool check_password(char *name, char *plaintext); // Finds a password for the given name, and checks it with passcmp against the plaintext password given.
  
@@ -61,7 +52,7 @@ bool check_password(char *name, char *plaintext); // Finds a password for the gi
 
 bool shuttingdown;
 bool timedOut(Player *p);
-void  updateTS(Player *p);
+void updateTS(Player *p);
 void timeOutEvent(Player *p);
 
 bool is_playing(char *u); // True if the given nickname in the clients list is playing.
@@ -76,6 +67,9 @@ bool player_fight(aClient *user);
 bool master_fight(char *u); // True if the player is fighting their master.
 bool master_fight(aClient *user);
 
+bool dragon_fight(char *u); // True if the player is fighting the dragon.
+bool dragon_fight(aClient *user);
+
 /********** GameServ Booleans **********/
 
 void display_help(char *u, char *file = NULL);
@@ -92,15 +86,15 @@ void refresh(Player *p);
 void refreshall();
 void updateTS(Player *p);
 void reset(Player *p);
-void init_masters();
-void init_monsters();
+bool load_masters();
 bool load_monsters();
+bool load_levels();
 void delete_monsters();
-void delete_masters();
 
 void do_admin(char *u);
 void do_attack(char *u);
 void do_bank(char *u);
+void do_check(char *u);
 void do_fight(char *u);
 void do_heal(char *u);
 void do_help(char *u);
@@ -116,6 +110,7 @@ void do_play(char *u);
 void do_quitg(char *u);
 void do_reset(char *u);
 void do_run(char *u);
+void do_set(char *u);
 void do_stats(char *u);
 void do_store(char *u);
 void do_tavern(char *u);
@@ -165,20 +160,6 @@ void gameserv(char *source, char *buf)
        log("Source: %s  Command: %s", source, cmd);
     #endif
 
-    struct tm *tm;
-    time_t ti;
-    time(&ti);
-    tm = localtime(&ti);
-
-    int curday = tm->tm_mday;
-
-    if (curday != day)
-    {
-        refreshall();
-        day = curday;
-       save_day(); // here i come to save the day!
-    }
-
     if (strnicmp(cmd, "\1PING", 6) == 0)
     {
        char *ts;
@@ -198,6 +179,8 @@ void gameserv(char *source, char *buf)
        do_fight(source);
     } else if (stricmp(cmd, "ATTACK") == 0) {
        do_attack(source);
+    } else if (stricmp(cmd, "CHECK") == 0) {
+       do_check(source);
     } else if (stricmp(cmd, "RUN") == 0) {
        do_run(source);
     } else if (stricmp(cmd, "USE") == 0) {
@@ -226,12 +209,16 @@ void gameserv(char *source, char *buf)
        do_list(source);
     } else if (stricmp(cmd, "LOGOUT") == 0) {
        do_logout(source);
+    } else if (stricmp(cmd, "NEWS") == 0) {
+       do_news(source);
     } else if (stricmp(cmd, "REGISTER") == 0) {
        do_register(source);
     } else if (stricmp(cmd, "IDENTIFY") == 0) {
        do_identify(source);
     } else if (stricmp(cmd, "HELP") == 0) {
        do_help(source);
+    } else if (stricmp(cmd, "SET") == 0) {
+       do_set(source);
     } else if (stricmp(cmd, "STATS") == 0) {
        do_stats(source);
     } else if (stricmp(cmd, "SHUTDOWN") == 0) {
@@ -294,7 +281,7 @@ void gameserv(char *source, char *buf)
            }
            else if (stricmp(cmd2, "MONSTERS") == 0)
            {
-               notice(s_GameServ, source, "Loading monster data from %s", monsterdata);
+               notice(s_GameServ, source, "Loading monster data");
                load_monsters();
            }
            else
@@ -318,6 +305,14 @@ void gameserv(char *source, char *buf)
            char *rest = strtok(NULL, "");
            raw("%s", rest);
        }
+    } else if (stricmp(cmd, "PRINT") == 0) {
+       for (int x = 0; x < LEVELS; x++)
+           levels[x].monsters.print();
+    } else if (stricmp(cmd, "RANDOM") == 0) {
+       char *rstr = strtok(NULL, "");
+       range trange;
+       trange.setRange(rstr);
+       notice(s_GameServ, source, "Random number in that range: %d", trange.random());
     #endif
     } else {
        aClient *user;
@@ -372,7 +367,7 @@ void showstats(const char *u, const char *nick)
     }
     else if (ni->stats)
     {
-        notice(s_GameServ, sender->getNick(), "Stats for %s:", ni->stats->name);
+        notice(s_GameServ, sender->getNick(), "Stats for %s:", ni->stats->name.c_str());
 
         sprintf(buf, "Experience: %ld", ni->stats->exp);
         space = spaces(strlen(buf), " ");
@@ -421,7 +416,7 @@ void showstats(const char *u, const char *nick)
     }
     else
     {
-       notice(s_GameServ, u, "%s is not playing!", ni->stats->name);
+       notice(s_GameServ, u, "%s is not playing!", ni->stats->name.c_str());
     }
     delete [] buf;
 }
@@ -590,6 +585,20 @@ char *strtok(char *str, const char *delim)
 }
 #endif
 
+void do_check(char *u)
+{
+    int days, hours, minutes, seconds;
+    long complete;
+    complete = (lastrefresh + refreshperiod) - time(NULL);
+    days = complete / 86400;
+    hours = (complete % 86400) / 3600;
+    minutes = (complete % 86400) % 3600 / 60;
+    seconds = (complete % 86400) % 3600 % 60;
+
+    notice(s_GameServ, u, "Time left to next refresh: %dd %dh %dm %ds", 
+          days, hours, minutes, seconds);
+}
+
 void do_list(char *u)
 {
     aClient *user;
@@ -618,7 +627,7 @@ void do_list(char *u)
     {
        while(temp)
        {
-           if (!cmd || is_playing(temp->getData()))
+           if (cmd || is_playing(temp->getData()))
            {
                if (!header)
                {
@@ -627,10 +636,10 @@ void do_list(char *u)
                }
                #ifdef P10
                notice(s_GameServ, u, "IRC: %s     Game: %s", temp->getData()->getRealNick(), 
-                       temp->getData()->stats->name);
+                       temp->getData()->stats->name.c_str());
                #else
                notice(s_GameServ, u, "IRC: %s     Game: %s", temp->getData()->getNick(), 
-                       temp->getData()->stats->name);
+                       temp->getData()->stats->name.c_str());
                #endif
            }
 
@@ -644,6 +653,455 @@ void do_list(char *u)
        notice(s_GameServ, u, "End of List");
 
 }
+void do_set(char *u)
+{
+  aClient *user, *target;
+  char *name = strtok(NULL, " ");
+  char *cmd = strtok(NULL, " ");
+  char *cmd2;
+  
+  if (!(user = find(u)))
+    {
+      notice(s_GameServ, u, "Fatal error. Cannot find aClient. "\
+            "Buf: %s LOGOUT", u);
+      return;
+    }
+  else if (isIgnore(user))
+    {
+#ifdef DEBUGMODE
+      log("Ignoring %s.", user->getNick());
+#endif
+      return;
+    }
+  else if (!name)
+    {
+      notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] {PASSWORD|BANK BALANCE|PLAYER FIGHTS|FOREST FIGHTS|GOLD|STRENGTH|DEFENSE|HP|MAXHP|EXP|LEVEL|WEAPON|ARMOR|HP POTIONS|STRENGTH POTIONS|DEFENSE POTIONS|HEALING POTIONS|ALIVE|SEEN MASTER} {STRING|NUMBER|TRUE|FALSE}");
+      return;
+    }
+  else if (!(target = findplayer(name)))
+    {
+      // Back the pointers up... they didn't send a name probably
+      cmd2= cmd;
+      cmd = name;
+      target = user;
+
+      if (!is_playing(user))
+       {
+         notice(s_GameServ, u, "You must be playing to set things for yourself!");
+         return;
+       }
+    }
+  else
+    {
+      cmd2 = strtok(NULL, " ");
+    }
+
+  // Regardless of the previous if/else, if it got here, we know we have the cmd pointer at the right spot.
+  if (stricmp(cmd, "PASSWORD") == 0)
+    {
+      // Person is looking to change their password
+      // If they're an admin, or it's theirself, allow it
+      // cmd2 is pointing to the password now
+      if (isAdmin(user) || user == target)
+       {
+         target->stats->setPassword(cmd2);
+         notice(s_GameServ, u, "Password successfully changed");
+       }
+      else if (user != target && !isAdmin(user))
+       {
+         notice(s_GameServ, u, "You must be a %S admin to set other peoples' passwords.");
+         return;
+       }
+    }
+  else if (stricmp(cmd, "BANK") == 0 || stricmp(cmd, "BALANCE") == 0)
+    {
+        if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+       else if (stricmp(cmd, "BANK") == 0)
+       {
+         cmd2 = strtok(NULL, " "); // Need an extra parameter for set bank balance
+       }
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] [BANK] BALANCE <NUMBER>");
+           return;
+       }
+
+       target->stats->bank = stringtoint(cmd2);
+       notice(s_GameServ, u, "Bank balance changed to %s!", cmd2);
+    }
+  else if (stricmp(cmd, "PLAYER") == 0)
+    {
+      if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+      else if (stricmp(cmd2, "FIGHTS") != 0)
+       {
+         notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] PLAYER FIGHTS <NUMBER>");
+         return;
+       }
+      else
+       {
+         cmd2 = strtok(NULL, " ");
+           if (!cmd2)
+           {
+               notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] PLAYER FIGHTS <NUMBER>");
+               return;
+           }
+         target->stats->player_fights = stringtoint(cmd2);
+         notice(s_GameServ, u, "Player fights changed to %s!", cmd2);
+       }         
+    }
+  else if (stricmp(cmd, "FOREST") == 0)
+    {
+      if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+      else if (stricmp(cmd2, "FIGHTS") != 0)
+       {
+         notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] FOREST FIGHTS <number>");
+         return;
+       }
+      else
+       {
+         cmd2 = strtok(NULL, " ");
+           if (!cmd2)
+           {
+               notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] FOREST FIGHTS <NUMBER>");
+               return;
+           }
+         target->stats->forest_fights = stringtoint(cmd2);
+         notice(s_GameServ, u, "Forest fights changed to %s!", cmd2);
+       }         
+    }
+  else if (stricmp(cmd, "GOLD") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] GOLD <NUMBER>");
+           return;
+       }
+         target->stats->gold = stringtoint(cmd2);
+         notice(s_GameServ, u, "Gold set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "STRENGTH") == 0 && stricmp(cmd2, "POTIONS") != 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] STRENGTH <NUMBER>");
+           return;
+       }
+
+         target->stats->strength = stringtoint(cmd2);
+         notice(s_GameServ, u, "Strength set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "DEFENSE") == 0 && stricmp(cmd2, "POTIONS") != 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] DEFENSE <NUMBER>");
+           return;
+       }
+
+         target->stats->defense = stringtoint(cmd2);
+         notice(s_GameServ, u, "Defense set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "HP") == 0 && stricmp(cmd2, "POTIONS") != 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] HP <NUMBER>");
+           return;
+       }
+         target->stats->hp = stringtoint(cmd2);
+         notice(s_GameServ, u, "HP set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "MAXHP") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] MAXHP <NUMBER>");
+           return;
+       }
+         target->stats->maxhp = stringtoint(cmd2);
+         notice(s_GameServ, u, "MaxHP set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "EXPERIENCE") == 0 || stricmp(cmd, "EXP") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] {EXPERIENCE|EXP} <NUMBER>");
+           return;
+       }
+
+         target->stats->exp = stringtoint(cmd2);
+         notice(s_GameServ, u, "Exp set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "LEVEL") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] LEVEL <NUMBER>");
+           return;
+       }
+         target->stats->level = stringtoint(cmd2);
+         notice(s_GameServ, u, "Level set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "WEAPON") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] WEAPON <NUMBER>");
+           return;
+       }
+
+         target->stats->weapon = stringtoint(cmd2);
+         notice(s_GameServ, u, "Weapon set to %s", weapons[target->stats->weapon]);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "ARMOR") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] ARMOR <NUMBER>");
+           return;
+       }
+         target->stats->armor = stringtoint(cmd2);
+         notice(s_GameServ, u, "Armor set to %s", armors[target->stats->armor]);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "HP") == 0 && stricmp(cmd2, "POTIONS") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+         cmd2 = strtok(NULL, " ");
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] HP POTIONS <NUMBER>");
+           return;
+       }
+         target->stats->inventory.setHP(stringtoint(cmd2));
+         notice(s_GameServ, u, "HP Potions set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "HEALING") == 0 && stricmp(cmd2, "POTIONS") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+         cmd2 = strtok(NULL, " ");
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] HEALING POTIONS <NUMBER>");
+           return;
+       }
+         target->stats->inventory.setHealing(stringtoint(cmd2));
+         notice(s_GameServ, u, "Healing Potions set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "STRENGTH") == 0 && stricmp(cmd2, "POTIONS") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+         cmd2 = strtok(NULL, " ");
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] STRENGTH POTIONS <NUMBER>");
+           return;
+       }
+         target->stats->inventory.setStrength(stringtoint(cmd2));
+         notice(s_GameServ, u, "Strength Potions set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "DEFENSE") == 0 && stricmp(cmd2, "POTIONS") == 0)
+  {
+    if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;         
+       }
+    else
+       {
+         cmd2 = strtok(NULL, " ");
+       if (!cmd2)
+       {
+           notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] DEFENSE POTIONS <NUMBER>");
+           return;
+       }
+         target->stats->inventory.setDefense(stringtoint(cmd2));
+         notice(s_GameServ, u, "Defense Potions set to %s", cmd2);
+         return;
+       }
+  }
+  else if (stricmp(cmd, "ALIVE") == 0)
+  {
+     if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+     else
+       {
+         cmd2 = strtok(NULL, " ");
+         if (!cmd2 || (stricmp(cmd2, "TRUE") != 0 && stricmp(cmd2, "FALSE") != 0))
+         {
+            notice(s_GameServ, u, "SYNTAX: /msg %S SET ALIVE TRUE|FALSE");
+            return;
+         }
+         else if (stricmp(cmd2, "TRUE") == 0)
+         {
+            notice(s_GameServ, u, "Target has been Resurrected!");
+            target->addFlag(FLAG_ALIVE);
+         }
+         else
+         {
+            notice(s_GameServ, u, "Target is now dead!");
+            target->remFlag(FLAG_ALIVE);
+         }
+       }
+  }
+  else if (stricmp(cmd, "SEEN") == 0)
+    {
+      if (!isAdmin(user))
+       {
+         notice(s_GameServ, u, "Admins Only!");
+         return;
+       }
+      else if (stricmp(cmd2, "MASTER") != 0)
+       {
+         notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] SEEN MASTER {TRUE|FALSE}");
+         return;
+       }
+      else
+       {
+         cmd2 = strtok(NULL, " ");
+         if (!cmd2 || (stricmp(cmd2, "TRUE") != 0 && stricmp(cmd2, "FALSE") != 0))
+         {
+            notice(s_GameServ, u, "SYNTAX: /msg %S SET [NICK] SEEN MASTER {TRUE|FALSE}");
+            return;
+         }
+         else if (stricmp(cmd2, "TRUE") == 0)
+         {
+            notice(s_GameServ, u, "Target has seen their master now.");
+            target->addFlag(FLAG_MASTER);
+         }
+         else
+         {
+            notice(s_GameServ, u, "Target has not seen their master now.");
+            target->remFlag(FLAG_MASTER);
+         }
+       }         
+    }
+  else
+  {
+     notice(s_GameServ, u, "Unknown command: SET %s", cmd);
+     notice(s_GameServ, u, "SYNTAX: /msg %S SET [NAME] {PASSWORD|BANK BALANCE|PLAYER FIGHTS|FOREST FIGHTS|GOLD|STRENGTH|DEFENSE|HP|MAXHP|EXP|LEVEL|WEAPON|ARMOR|HP POTIONS|STRENGTH POTIONS|DEFENSE POTIONS|HEALING POTIONS|ALIVE|SEEN MASTER} {STRING|NUMBER|TRUE|FALSE}");
+     return;
+  }
+}
 
 void do_logout(char *u)
 {
@@ -678,7 +1136,7 @@ void do_logout(char *u)
        }
        else
        {
-           notice(s_GameServ, u, "Logging out %s", user->stats->name);
+           notice(s_GameServ, u, "Logging out %s", user->stats->name.c_str());
            logout(user);
        }
     }
@@ -706,7 +1164,7 @@ void logout(aClient *user)
     {
        ListNode<aClient> *it;
        aClient *temp;
-       unsigned long hv = iHASH((unsigned char *) user->stats->name);
+       unsigned long hv = iHASH((unsigned char *) user->stats->name.c_str());
        it = players[hv].Find(user);
 
         if (!it)
@@ -760,13 +1218,6 @@ void do_register(char *u)
     name = strtok(NULL, " ");
     password = strtok(NULL, " ");
 
-    static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
-    static char salt[3];
-    
-    salt[0] = saltChars[rand() % strlen(saltChars)];
-    salt[1] = saltChars[rand() % strlen(saltChars)];
-    salt[2] = '\0';
-
     if (!name)
     {
        notice(s_GameServ, u, "SYNTAX: /msg %S REGISTER NAME PASSWORD");
@@ -799,16 +1250,19 @@ void do_register(char *u)
            user->stats = new Player(user);
            user->stats->client = user; // Set the backwards pointer
            user->stats->reset(); // set the user up
-           strncpy(user->stats->password, crypt(password, salt), 255);
-           strncpy(user->stats->name, name, 255);
+           user->stats->setPassword(password);
+           user->stats->name = name;
            unsigned long hv = iHASH((unsigned char *) name);
            updateTS(user->stats);
            temp = players[hv].insertAtBack_RLN(user);
            temp->setPtr(user); // This is an extra step, but necessary for now
 
-           notice(s_GameServ, u, "Player %s registered with password %s.", user->stats->name, password);
+           // Update the last login time
+           user->stats->lastlogin = time(NULL);
+
+           notice(s_GameServ, u, "Player %s registered with password %s.", user->stats->name.c_str(), password);
            notice(s_GameServ, u, "Write this password down. If you lose it, there is no way to retrieve it!");
-           log("Nickname %s registered player %s.", u, user->stats->name);
+           log("Nickname %s registered player %s.", u, user->stats->name.c_str());
            setPlaying(user); // set the playing flag
        }
        else
@@ -856,7 +1310,7 @@ void do_identify(char *u)
     }
     else {
        ListNode<aClient> *temp;
-       unsigned long hv = iHASH((unsigned char *) p->stats->name);
+       unsigned long hv = iHASH((unsigned char *) p->stats->name.c_str());
        temp = players[hv].Find(p);
        if (!temp)
        {
@@ -874,14 +1328,19 @@ void do_identify(char *u)
 
 
        #ifdef DEBUGMODE
-           log("Player %s IRC: %s Identified", user->stats->name, 
+           log("Player %s IRC: %s Identified", user->stats->name.c_str()
                user->getNick());
        #endif
 
        setPlaying(user); // set the playing flag
 
        temp->setPtr(user);
-       notice(s_GameServ, u, "Password Accepted. Identified.");            
+
+       // Update the last login time
+       user->stats->lastlogin = time(NULL);
+
+       notice(s_GameServ, u, "Password Accepted. Identified.");
+       showNews(u, todaysnews);
     }
 }
 
@@ -914,157 +1373,78 @@ void do_stats(char *u)
        else
        {
            updateTS(user->stats);
-           showstats(u, user->stats->name);
+           showstats(u, user->stats->name.c_str());
        }
     }
     else
        showstats(u, nick);
 }
 
-void init_masters()
+bool load_masters()
 {
-    #ifdef DEBUGMODE
-       log("Calling delete_masters()");
-    #endif
+    ifstream infile("data/masters.dat");
+    char *buf;
+    int l = 0;
+    buf = new char[1024];
 
-    delete_masters();
+    if (infile.fail())
+    {
+       log("Error opening data/masters.dat");
+       return false;
+    }
 
     #ifdef DEBUGMODE
-       log("Initializing masters");
+       log("Loading masters from data/masters.dat");
     #endif
 
-    for (int x = 0; x < LEVELS; x++)
-       masters[x] = new Monster;
-
-    strcpy(masters[0]->name, "Old Bones");
-    strcpy(masters[0]->weapon, "Dull Sword Cane");
-    masters[0]->strength = 30;
-    masters[0]->gold = 0;
-    masters[0]->exp = 0;
-    masters[0]->maxhp = 35;
-    masters[0]->hp = 35;
-    strcpy(masters[0]->death, "You have done well my student, but the road is long. Use your new strength with humility and honor as you progress in levels!");
-
-    strcpy(masters[1]->name, "Master Chang");
-    strcpy(masters[1]->weapon, "Nanchaku");
-    masters[1]->strength = 45;
-    masters[1]->gold = 0;
-    masters[1]->exp = 0;
-    masters[1]->maxhp = 51;
-    masters[1]->hp = 51;
-    strcpy(masters[1]->death, "You try to make out what Master Chang is saying, but the only thing you catch is something about a grasshopper.");
-
-    strcpy(masters[2]->name, "Chuck Norris");
-    strcpy(masters[2]->weapon, "Ranger Kick");
-    masters[2]->strength = 83;
-    masters[2]->gold = 0;
-    masters[2]->exp = 0;
-    masters[2]->maxhp = 100;
-    masters[2]->hp = 100;
-    strcpy(masters[2]->death, "Be strong, and keep your goals in site. Drink milk, and don't do drugs. One day you may be fighting next to me as a Texas Ranger YEEHAW!");
-
-
-    strcpy(masters[3]->name, "Mr. Miagi");
-    strcpy(masters[3]->weapon, "Petrified Bonsai");
-    masters[3]->strength = 159;
-    masters[3]->gold = 0;
-    masters[3]->exp = 0;
-    masters[3]->maxhp = 165;
-    masters[3]->hp = 165;
-    strcpy(masters[3]->death, "Skill comes from repeating the correct but seemingly mundane actions. Wax ON, wax OFF!");
-
-    strcpy(masters[4]->name, "Jackie Chan");
-    strcpy(masters[4]->weapon, "Kung Fu Kick");
-    masters[4]->strength = 260;
-    masters[4]->gold = 0;
-    masters[4]->exp = 0;
-    masters[4]->maxhp = 232;
-    masters[4]->hp = 232;
-    strcpy(masters[4]->death, "I like to let people talk who like to talk... it's easier to find out how full of it they really are!");
-
-    strcpy(masters[5]->name, "Jet Li");
-    strcpy(masters[5]->weapon, "Motorcycle");
-    masters[5]->strength = 325;
-    masters[5]->gold = 0;
-    masters[5]->exp = 0;
-    masters[5]->maxhp = 504;
-    masters[5]->hp = 504;
-    strcpy(masters[5]->death, "Failure is a fuel for excuses. It's the doing the do, that makes the making.");
-
-
-    strcpy(masters[6]->name, "Muhammad Ali");
-    strcpy(masters[6]->weapon, "Quick Jab");
-    masters[6]->strength = 380;
-    masters[6]->gold = 0;
-    masters[6]->exp = 0;
-    masters[6]->maxhp = 1078;
-    masters[6]->hp = 1078;
-    strcpy(masters[6]->death, "It's just a job. Grass grows, birds fly, waves pound the sand. I beat people up.");
-
-    strcpy(masters[7]->name, "Li Mu Bai");
-    strcpy(masters[7]->weapon, "Green Destiny");
-    masters[7]->strength = 462;
-    masters[7]->gold = 0;
-    masters[7]->exp = 0;
-    masters[7]->maxhp = 2207;
-    masters[7]->hp = 2207;
-    strcpy(masters[7]->death, "No growth without resistance.  No action without reaction.  No desire without restraint.");
-
-
-    strcpy(masters[8]->name, "Jimmy Wang Yu");
-    strcpy(masters[8]->weapon, "Flying Guillotine");
-    masters[8]->strength = 511;
-    masters[8]->gold = 0;
-    masters[8]->exp = 0;
-    masters[8]->maxhp = 2780;
-    masters[8]->hp = 2780;
-    strcpy(masters[8]->death, "You have beaten the one armed boxer. Proceed with caution!");
-
-    strcpy(masters[9]->name, "Wong Fei Hung");
-    strcpy(masters[9]->weapon, "Drunken Boxing");
-    masters[9]->strength = 618;
-    masters[9]->gold = 0;
-    masters[9]->exp = 0;
-    masters[9]->maxhp = 3046;
-    masters[9]->hp = 3046;
-    strcpy(masters[9]->death, "Hiccup! Monkey drinks master's wine!");
-
-    strcpy(masters[10]->name, "Bruce Lee");
-    strcpy(masters[10]->weapon, "Fists of fury");
-    masters[10]->strength = 725;
-    masters[10]->gold = 0;
-    masters[10]->exp = 0;
-    masters[10]->maxhp = 3988;
-    masters[10]->hp = 3988;
-    strcpy(masters[10]->death, "You must learn to concentrate. It is like a finger pointing away to the moon... DONT concentrate on the finger, or you will miss all the heavenly glory.");
-}
-
-void init_monsters()
-{
-    #ifdef DEBUGMODE
-       log("Calling delete_monsters");
-    #endif
+    for (l = 0; l < LEVELS; l++)
+    {
+       infile.getline(buf, 1024, '\n');
 
-    delete_monsters();
+       log("%s", buf);
+       if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
+       {
+           l--;
+           continue;
+       }
+       else if (buf[0] == '^')
+           break;
 
-    for (int x = 0; x < LEVELS; x++)
-       for (int y = 0; y < MONSTERS; y++)
-           monsters[x][y] = new Monster();
-}
+       Monster *master = &levels[l].master;
 
-void delete_monsters()
-{
-    for (int x = 0; x < LEVELS; x++)
-       for (int y = 0; y < MONSTERS; y++)
-           if (monsters[x][y])
-               delete monsters[x][y];
+       char *name, *weapon, *strength, *gold, *exp, *maxhp, *death;
+
+
+       name = strtok(buf, "~");
+       weapon = strtok(NULL, "~");
+       strength = strtok(NULL, "~");
+       gold = strtok(NULL, "~");
+       exp = strtok(NULL, "~");
+       maxhp = strtok(NULL, "~");
+       death = strtok(NULL, "~");
+       
+       master->name = name;
+       master->weapon = weapon;
+       master->strength = stringtoint(strength);
+       master->gold = stringtoint(gold);
+       master->exp = stringtoint(exp);
+       master->maxhp = stringtoint(maxhp);
+       master->hp = master->maxhp;
+       master->death = death;
+    }
+
+    delete []buf;
+
+    if (l < LEVELS)  // We didn't load a master for every level - check data/masters.dat
+       return false;
+    else
+       return true;
 }
 
-void delete_masters()
+void delete_monsters()
 {
     for (int x = 0; x < LEVELS; x++)
-       if (masters[x])
-           delete masters[x];
+       levels[x].monsters.deleteNodes();
 }
 
 void display_monster(char *u)
@@ -1075,7 +1455,7 @@ void display_monster(char *u)
        Player *ni = user->stats;
        
        notice(s_GameServ, u, "Your Hitpoints: \ 2%d\ 2", ni->hp);
-       notice(s_GameServ, u, "%s's Hitpoints: \ 2%d\ 2", ni->fight->name, ni->fight->hp);
+       notice(s_GameServ, u, "%s's Hitpoints: \ 2%d\ 2", ni->fight->name.c_str(), ni->fight->hp);
        notice(s_GameServ, u, "Here are your commands:");
        notice(s_GameServ, u, "/msg %S attack");
        notice(s_GameServ, u, "/msg %S run");
@@ -1101,7 +1481,7 @@ void display_players(aClient *user)
     {
        aClient *battle = user->stats->battle;
        notice(s_GameServ, u, "Your Hitpoints: \ 2%d\ 2", user->stats->hp);
-       notice(s_GameServ, u, "%s's Hitpoints: \ 2%d\ 2", battle->stats->name, battle->stats->hp);
+       notice(s_GameServ, u, "%s's Hitpoints: \ 2%d\ 2", battle->stats->name.c_str(), battle->stats->hp);
        notice(s_GameServ, u, "Here are your commands:");
        notice(s_GameServ, u, "/msg %S attack");
        notice(s_GameServ, u, "/msg %S run");
@@ -1194,6 +1574,22 @@ bool master_fight(aClient *user)
        return user->stats->master != NULL;
 }
 
+bool dragon_fight(char *u)
+{
+    aClient *user;
+    if (!(user = find(u)))
+       return false;
+    else
+       return dragon_fight(user);
+}
+
+bool dragon_fight(aClient *user)
+{
+    if (!is_playing(user))
+       return false;
+    else
+       return (user->stats->level == LEVELS && master_fight(user));
+}
 void do_fight(char *u)
 {
     aClient *ni, *battle;
@@ -1254,11 +1650,11 @@ void do_fight(char *u)
 
         notice(s_GameServ, u, "You decide to fight %s while they're "\
                              "not in the realm!",
-                 battle->stats->name);
+                 battle->stats->name.c_str());
         display_players(u);
     }
 */
-    else if (stricmp(ni->stats->name, battle->stats->name) == 0)
+    else if (stricmp(ni->stats->name.c_str(), battle->stats->name.c_str()) == 0)
     {
        notice(s_GameServ, u, "Are you trying to commit suicide!?");
     }
@@ -1268,29 +1664,29 @@ void do_fight(char *u)
     }
     else if (player_fight(battle))
     {
-       notice(s_GameServ, u, "%s is fighting %s already!", battle->stats->name, battle->stats->battle->stats->name);
+       notice(s_GameServ, u, "%s is fighting %s already!", battle->stats->name.c_str(), battle->stats->battle->stats->name.c_str());
     }
     else if (master_fight(battle))
     {
-       notice(s_GameServ, u, "%s is fighting their master!", battle->stats->name);
+       notice(s_GameServ, u, "%s is fighting their master!", battle->stats->name.c_str());
     }
     else if (is_fighting(battle))
     {
-       notice(s_GameServ, u, "%s is fighting %s already!", battle->stats->name, battle->stats->fight->name);
+       notice(s_GameServ, u, "%s is fighting %s already!", battle->stats->name.c_str(), battle->stats->fight->name.c_str());
     }
     else if (ni->stats->level - battle->stats->level > maxbfightdistance)
     {
        // You can't fight someone below you by more than X level(s)
        // level 12 can fight level (12 - X) but not < (12 - X)
        notice(s_GameServ, u, "You may not fight %s. You're too strong!", 
-               battle->stats->name);
+               battle->stats->name.c_str());
     }
     else if (battle->stats->level - ni->stats->level > maxafightdistance)
     {
        // You can't fight someone above you by more than X level(S)
        // level 1 can fight level (1 + X), but not > (1 + X)
        notice(s_GameServ, u, "%s, do you really have a death wish? Try the forest you "\
-               "weakling!", ni->stats->name);
+               "weakling!", ni->stats->name.c_str());
     }
     else
     {
@@ -1307,11 +1703,11 @@ void do_fight(char *u)
        // Initiate Battle sequence!
        ni->stats->player_fights -= 1;
 
-        notice(s_GameServ, u, "You challenge %s to an online duel!", battle->stats->name);
-        notice(s_GameServ, battle->getNick(), "%s has challenged you to an online duel!", ni->stats->name);
+        notice(s_GameServ, u, "You challenge %s to an online duel!", battle->stats->name.c_str());
+        notice(s_GameServ, battle->getNick(), "%s has challenged you to an online duel!", ni->stats->name.c_str());
         notice(s_GameServ, battle->getNick(), "%s gets to go first "\
-                       "because they initiated!", ni->stats->name);
-        notice(s_GameServ, battle->getNick(), "Please wait while %s decides what to do.", ni->stats->name);
+                       "because they initiated!", ni->stats->name.c_str());
+        notice(s_GameServ, battle->getNick(), "Please wait while %s decides what to do.", ni->stats->name.c_str());
         display_players(ni);
     }
 }
@@ -1359,9 +1755,20 @@ void do_use(char *u)
            return;
        }
        int oldhealing = user->stats->hp;
+       user->stats->hp += (10 * user->stats->level) + (rand() % 10) * user->stats->level;
+       if (user->stats->hp - user->stats->maxhp >= 100)
+       {
+           user->stats->hp = user->stats->maxhp + 100;
+
+           if (oldhealing >= (user->stats->maxhp + 100))
+           {
+               notice(s_GameServ, u, "You cannot hold anymore HP!");
+               return;
+           }
+       }
+
        notice(s_GameServ, u, "You hastiliy gulp down the flask of cool life-giving waters.");
        notice(s_GameServ, u, "Rejuvination spreads throughout your body.");
-       user->stats->hp += (10 * user->stats->level) + (rand() % 10) * user->stats->level;
        notice(s_GameServ, u, "You gain %d HP!", user->stats->hp - oldhealing);
        p->decHealing();
        if (player_fight(user))
@@ -1469,23 +1876,23 @@ void do_run(char *u)
        notice(s_GameServ, u, "You run in place... try fighting next time.");
     else if (!player_fight(user) && !master_fight(user))
     {
-       notice(s_GameServ, u, "You run away from \ 2%s\ 2 like a little baby!", p->fight->name);
+       notice(s_GameServ, u, "You run away from \ 2%s\ 2 like a little baby!", p->fight->name.c_str());
        delete p->fight;
        p->fight = NULL;
     }
     else if (player_fight(user) && isYourTurn(p))
     {
-       notice(s_GameServ, u, "You run away from \ 2%s\ 2 like a little baby!", p2->name);
-       notice(s_GameServ, p->battle->getNick(), "\ 2%s\ 2 ran away from you like a little baby!", p->name);
+       notice(s_GameServ, u, "You run away from \ 2%s\ 2 like a little baby!", p2->name.c_str());
+       notice(s_GameServ, p->battle->getNick(), "\ 2%s\ 2 ran away from you like a little baby!", p->name.c_str());
        p2->battle = NULL;
     }
     else if (player_fight(user) && !isYourTurn(p))
     {
-       notice(s_GameServ, u, "It is not your turn. Please wait until \ 2%s\ 2 decides what to do.", p2->name);
+       notice(s_GameServ, u, "It is not your turn. Please wait until \ 2%s\ 2 decides what to do.", p2->name.c_str());
     }
     else if (master_fight(user))
     {
-       notice(s_GameServ, u, "You cannot run from \ 2%s\ 2! FIGHT!", p->master->name);
+       notice(s_GameServ, u, "You cannot run from \ 2%s\ 2! FIGHT!", p->master->name.c_str());
     }
     p->battle = NULL;
 }
@@ -1528,16 +1935,16 @@ void end_turn(aClient *user)
         if (mhit > 0)
         {
             notice(s_GameServ, u, "\1f%s\1f attacks with their \1f%s\1f for \ 2%d\ 2 damage!",
-                     fight->name, fight->weapon, mhit);
+                     fight->name.c_str(), fight->weapon.c_str(), mhit);
         }
         else if (mhit <= 0)
-            notice(s_GameServ, u, "%s completely misses you!", fight->name);
+            notice(s_GameServ, u, "%s completely misses you!", fight->name.c_str());
 
         if (mhit >= user->stats->hp)
         {
             if (!master_fight(user))
             {
-                notice(s_GameServ, u, "You have been \ 2\1fkilled\1f\ 2 by %s!", fight->name);
+                notice(s_GameServ, u, "You have been \ 2\1fkilled\1f\ 2 by %s!", fight->name.c_str());
                 notice(s_GameServ, u, "You lose all gold on hand and lose 10 percent "\
                         "of your experience!");
                 user->stats->gold = 0;
@@ -1550,7 +1957,7 @@ void end_turn(aClient *user)
             else
             {
                 notice(s_GameServ, u, "%s has bested you! You will have to wait "\
-                        "until tomorrow to try again", user->stats->master->name);
+                        "until tomorrow to try again", user->stats->master->name.c_str());
                 user->stats->fight = NULL;
                 user->stats->master = NULL;
                goto endturn;
@@ -1643,31 +2050,45 @@ void do_attack(char *u)
   if (!player_fight(ni))
   {
     if (hit > 0)
-        notice(s_GameServ, u, "You attack \1f%s\1f for \ 2%d\ 2 points!", fight->name, hit);
+        notice(s_GameServ, u, "You attack \1f%s\1f for \ 2%d\ 2 points!", fight->name.c_str(), hit);
     else
-        notice(s_GameServ, u, "You miss \1f%s\1f completely!", fight->name);
+        notice(s_GameServ, u, "You miss \1f%s\1f completely!", fight->name.c_str());
 
     if (hit >= fight->hp)
     {
-        if (master_fight(ni))
-            notice(s_GameServ, u, "You have bested %s!", fight->name);
+        if (master_fight(ni) && !dragon_fight(ni))
+       {
+            notice(s_GameServ, u, "You have bested %s!", fight->name.c_str());
+           addNews(todaysnews, "%s has bested %s and moved "\
+                   "to level %d", ni->stats->name.c_str(), fight->name.c_str(),
+                   (ni->stats->level + 1));
+       }
         else
-            notice(s_GameServ, u, "You have killed \ 2%s\ 2!", fight->name);
+            notice(s_GameServ, u, "You have killed \ 2%s\ 2!", fight->name.c_str());
 
-        notice(s_GameServ, u, "%s", fight->death);
+        notice(s_GameServ, u, "%s", fight->death.c_str());
         notice(s_GameServ, u, "You recieve \ 2%d\ 2 experience and \ 2%d\ 2 gold!",
                  fight->exp, fight->gold);
 
+       if (dragon_fight(ni))
+       {
+           addNews(todaysnews, "%s is a true warrior! %s has beaten %s!!", 
+               ni->stats->name.c_str(), ni->stats->name.c_str(), 
+               ni->stats->master->name.c_str());
+           ni->stats->master = NULL; // Don't progress in levels
+       }
+
        // If your new experience (or gold) will be greater than 2 billion,
        // then set your exp to 2bil. (2 billion max)... otherwise add them.
        // This could be a problem with overflowing out of the sign bit.
        // Unsigned long int maybe? Leave it for now.
-        ni->stats->exp = ( (ni->stats->exp + fight->exp) > 2000000000 ? 2000000000 : 
-                               ni->stats->exp + fight->exp);
-
-        ni->stats->gold = (ni->stats->gold + fight->gold > 2000000000 ? 2000000000 : 
-                               ni->stats->gold + fight->gold);
+       ni->stats->exp += fight->exp;
+       if (ni->stats->exp < 0 || ni->stats->exp > 2000000000)
+           ni->stats->exp = 2000000000;
 
+       ni->stats->gold += fight->gold;
+       if (ni->stats->gold < 0 || ni->stats->gold > 2000000000)
+           ni->stats->gold = 2000000000;
 
         if (master_fight(ni))
         {
@@ -1676,7 +2097,6 @@ void do_attack(char *u)
                      strbonus[ni->stats->level - 1], defbonus[ni->stats->level - 1]);
 
            // Increase your level
-            ni->stats->level++;
 
            // Increase your maximum hit points
             ni->stats->maxhp += hpbonus[ni->stats->level - 1];
@@ -1690,6 +2110,8 @@ void do_attack(char *u)
            // Add to your defensive power
             ni->stats->defense += defbonus[ni->stats->level - 1];
 
+            ni->stats->level++;
+
            // Clear the pointer for your master
             ni->stats->master = NULL;
         }
@@ -1708,18 +2130,20 @@ void do_attack(char *u)
         if (mhit > 0)
         {
             notice(s_GameServ, u, "\1f%s\1f attacks with their \1f%s\1f for \ 2%d\ 2 damage!",
-                     fight->name, fight->weapon, mhit);
+                     fight->name.c_str(), fight->weapon.c_str(), mhit);
         }
         else if (mhit <= 0)
-            notice(s_GameServ, u, "%s completely misses you!", fight->name);
+            notice(s_GameServ, u, "%s completely misses you!", fight->name.c_str());
 
         if (mhit >= ni->stats->hp)
         {
             if (!master_fight(ni))
             {
-                notice(s_GameServ, u, "You have been \ 2\1fkilled\1f\ 2 by %s!", fight->name);
+                notice(s_GameServ, u, "You have been \ 2\1fkilled\1f\ 2 by %s!", fight->name.c_str());
                 notice(s_GameServ, u, "You lose all gold on hand and lose 10 percent "\
                         "of your experience!");
+               addNews(todaysnews, "%s has been killed by %s!",
+                       ni->stats->name.c_str(), fight->name.c_str());
                 ni->stats->gold = 0;
                 ni->stats->exp -= (long int)(ni->stats->exp * .10);
                ni->stats->hp = 0;
@@ -1730,7 +2154,9 @@ void do_attack(char *u)
             else
             {
                 notice(s_GameServ, u, "%s has bested you! You will have to wait "\
-                        "until tomorrow to try again", ni->stats->master->name);
+                        "until tomorrow to try again", ni->stats->master->name.c_str());
+               addNews(todaysnews, "%s tried to best %s and failed!",
+                       ni->stats->name.c_str(), fight->name.c_str());
                 ni->stats->fight = NULL;
                 ni->stats->master = NULL;
                return;
@@ -1836,48 +2262,38 @@ void do_attack(char *u)
     if (!isYourTurn(ni->stats))
     {
         notice(s_GameServ, u, "Please wait until %s decides what to do!", 
-               battle->stats->name);
+               battle->stats->name.c_str());
         return;
     }
     if (hit > 0)
     {
-        notice(s_GameServ, u, "You attack \1f%s\1f for \ 2%d\ 2 points!", battle->stats->name, hit);
+        notice(s_GameServ, u, "You attack \1f%s\1f for \ 2%d\ 2 points!", battle->stats->name.c_str(), hit);
 
         notice(s_GameServ, battle->getNick(), "%s has hit you with their %s for "\
-                                             "\ 2%d\ 2 damage!", ni->stats->name, 
+                                             "\ 2%d\ 2 damage!", ni->stats->name.c_str()
                                              weapons[ni->stats->weapon], hit);
-       clearYourTurn(ni->stats);
-       setYourTurn(battle->stats);
-        display_players(battle);
     }
     else
     {
-        notice(s_GameServ, u, "You miss \1f%s\1f completely!", battle->stats->name);
-        notice(s_GameServ, battle->getNick(), "%s misses you completely!", ni->stats->name);
-       clearYourTurn(ni->stats);
-       setYourTurn(battle->stats);
-        display_players(battle);
+        notice(s_GameServ, u, "You miss \1f%s\1f completely!", battle->stats->name.c_str());
+        notice(s_GameServ, battle->getNick(), "%s misses you completely!", ni->stats->name.c_str());
     }
+
     if (hit >= battle->stats->hp)
     {
-        notice(s_GameServ, u, "You have killed \ 2%s\ 2!", battle->stats->name);
+        notice(s_GameServ, u, "You have killed \ 2%s\ 2!", battle->stats->name.c_str());
         notice(s_GameServ, u, "You recieve \ 2%d\ 2 experience and \ 2%ld\ 2 gold!",
                 (long int)(battle->stats->exp * .10), battle->stats->gold);
         notice(s_GameServ, battle->getNick(), "You have been killed by \ 2%s\ 2!", 
-               ni->stats->name);
+               ni->stats->name.c_str());
         battle->stats->hp = 0;
         clearAlive(battle->stats);
 
-        if (2000000000 - ni->stats->exp > (long int)(battle->stats->exp * .10))
-        {
-            ni->stats->exp += (long int)(battle->stats->exp * .10);
-            battle->stats->exp -= (long int)(battle->stats->exp * .10);
-        }
-        else
-        {
-            battle->stats->exp -= (long int)(battle->stats->exp * .10);
+        ni->stats->exp += (long int)(battle->stats->exp * .10);
+        battle->stats->exp -= (long int)(battle->stats->exp * .10);
+
+        if (ni->stats->exp < 0 || ni->stats->exp > 2000000000)
             ni->stats->exp = 2000000000;
-        }
 
         if (2000000000 - ni->stats->gold > battle->stats->gold)
         {
@@ -1892,13 +2308,16 @@ void do_attack(char *u)
             notice(s_GameServ, battle->getNick(), "You lose ten percent of your experience!");
 
             notice(s_GameServ, battle->getNick(), "However, %s could not carry all of your "\
-                       "gold.", ni->stats->name);
+                       "gold.", ni->stats->name.c_str());
 
             notice(s_GameServ, battle->getNick(), "Luckily, you still have \ 2%ld\ 2 gold "\
                        "left. All is not lost!", battle->stats->gold);
 
             ni->stats->gold = 2000000000;
         }
+
+       clearYourTurn(ni->stats);
+       clearYourTurn(battle->stats);
        battle->stats->battle = NULL;
         ni->stats->battle = NULL;
         return;
@@ -1909,9 +2328,9 @@ void do_attack(char *u)
             battle->stats->hp -= hit;
        clearYourTurn(ni->stats);
        setYourTurn(battle->stats);
+        display_players(battle);
         notice(s_GameServ, u, "Please wait while %s decides what to do!", 
-               battle->stats->name);
-
+               battle->stats->name.c_str());
         return;
     }
    }
@@ -2083,12 +2502,13 @@ int save_gs_dbase()
     {
        it = ptr->getData()->stats;
        clearYourTurn(it);
-       outfile << it->name << ' ' << it->level << ' ' << it->exp << ' ' << it->gold << ' ' << it->bank << ' '
+       outfile << it->name.c_str() << ' ' << it->level << ' ' << it->exp << ' ' << it->gold << ' ' << it->bank << ' '
                << it->hp << ' ' << it->maxhp << ' ' << it->strength << ' ' << it->defense << ' '
                << it->armor << ' ' << it->weapon << ' '
                << it->forest_fights << ' ' << it->player_fights <<  ' ' 
                << it->getFlags() << ' ' << it->password << ' ' << it->inventory.Healing()
-               << ' ' << it->inventory.Strength() << ' ' << it->inventory.Defense() << ' ' << it->inventory.HP() << endl;
+               << ' ' << it->inventory.Strength() << ' ' << it->inventory.Defense() << ' ' << it->inventory.HP()
+               << ' ' << it->lastlogin << endl;
        ptr = ptr->Next();
     }
    }
@@ -2112,6 +2532,19 @@ int load_gs_dbase()
        return 0;
     }
 
+    for (int x = 0; x < U_TABLE_SIZE; x++)
+    {
+       ListNode<aClient> *tempNode;
+       tempNode = players[x].First();
+       while (tempNode)
+       {
+           if (tempNode->getData()->stats->client)
+               logout(tempNode->getData()->stats->client);
+           tempNode = tempNode->Next();
+       }
+       players[x].deleteNodes();
+    }
+
     while (infile.getline(buf, 1024, '\n'))
     {
        temp = new aClient;
@@ -2134,7 +2567,7 @@ int load_gs_dbase()
        p->setFlags(stringtoint(strtok(NULL, " ")));
 
        password = strtok(NULL, " ");
-       strcpy(p->password, password);
+       p->password = password;
        temp->setNick("Not Playing");
        #ifdef P10
        temp->setRealNick("Not Playing");
@@ -2159,7 +2592,14 @@ int load_gs_dbase()
        tempname = strtok(NULL, " ");
        if (tempname)
            p->inventory.setHP(stringtoint(tempname));
-       unsigned long hv = iHASH((unsigned char *) temp->stats->name);
+
+        tempname = strtok(NULL, " ");
+       if (tempname)
+           p->lastlogin = stringtoint(tempname);
+       else
+           p->lastlogin = time(NULL);
+
+       unsigned long hv = iHASH((unsigned char *) temp->stats->name.c_str());
 
        temp->stats->client = NULL;
        players[hv].insertAtBack(temp);
@@ -2170,7 +2610,7 @@ infile.close();
 return 1;
 }
 
-bool passcmp(char *encrypted, char *plaintext)
+bool passcmp(const char *encrypted, char *plaintext)
 {
     char salt[3];
     char *plaintext2, *plainToencrypt;
@@ -2200,7 +2640,7 @@ bool check_password(char *name, char *plaintext)
        return false;
     else
     {
-       return passcmp(client->stats->password, plaintext);
+       return passcmp(client->stats->password.c_str(), plaintext);
     }
 }
 
@@ -2331,6 +2771,11 @@ void do_store(char *u)
                 p->gold -= prices[wep - 1];
             }
         }
+       else
+       {
+           notice(s_GameServ, u, "SYNTAX: \ 2STORE BUY {ARMOR | WEAPON} \1fNUMBER\1f\ 2");
+           return;
+       }
     }
     else if (stricmp(cmd, "SELL" ) == 0)
     {
@@ -2440,7 +2885,7 @@ void showinventory(aClient *from, aClient *to)
     if (is_playing(from))
     {
        Pouch *p = &from->stats->inventory;
-       notice(s_GameServ, nick, "Inventory for %s:", from->stats->name);
+       notice(s_GameServ, nick, "Inventory for %s:", from->stats->name.c_str());
        notice(s_GameServ, nick, " Healing Potions: %d", p->Healing());
        notice(s_GameServ, nick, "Strength Potions: %d", p->Strength());
        notice(s_GameServ, nick, " Defense Potions: %d", p->Defense());
@@ -2454,6 +2899,7 @@ void do_tavern(char *u)
 
     aClient *user;
     Player *p;
+
     if (!(user = find(u)))
     {
        notice(s_GameServ, u, "Fatal Error. See a %S admin for help");
@@ -2489,19 +2935,21 @@ void do_tavern(char *u)
     }
     else if (stricmp(cmd, "LIST") == 0)
     {
-       notice(s_GameServ, u, "Here is a list of what we have to offer:");
-       notice(s_GameServ, u, "1. Healing Potions for %ld Gold", 100 * p->level + (p->exp / 10));
-       notice(s_GameServ, u, "2. Strength Potions for %ld Gold", 205 * p->level + (p->exp / 10));
-       notice(s_GameServ, u, "3. Defense Potions for %ld Gold", 200 * p->level + (p->exp / 10));
-       notice(s_GameServ, u, "4. HP Potions for %ld Gold", 230 * p->level + (p->exp / 10));
-       notice(s_GameServ, u, "To buy a potion, type /msg %S TAVERN BUY #");
-       notice(s_GameServ, u, "Example: /msg %S TAVERN BUY 1 buys a healing potion!");
-       notice(s_GameServ, u, "By something will ya!");
+           notice(s_GameServ, u, "Here is a list of what we have to offer:");
+           notice(s_GameServ, u, "1. Healing Potions for %ld Gold", 
+                                       1000 * p->level * 4);
+           notice(s_GameServ, u, "2. Strength Potions for %ld Gold", 
+                                       2500 * p->level * 4);
+           notice(s_GameServ, u, "3. Defense Potions for %ld Gold", 
+                                       3000 * p->level * 4);
+           notice(s_GameServ, u, "4. HP Potions for %ld Gold", 
+                                       2000 * p->level * 4);
+           notice(s_GameServ, u, "To buy a potion, type /msg %S TAVERN BUY #");
+           notice(s_GameServ, u, "Example: /msg %S TAVERN BUY 1 buys a healing potion!");
     }
     else if (stricmp(cmd, "BUY") == 0)
     {
        char *chnum = strtok(NULL, " ");
-       int num = stringtoint(chnum);
 
        if (!chnum)
        {
@@ -2509,14 +2957,20 @@ void do_tavern(char *u)
            notice(s_GameServ, u, "Example: /msg %S TAVERN BUY 1");
            return;
        }
+       int num = stringtoint(chnum);
+
        if (num < 1 || num > 4)
        {
            notice(s_GameServ, u, "Invalid Choice!");
            notice(s_GameServ, u, "Here is a list of what we have to offer:");
-           notice(s_GameServ, u, "1. Healing Potions for %ld Gold", 100 * p->level + (p->exp / 10));
-           notice(s_GameServ, u, "2. Strength Potions for %ld Gold", 205 * p->level + (p->exp / 10));
-           notice(s_GameServ, u, "3. Defense Potions for %ld Gold", 200 * p->level + (p->exp / 10));
-           notice(s_GameServ, u, "4. HP Potions for %ld Gold", 230 * p->level + (p->exp / 10));
+           notice(s_GameServ, u, "1. Healing Potions for %ld Gold", 
+                                       1000 * p->level * 4);
+           notice(s_GameServ, u, "2. Strength Potions for %ld Gold", 
+                                       2500 * p->level * 4);
+           notice(s_GameServ, u, "3. Defense Potions for %ld Gold", 
+                                       3000 * p->level * 4);
+           notice(s_GameServ, u, "4. HP Potions for %ld Gold", 
+                                       2000 * p->level * 4);
            notice(s_GameServ, u, "To buy a potion, type /msg %S TAVERN BUY #");
            notice(s_GameServ, u, "Example: /msg %S TAVERN BUY 1 buys a healing potion!");
            return;
@@ -2524,7 +2978,7 @@ void do_tavern(char *u)
        switch(num)
        {
            case 1:
-               price = (100 * p->level) + (p->exp / 10);
+               price = (1000 * p->level * 4);
                if (p->gold >= price)
                {
                    notice(s_GameServ, u, "One healing potion coming right up!");
@@ -2535,7 +2989,7 @@ void do_tavern(char *u)
                    notice(s_GameServ, u, "You don't have enough gold!");
                break;
            case 2:
-               price = (205 * p->level) + (p->exp / 10);
+               price = 2500 * p->level * 4;
                if (p->gold >= price)
                {
                    notice(s_GameServ, u, "One strength boost coming right up!");
@@ -2546,7 +3000,7 @@ void do_tavern(char *u)
                    notice(s_GameServ, u, "You don't have enough gold!");
                break;
            case 3:
-               price = (200 * p->level) + (p->exp / 10);
+               price = 3000 * p->level * 4;
                if (p->gold >= price)
                {
                    notice(s_GameServ, u, "One defense boost coming right up!");
@@ -2557,7 +3011,7 @@ void do_tavern(char *u)
                    notice(s_GameServ, u, "You don't have enough gold!");
                break;
            case 4:
-               price = (230 * p->level) + (p->exp / 10);
+               price = 3000 * p->level * 4;
                if (p->gold >= price)
                {
                    notice(s_GameServ, u, "One HP Potion coming right up!");
@@ -2634,7 +3088,12 @@ void do_bank(char *u)
         notice(s_GameServ, u, "I don't know how to convert alphabet letters into currency, sire!");
         return;
     }
-
+    if (stringtoint(amount) < 0)
+    {
+        notice(s_GameServ, u, "Sorry. This bank is not licensed "\
+       "to handle such sums of cash, noble Lord.");
+        return;
+    }
     p = user->stats;
 
     if (stricmp(cmd, "DEPOSIT") == 0)
@@ -2773,7 +3232,7 @@ void do_dragon(char *u)
        notice(s_GameServ, u, "You're dead. Wait until tomorrow to see your master!");
        return;
     }
-    else if (user->stats->level < REALLEVELS)
+    else if (user->stats->level < LEVELS)
     {
        notice(s_GameServ, u, "You fool! Only those strong enough "\
                "to vanquish any foe should DARE fight the dragon!");
@@ -2785,7 +3244,7 @@ void do_dragon(char *u)
     updateTS(user->stats);
 
     Player *p = user->stats;
-    p->fight = new Monster(boss);
+    setMaster(p);
     notice(s_GameServ, u, "You approach the dragon's lair cautiously.");
     notice(s_GameServ, u, "The stench of sulfer fills the air as a "\
        "deep, red fog rolls in. The air is filled with the "\
@@ -2794,7 +3253,8 @@ void do_dragon(char *u)
     notice(s_GameServ, u, "You adjust your %s, tighten your grip on "\
        "your %s, and venture into the hot, dark cave. "\
        "You are surprised at the angle of descent as you climb "\
-       "lower and lower, deeper into the dragon's den.");
+       "lower and lower, deeper into the dragon's den.", 
+       armors[p->armor], weapons[p->weapon]);
     notice(s_GameServ, u, "You come to the end of the cave to find "\
        "a tooth. It is a large tooth... bigger than your torso."\
        " Suddenly the darkness lifts from the gleam of an eye "\
@@ -2802,7 +3262,7 @@ void do_dragon(char *u)
     notice(s_GameServ, u, "Just then you notice the eye begin to "\
        "glare orange! The tooth is moving... but it is still too "\
        "dark for you to make out.... THE DRAGON! You see it!");
-    display_monster(u);
+    see_master(u);
 }
 
 void do_master(char *u)
@@ -2912,15 +3372,18 @@ void do_master(char *u)
            see_master(u);
        }
        else
-           notice(s_GameServ, u, "You are not worthy of fighting %s! You need %ld more experience.", masters[p->level - 1]->name, (need - p->exp));
+           notice(s_GameServ, u, "You are not worthy of fighting %s! You need %ld more experience.", 
+               levels[p->level - 1].master.name.c_str(), (need - p->exp));
        return;
     }
     else if (stricmp(cmd, "QUESTION") == 0)
     {
        if (p->exp >= need)
-           notice(s_GameServ, u, "%s looks you up and down and decides you are more ready than you will ever be.", masters[p->level - 1]->name);
+           notice(s_GameServ, u, "%s looks you up and down and decides you are more ready than you will ever be.", 
+               levels[p->level - 1].master.name.c_str());
        else
-           notice(s_GameServ, u, "You pathetic fool! You are no match for %s, %s!", masters[p->level - 1]->name, p->name);
+           notice(s_GameServ, u, "You pathetic fool! You are no match for %s, %s!", 
+               levels[p->level - 1].master.name.c_str(), p->name.c_str());
 
        return;
     }
@@ -2943,7 +3406,7 @@ void see_master(char *u)
     if (!is_fighting(user) && is_playing(user))
     {
        Player *p = user->stats;
-       p->master = new Monster(masters[p->level - 1]);
+       p->master = new Monster(&levels[p->level - 1].master);
        p->fight = p->master;
        display_monster(u);  // Since master is the same structure, use this function
     }
@@ -3077,10 +3540,16 @@ void resetall()
 
 void reset(Player *p)
 {
+    string *myname;
+
     if (!p)
        return;
 
+    myname = new string(p->name);
+
     p->reset();
+    p->name = *myname;
+    delete myname;
 }
 
 void updateTS(Player *p)
@@ -3089,11 +3558,11 @@ void updateTS(Player *p)
        return;
 
     #ifdef DEBUGMODE
-        log("Old timestamp for %s: %ld", p->name, p->lastcommand);
+        log("Old timestamp for %s: %ld", p->name.c_str(), p->lastcommand);
     #endif
     p->lastcommand = time(NULL);
     #ifdef DEBUGMODE
-        log("New timestamp for %s: %ld", p->name, p->lastcommand);
+        log("New timestamp for %s: %ld", p->name.c_str(), p->lastcommand);
     #endif
 
 }
@@ -3115,7 +3584,7 @@ bool timedOut(Player *p)
 
 void timeOutEvent(Player *p)
 {
-    aClient *user = findplayer(p->name);
+    aClient *user = findplayer(p->name.c_str());
 
     if (!user || !p->client) // then they're not playing
        return;
@@ -3133,7 +3602,7 @@ void timeOutEvent(Player *p)
            notice(s_GameServ, nick, "You timed out "\
                "during a fight. You lose your turn!");
            notice(s_GameServ, p->battle->getNick(),
-                  "%s hesitated for too long. Your move.", p->name);
+                  "%s hesitated for too long. Your move.", p->name.c_str());
            clearYourTurn(p);
            setYourTurn(p->battle->stats);
 
@@ -3150,11 +3619,11 @@ void timeOutEvent(Player *p)
            notice(s_GameServ, p->battle->getNick(),
                "You and %s timed out at the same time."\
                " Don't fight if you're just going to "\
-               "sit there!", p->name);
+               "sit there!", p->name.c_str());
            notice(s_GameServ, user->getNick(),
                "You and %s timed out at the same time."\
                " Don't fight if you're just going to "\
-               "sit there!", p->battle->stats->name);
+               "sit there!", p->battle->stats->name.c_str());
            logout(p->battle);
            logout(user);
            return;
@@ -3236,7 +3705,7 @@ void do_reset(char *u)
        notice(s_GameServ, u, "Resetting everyone's stats!");
        resetall();
     }
-    else if ((user = findbyrealnick(nick)))
+    else if ((user = findplayer(nick)))
     {
        if (is_playing(user))
        {
@@ -3249,11 +3718,8 @@ void do_reset(char *u)
        }
        else
        {
-           #ifdef P10
-           notice(s_GameServ, u, "%s is not playing.", user->getRealNick());
-           #else
-           notice(s_GameServ, u, "%s is not playing.", user->getNick());
-           #endif
+           notice(s_GameServ, u, "Resetting %s", user->stats->name.c_str());
+           reset(user->stats);
        }
     }
     else
@@ -3366,78 +3832,63 @@ void do_admin(char *u)
     }
 }
 
+bool load_levels()
+{
+    char *filename;
+    filename = new char[256];
+
+    for (int x = 1; x <= LEVELS; x++)
+    {
+       sprintf(filename, "data/levels/level%d.dat", x);
+       if (levels[x - 1].loadLevel(filename) == false)
+           return false;
+    }
+
+    delete []filename;
+    return true;
+}
 bool load_monsters()
 {
+    char *filename;
     ifstream infile;
-    infile.open("monsters.dat");
-
     char *buf;
+    buf = new char[2048];
 
-    if (infile.fail())
+  for (int level = 1; level <= LEVELS; level++)
+  {
+    filename = new char[256];
+    sprintf(filename, "data/monsters/level%d.dat", level);
+    infile.open(filename);
+
+    if (!infile)
     {
-       log("Error opening monsters.dat");
+       log("Error opening %s", filename);
        return false;
     }
-    init_monsters();
-    buf = new char[2048];
 
     #ifdef DEBUGMODE
-       log("Loading monsters from monsters.dat");
+       log("Loading monsters from %s", filename);
     #endif
 
-  for (int l = 0; l < REALLEVELS; l++)
-  {
-    for (int m = 0; m < MONSTERS;)
+    while (infile.getline(buf, 2048))
     {
-       infile.getline(buf, 2048);
+       if (buf[0] == '^')
+           break;
        if (buf[0] == '\n' || buf[0] == '\0' || buf[0] == '#')
            continue;
-       else
-       {
-           strcpy(monsters[l][m]->name, strtok(buf, "~"));
-           strcpy(monsters[l][m]->weapon, strtok(NULL, "~"));
-           monsters[l][m]->strength = stringtoint(strtok(NULL, "~"));
-           monsters[l][m]->gold = stringtoint(strtok(NULL, "~"));
-           monsters[l][m]->exp = stringtoint(strtok(NULL, "~"));
-           monsters[l][m]->maxhp = stringtoint(strtok(NULL, "~"));
-           monsters[l][m]->hp = monsters[l][m]->maxhp;
-           strcpy(monsters[l][m]->death, strtok(NULL, ""));
-           m++;
-       }
+       Monster *temp;
+       temp = new Monster;
+
+           temp->name = strtok(buf, "~");
+           temp->weapon = strtok(NULL, "~");
+            temp->death = strtok(NULL, "~");
+
+       levels[level - 1].monsters.insertAtBack_RLN(temp);
+       delete temp;
     }
+    delete [] filename;
+    infile.close();
   }
     delete [] buf;
 return true;
 }
-
-// this will be hash.cpp start
-// thank you wcampbel
-unsigned long sHASH(const unsigned char *name)
-{
-  unsigned long h = 0, g;
-
-  while (*name)
-  {
-    h = (h << 4) + (*name++); // Case sensitive for numerics
-    if ((g = (h & 0xF0000000)))
-      h ^= g >> 24;
-    h &= ~g;
-  }
-  return h % U_TABLE_SIZE;
-}
-
-unsigned long iHASH(const unsigned char *name)
-{
-  unsigned long h = 0, g;
-
-  while (*name)
-  {
-    h = (h << 4) + tolower(*name++);
-    if ((g = (h & 0xF0000000)))
-      h ^= g >> 24;
-    h &= ~g;
-  }
-  return h % U_TABLE_SIZE;
-}
-
-// this will be hash.cpp end