/
CVS/
boards/CVS/
clans/
gmc/CVS/
help/CVS/
include/CVS/
players/
progs/CVS/
races/CVS/
system/CVS/
text/
text/CVS/
todo/
todo/CVS/
units/CVS/
// $Id: command.inc,v 1.17 2001/05/11 14:25:08 druid Exp $

{$F+}

{ The complete quit procedure, which even logs off NPCs! - Grimlord }
procedure do_quit(ch : GCharacter; param : string);
var
   timer : GTimer;
begin
  if (ch.IS_NPC) then
    exit;

  if (ch.position = POS_FIGHTING) then
    begin
    ch.sendBuffer('You are fighting! You can''t quit!'#13#10);
    exit;
    end;

  timer := hasTimer(ch, TIMER_COMBAT);

  if (timer <> nil) then
    begin
    ch.sendBuffer('You have recently fled out of combat or have encountered a member'#13#10);
    ch.sendBuffer('of the opposite alignment. Therefor you are not allowed to quit.'#13#10);
    ch.sendBuffer('Please wait another '+inttostr(round(timer.counter / CPULSE_TICK))+' gameticks to quit.'#13#10);
    exit;
    end;

  if (auction_good.seller = ch) or (auction_good.buyer = ch)
   or (auction_evil.seller = ch) or (auction_evil.buyer = ch) then
    begin
    ch.sendBuffer('Please wait till the current auction has been concluded.'#13#10);
    exit;
    end;

  if (ch.snooped_by <> nil) then
    interpret(ch.snooped_by, 'snoop self');

  act(AT_REPORT, '$n has logged off.', false, ch, nil, nil, TO_ROOM);


  if (ch.conn <> nil) then
    GConnection(ch.conn).send('Thanks for playing! Please visit this MUD again!'#13#10);

  GPlayer(ch).quit;
end;

procedure do_save(ch : GCharacter; param : string);
begin
  if (ch.IS_NPC) then
    exit;

  GPlayer(ch).save(ch.name^);
  ch.sendBuffer('Ok.'#13#10);
end;

procedure do_afk(ch : GCharacter; param : string);
begin
  GConnection(ch.conn).afk := true;
  ch.sendBuffer('You are now listed as AFK. Hitting ENTER will cease this.'#13#10);
end;

type 
  THelpKeyword = class
                   keyword : string;
                   phelp : GHelp;
                   constructor Create(str : string; p : GHelp);
                 end;

constructor THelpKeyword.Create(str : string; p : GHelp);
begin
  inherited Create();

  keyword := str;
  phelp := p;
end;

{ Xenon 22/Apr/2001: helper function for do_help() and do_apropos() }
procedure insertAlphabetical(var ll : GDLinkedList; hk : THelpKeyword);
var
  node, ins : GListNode;
  s : THelpKeyword;
begin
  ins := nil;
  node := ll.head;

  if (ll.head = nil) then
  begin
    ll.insertLast(hk);
    exit;
  end;

  while (node <> nil) do
  begin
    s := node.element;

    if (AnsiCompareStr(hk.keyword, s.keyword) > 0) then
    begin
      ins := node;
    end
    else
    begin
      ll.insertBefore(node, hk);
      exit;
    end;
    
    node := node.next;
  end;

  ll.insertAfter(ins, hk)
end;


{ Revised help - Nemesis }
{ Xenon 16/Apr/2001: - help without arguments now gives sorted keywordlist
                     - help with an arg that matches multiple keywords will show matching keywords}
procedure do_help(ch : GCharacter; param : string);
var buf, s, keyword : string;
    help : GHelp;
    counter : integer;
    node : GListNode;
    keywordlist : GDLinkedList;
    hk : THelpKeyword;
    done : boolean;
begin
  keywordlist := nil; hk := nil;
  done := false;
  counter := 0;
  
  if (length(param) = 0) then
  begin
    buf := ch.ansiColor(3) + ' ' + add_chars(78, '---- Available help keywords ', '-') + ch.ansiColor(7) + #13#10#13#10;

    keywordlist := GDLinkedList.Create();
    
    node := help_files.head;
    while (node <> nil) do
    begin
      help := node.element;

      keyword := help.keywords;

      while (length(keyword) > 0) do
      begin
        keyword := one_argument(keyword, s);

        if ((s[length(s)] <> '_') and (help.level <= ch.level)) then
        begin
          hk := THelpKeyword.Create(lowercase(s), help);

          insertAlphabetical(keywordlist, hk);
        end;
          
      end;

      node := node.next;
    end;

    node := keywordlist.head;
    while (node <> nil) do
    begin
      buf := buf + pad_string(THelpKeyword(node.element).keyword, 19);
      inc(counter);

      if (counter = 4) then
      begin
        buf := buf + #13#10;
        counter := 0;
      end;      
      node := node.next;
    end;

    keywordlist.Clean();
    keywordlist.Free();
    ch.sendPager(buf + #13#10);
    exit;
  end;

  keywordlist := GDLinkedList.Create();
  node := help_files.head;
  while (node <> nil) do
  begin
    help := node.element;

    keyword := help.keywords;

    while (length(keyword) > 0) do
    begin
      keyword := one_argument(keyword, s);

      if (s[length(s)] <> '_') then
      begin
        if ((pos(uppercase(param), s) = 1) and (help.level <= ch.level)) then
        begin
          hk := THelpKeyword.Create(lowercase(s), help);
          insertAlphabetical(keywordlist, hk);
        end;
        if ((uppercase(param) = s) and (help.level <= ch.level)) then // if it's a 1-on-1 match, stop right away
        begin
          keywordlist.Clean();
          keywordlist.Free();
          keywordlist := GDLinkedList.Create();
          keywordlist.insertLast(THelpKeyword.Create(lowercase(s), help));
          done := true;
          break;
        end;
      end;
    end;

    if (done) then
      break;
      
    node := node.next;
  end;
  
  if (keywordlist.getSize() = 0) then
  begin
    ch.sendBuffer('No help on that word.'#13#10)
  end
  else
  if (keywordlist.getSize() = 1) then
  begin
    help := THelpKeyword(keywordlist.head.element).phelp;
    buf := '$A$3 ' + add_chars(78, '---- Help topic ', '-') + '$A$7'#13#10#13#10 +
           'Name:    $A$3' + help.keywords + #13#10 + '$A$7' +
           'Type:    $A$3' + help.helptype + #13#10 + '$A$7' +
           'Syntax:  $A$3' + help.syntax + #13#10 + '$A$7' +
           'Related: $A$3' + help.related + #13#10 + '$A$7' +
           #13#10 + help.text;

    ch.sendPager(act_string(buf, ch, nil, nil, nil));
  end
  else
  if (keywordlist.getSize() > 1) then
  begin
    buf := Format('Your help query ''$B$7%s$A$7'' matched $B$7%d$A$7 keywords:'#13#10#13#10, [param, keywordlist.getSize()]);
    node := keywordlist.head;
    while (node <> nil) do
    begin
      buf := buf + Format('  $B$7%s$A$7'#13#10, [THelpKeyword(node.element).keyword]);
      node := node.next;
    end;

    ch.sendPager(act_string(buf, ch, nil, nil, nil));
  end;

  keywordlist.Clean();
  keywordlist.Free();
end;

procedure do_remort(ch : GCharacter; param : string);
begin
  ch.sendBuffer('Disfunctional. Sorry.'#13#10);
end;

{ Revised - Nemesis }
procedure do_delete(ch: GCharacter; param : string);
var f:file;
begin
  if (ch.IS_NPC) then
    begin
    ch.sendBuffer('NPCs cannot delete.'#13#10);
    exit;
    end;

  if (not MD5Match(GPlayer(ch).md5_password, MD5String(param))) then
    begin
    ch.sendBuffer('Type DELETE <password> to delete. WARNING: This is irreversible!'#13#10);
    exit;
    end;

  GConnection(ch.conn).send('You feel yourself dissolving, atom by atom...'#13#10);

  write_console(ch.name^ + ' has deleted');
  GPlayer(ch).quit;

  assignfile(f, 'players\' + ch.name^ + '.usr');
  rename(f, 'backup\' + ch.name^ + '.usr');
end;

procedure do_wimpy(ch : GCharacter; param : string);
var wimpy:integer;
begin
  if (length(param) = 0) or (ch.IS_NPC) then
    begin
    ch.sendBuffer('Set wimpy to what?'#13#10);
    exit;
    end;

  try
    wimpy := strtoint(param);
  except
    ch.sendBuffer('That is not a valid number.'#13#10);
    exit;
  end;

  if (wimpy > ch.max_hp div 3) then
    ch.sendBuffer('Your wimpy cannot be higher than 1/3 of your total hps!'#13#10)
  else
    begin
    GPlayer(ch).wimpy := wimpy;
    ch.sendBuffer('Wimpy set to '+inttostr(wimpy)+'.'+#13#10);
    end;
end;

{ Allow players to lock their keyboard - Nemesis }
procedure do_keylock(ch : GCharacter; param: string);
begin
  GConnection(ch.conn).afk := true;
  GConnection(ch.conn).keylock := true;

  ch.sendBuffer('You are now away from keyboard.'#13#10);
  ch.sendBuffer('Enter your password to unlock.'#13#10);
end;

// Handle Notes - Nemesis
procedure do_note(ch : GCharacter; param : string);
var arg1, arg2, buf : string;
    number, counter : integer;
    note : GNote;
    node : GListNode;
begin
  if (ch.IS_NPC) then
    exit;

  param := one_argument(param, arg1);
  one_argument(param, arg2);

  if (length(arg1) = 0) then
    begin
    ch.sendBuffer('Usage: NOTE READ <number>'#13#10);
    ch.sendBuffer('       NOTE WRITE'#13#10);
    ch.sendBuffer('       NOTE LIST'#13#10);

    if (ch.IS_IMMORT) then
      ch.sendBuffer('       NOTE DELETE <number>'#13#10);

    exit;
    end
  else
  if (uppercase(arg1) = 'WRITE') then
    begin
    ch.substate := SUB_SUBJECT;

    ch.sendBuffer('You are now away from keyboard.'#13#10#13#10);
    act(AT_REPORT,'$n has left $s keyboard and starts writing a note.',false,ch,nil,nil,to_room);

    ch.sendBuffer('You start writing a note on the ' + board_names[GPlayer(ch).active_board] + ' board.'#13#10);
    GPlayer(ch).startEditing('');
    exit;
    end
  else
  if (uppercase(arg1) = 'LIST') then
    begin
    counter := 0;
    node := notes.head;

    if (node = nil) then
      begin
      ch.sendBuffer('There are no notes on this board.'#13#10);
      exit;
      end;

    while (node <> nil) do
      begin
      note := node.element;

      if (note.board = GPlayer(ch).active_board) then
        begin
        inc(counter);
        buf := buf + ch.ansiColor(15) + ' ' + pad_integer_front(note.number,3) + ch.ansiColor(7) + '>   ' + pad_string(note.author,20) + ' ' + note.subject + #13#10;
        end;

      node := node.next;
      end;

    if (counter = 0) then
      buf := ch.ansiColor(7) + 'There are no notes on this board.' + #13#10;

    buf := ch.ansiColor(8) + '[' + ch.ansiColor(9) + 'Num ' + ch.ansiColor(8) + '] ' +
           ch.ansiColor(8) + '[' + ch.ansiColor(9) + 'Author            ' + ch.ansiColor(8) + '] ' +
           ch.ansiColor(8) + '[' + ch.ansiColor(9) + 'Subject               ' + ch.ansiColor(8) + ']' + #13#10 + #13#10 + buf;

    ch.sendPager(buf);
    exit;
    end
  else
  if (uppercase(arg1) = 'READ') then
    begin
    if (length(arg2) = 0) then
      begin
      ch.sendBuffer('Usage: NOTE READ <number>'#13#10);
      exit;
      end;

    try
      number := strtoint(arg2);
    except
      ch.sendBuffer('Usage: NOTE READ <number>'#13#10);
      exit;
    end;

    note := findNote(GPlayer(ch).active_board, number);

    if (note = nil) then
      begin
      ch.sendBuffer('That is not a valid number.'#13#10);
      exit;
      end;

    buf := ch.ansiColor(3) + add_chars(76, '---- Note by ' + note.author, '-') + #13#10 +
           ch.ansiColor(7) + 'Date:    ' + ch.ansiColor(7) + note.date + #13#10 +
           ch.ansiColor(7) + 'Subject: ' + ch.ansiColor(7) + note.subject + #13#10 +
           ch.ansiColor(3) + add_chars(76, '', '-') + #13#10#13#10 +
           ch.ansiColor(7) + note.text +
           ch.ansiColor(3) + add_chars(76, '', '-') + #13#10;

    ch.sendPager(buf);

    GPlayer(ch).boards[GPlayer(ch).active_board] := number;
    exit;
    end
  else
  if (uppercase(arg1) = 'DELETE') then
    begin
    if (length(arg2) = 0) then
      begin
      ch.sendBuffer('Usage: NOTE DELETE <number>'#13#10);
      exit;
      end;

    try
      number := strtoint(arg2);
    except
      ch.sendBuffer('Usage: NOTE DELETE <number>'#13#10);
      exit;
    end;

    node := notes.head;

    if (node = nil) then
      begin
      ch.sendBuffer('There are no notes to delete.'#13#10);
      exit;
      end;

    while (node <> nil) do
      begin
      note := node.element;

      if (note.board = GPlayer(ch).active_board) and (note.number = number) then
        begin
        notes.remove(node);
        save_notes;
        ch.sendBuffer('Note succesfully deleted.'#13#10);
        exit;
        end;

      node := node.next;
      end;

    ch.sendBuffer('Not a valid number.'#13#10);
    exit;
    end
  else
    begin
    ch.sendBuffer('Usage: NOTE READ <number>'#13#10);
    ch.sendBuffer('       NOTE WRITE'#13#10);
    ch.sendBuffer('       NOTE LIST'#13#10);

    if (ch.IS_IMMORT) then
      ch.sendBuffer('       NOTE DELETE <number>'#13#10);

    exit;
    end
end;

// Bulletinboard - Nemesis
procedure do_board(ch : GCharacter; param : string);
var node : GListNode;
    i, counter, boardnumber : integer;
    note : GNote;
    arg1 : string;
begin
  if (ch.IS_NPC) then
    exit;

  param := one_argument(param, arg1);

  if (length(arg1) > 0) then
    begin
    try
      boardnumber := strtoint(arg1);

      if (boardnumber < BOARD1) or (boardnumber >= BOARD_MAX) or ((boardnumber = BOARD_IMM) and (not ch.IS_IMMORT)) then
        begin
        ch.sendBuffer('That board is not available.'#13#10);
        exit;
        end;

      GPlayer(ch).active_board := boardnumber;
      ch.sendBuffer('Current board changed to ' + board_names[GPlayer(ch).active_board] + '.'#13#10);
      exit;
    except
      arg1 := '';
    end;
    end;

  if (length(arg1) = 0) then
    begin
    act(AT_REPORT, '$8[$B$1Num$A$8] [$B$1Name      $A$8] [$B$1New$A$8] [$B$1Description$A$8]'#13#10,false,ch,nil,nil,TO_CHAR);

    for i:=1 to BOARD_MAX-1 do
      begin
      counter := 0;
      node := notes.head;

      while (node <> nil) do
        begin
        note := node.element;

        if (note.board = i) then
          begin
          if (note.number > counter) then
            counter := note.number;
          end;

        node := node.next;
        end;

      counter := counter - GPlayer(ch).boards[i];

      if (i = BOARD_IMM) then
        begin
        if (ch.IS_IMMORT) then
          act(AT_REPORT, '$B$7 ' + pad_integer_front(i, 2) + '$A$7>   ' + pad_string(board_names[i],10) + '   ' + pad_integer(counter,3) + '   ' + board_descr[i],false,ch,nil,nil,TO_CHAR);
        end
      else
        act(AT_REPORT, '$B$7 ' + pad_integer_front(i, 2) + '$A$7>   ' + pad_string(board_names[i],10) + '   ' + pad_integer(counter,3) + '   ' + board_descr[i],false,ch,nil,nil,TO_CHAR);
      end;

    ch.sendBuffer(#13#10 + ch.ansiColor(7) + 'Your current board is ' + board_names[GPlayer(ch).active_board] + '.'#13#10);

    if (GPlayer(ch).active_board = BOARD_NEWS) and (not ch.IS_IMMORT) then
      ch.sendBuffer(ch.ansiColor(7) + 'You can only read from this board.'#13#10)
    else
      ch.sendBuffer(ch.ansiColor(7) + 'You can both read and write on this board.'#13#10);
    end;
end;

{ Xenon 23/Apr/2001: apropos searches through all helpfiles for a match on user input }
procedure do_apropos(ch : GCharacter; param : string);
var
  node : GListNode;
  help : GHelp;
  matchlist : GDLinkedList;
  hk : THelpKeyword;
  s : string;
begin
  if (ch.IS_NPC) then
    exit;

  if (length(param) = 0) then
  begin
    ch.sendBuffer('Usage: APROPOS <text>'#13#10#13#10);
    ch.sendBuffer('Apropos searches for ''text'' in the online helpfiles.'#13#10);
    exit;
  end;

  matchlist := GDLinkedList.Create();
  
  node := help_files.head;
  while (node <> nil) do
  begin
    help := node.element;

    s := help.keywords;
    
    if ((s[length(s)] <> '_') and (pos(param, help.text) > 0) and (help.level <= ch.level)) then
    begin
      hk := THelpKeyword.Create(lowercase(s), help);
      insertAlphabetical(matchlist, hk);
    end;

    node := node.next;
  end;

  if (matchlist.getSize() = 0) then
  begin
    ch.sendBuffer(Format('No matches found for your query ''%s''.'#13#10, [param]));
    exit;
  end
  else
  begin
    ch.sendPager(act_string(Format('Found $B$7%d$A$7 helpfiles that match your query ''$B$7%s$A$7'':'#13#10#13#10, [matchlist.getSize(), param]), ch, nil, nil, nil));
    
    node := matchlist.head;
    while (node <> nil) do
    begin
      hk := node.element;
    
      ch.sendPager(act_string(Format('  $B$7%s$A$7'#13#10, [hk.keyword]), ch, nil, nil, nil));

      node := node.next;
    end;
  end;

  matchlist.Clean();
  matchlist.Free();
end;

{$I include\cmd_imm.inc}
{$I include\cmd_info.inc}
{$I include\cmd_move.inc}
{$I include\cmd_fight.inc}
{$I include\cmd_magic.inc}
{$I include\cmd_skill.inc}
{$I include\cmd_comm.inc}
{$I include\cmd_obj.inc}
{$I include\cmd_shops.inc}
{$I include\cmd_build.inc}