/*

 BabbleMud - A MUD server

 Author:  Nick Gammon 
          http://www.gammon.com.au/ 

(C) Copyright Nick Gammon 2004. Permission to copy, use, modify, sell and
distribute this software is granted provided this copyright notice appears
in all copies. This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.
 
*/


#include "commands.h"

//~ PLAYER (number):
  
const string COINS = "coins";   // coins s/he is carrying

void DoHelp (CommandInfo & info)
{
CACHE_COLOURS string CommandHelpColour = control ().gets ("colour_command_help");
CACHE_COLOURS string SingleCommandColour = control ().gets ("colour_single_command");

Character & p (info.player ());

// show generic help

  p.send ("help", messagemap ());

// now list commands they know

CiStringMap knownCommands;
list<Object>::iterator commandIter;
int maxwidth = 0;

// build map of commands they know and can use
  for (commandIter = commands ().begin ();
        commandIter != commands ().end ();
        ++commandIter)
    {
    Object & command = *commandIter;
    string name = command.gets ("name");
    string summary = command.gets ("summary");
    if (name.empty () || summary.empty ())
      continue; // can't list unnamed commands or ones without a summary
    
    // if they need a flag but don't have it, don't show them it
    string needflag = command.gets ("needflag");
    if (!needflag.empty ())
      if (!p.getb (needflag)) // needs flag x but doesn't have it
        continue;
      
    // if they need a flag off, but don't have it, don't show them
    string neednoflag = command.gets ("neednoflag");
    if (!neednoflag.empty ())
      if (p.getb (neednoflag)) // doesn't need flag x but has it
        continue;
    
    knownCommands [name] = summary;
    // find widest command name
    maxwidth = max<int> (maxwidth, name.size ());
    }

// now show them  
CiStringMap::const_iterator i;

  p.send (makeHeading (p.message ("commands"), '-', CommandHelpColour));
  for (i = knownCommands.begin ();
        i != knownCommands.end ();
        ++i)
    p.send (MAKE_STRING ("`^" << SingleCommandColour << setw (maxwidth) << i->first 
      << "`v - " << i->second));
  p.send (RESET);
} // end of DoHelp

struct fShowInventory
{
  Character & player_;
  const int indent;
  const string sIndent;
  
  // ctor
  fShowInventory (Character & p, const int i = 0) 
    : player_ (p), indent (i), sIndent (indent, ' ') {}
  void operator() (const Object & o) 
    {
    // show short description, indented by 'indent' spaces
    player_.send (sIndent + firstLetterCaps (shortDesc (o, player_.prefix ())), false);
    if (!o.contents_.empty ())
      player_.send ("containing", messagemap (), false);
    player_.send ("");
    // show this item's contents
    for_each (ISEQ (o.contents_), fShowInventory (player_, indent + 2));
    } // end of operator()
  
};  // end of fShowInventory

void DoInventory (CommandInfo & info)
{
CACHE_COLOURS string InventoryColour = control ().gets ("colour_inventory");
CACHE_COLOURS string NoInventoryColour = control ().gets ("colour_no_inventory");

Character & p (info.player ());
   
  // show inventory_
  if (p.inventory ().empty ())
    p.send ("no_inventory", messagemap ());
  else
    {
    p.send ("you_are_carrying", messagemap ());
    for_each (ISEQ (p.inventory ()), fShowInventory (p, 1));
     p.send ("");   
    p.send (MAKE_STRING (p.message ("total_weight") << p.getiTotal ("inventory", "weight")));
    }
  
  p.send (MAKE_STRING (p.message ("you_have_money")  << p.GetCoins (p.geti (COINS)) << "."));
  
} // end of DoInventory

void DoLook (CommandInfo & info)
{
CACHE_COLOURS string RoomNameColour = control ().gets ("colour_room_name");

Character & p (info.player ());
 
  // TODO: add: look (thing)
  
  p.send (RoomNameColour + info.room ().roomName (p.prefix ()) + RESET);

  // show room description
  p.send (info.room ().roomDescription (p.prefix ()));

  // show available exits
  int iExits = 0;
  for (ObjectList::const_iterator exititer = info.room ().exits ().begin ();
       exititer != info.room ().exits ().end (); ++exititer)
    {
    if (exititer->getb ("exit"))    // 'exit' flag set on obvious exits
      {
      if (iExits++ == 0)
        p.send ("obvious_exits", messagemap (), false);
      else
        p.send (", ", false);
      
      p.send (exititer->gets (p.prefix () + "short", 
          MAKE_STRING ("<<Exit " << iExits << ":" << p.prefix () << "short>>")), false); // show short description
      } // end of visible exit
    }
  if (iExits)
    p.send (RESET);        
  
  // show contents
  for (list<Object>::const_iterator contentsiter = info.room ().contents ().begin ();
       contentsiter != info.room ().contents ().end (); ++contentsiter)
    p.send (longDesc (*contentsiter, p.prefix ()));
    
  /* list other players in the same room */
  
  int iOthers = 0;
  for (PlayerListIterator listiter = playerlist ().begin (); 
      listiter != playerlist ().end (); 
      ++listiter)
    {
    Player *otherp = *listiter;
    if (otherp != &p && /* we don't see ourselves */
        otherp->IsPlaying () &&
        otherp->GetRoom () == p.GetRoom ())  // need to be in same room
      {
      if (iOthers++ == 0)
        p.send ("you_see_other_players", messagemap (), false) ;
      else
        p.send (", ", false);
      p.send (otherp->GetName (), false);
      }
    }   /* end of looping through all players */

  /* If we listed anyone, finish up the line with a period, newline */
  if (iOthers)
    p.send (".");

  // now list mobs
  for (CharacterListIterator mobiter = moblist ().begin (); 
      mobiter != moblist ().end (); 
      ++mobiter)
    {
    Character * mob = *mobiter;
    if (mob->IsPlaying () &&
        mob->GetRoom () == p.GetRoom ())  // need to be in same room
      {
      if (mob->geti ("hp") <= 0)
        {
        ThingMap m;
        m ["mob"].sets ("short", mob->GetName ());
        p.send ("dead_mob_here", messagemap (), m);
        }
      else
        p.send (mob->gets ("long"));
      }
  }

  // is it a shop?
  
  if (info.room ().roomFlag ("shop"))
    p.send ("in_shop", messagemap ()); 
   
} // end of DoLook

void DoWho (CommandInfo & info)
{
Character & p (info.player ());

  p.send ("connected_players", messagemap ()); 
  
  int count = 0;
  for (PlayerListIterator iter = playerlist ().begin ();
       iter != playerlist ().end ();
       ++iter)
    {
    Player * pTarget = *iter;    // the player  
    if (pTarget->IsPlaying ())
      {
      p.send (MAKE_STRING ("  " << pTarget->GetName () << p.message ("who_in_room")
        << pTarget->GetRoom ()));
      ++count;
      } // end of if playing
    } // end of doing each player
  
  p.send (MAKE_STRING (count << p.message ("total_players")));
  
} // end of DoWho

void DoScore (CommandInfo & info)
{
Character & p (info.player ());
const int labelWidth = 10;
const int datawidth = 5;

  p.send (MAKE_STRING (setw (labelWidth) << "HP: "   << setw (datawidth) << p.geti ("hp") << "."));
  p.send (MAKE_STRING (setw (labelWidth) << "Str: "  << setw (datawidth) << p.geti ("str") << "."));
  p.send (MAKE_STRING (setw (labelWidth) << "Dex: "  << setw (datawidth) << p.geti ("dex") << "."));
  p.send (MAKE_STRING (setw (labelWidth) << "Mana: " << setw (datawidth) << p.geti ("mana") << "."));
  p.send (MAKE_STRING (setw (labelWidth) << "Move: " << setw (datawidth) << p.geti ("move") << "."));
  p.send (MAKE_STRING (setw (labelWidth) << "Wis: "  << setw (datawidth) << p.geti ("wis") << "."));

  p.send (MAKE_STRING (p.message ("you_have_money") << p.GetCoins (p.geti (COINS)) << "."));

} // end of DoScore

static int LoadCommandsMap ()
  {
static CommandHandlerMap & commandmap = getCommandHandlerMap ();

  cout << "Loading command handlers in " __FILE__ << endl;
    
  COMMAND (DoHelp);      // show help message
  COMMAND (DoInventory); // what am I carrying?
  COMMAND (DoLook);      // look around
  COMMAND (DoScore);     // what is our status?
  COMMAND (DoWho);       // who is on?

  return 0;
  } // end of LoadCommands

static int loadThemUp = LoadCommandsMap ();

