grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
// $Id: cmd_imm.inc,v 1.16 2004/04/04 22:13:01 druid Exp $

procedure do_shutdown(ch : GCharacter; param : string);
var
  haltparam : string;
  serverInstance : GServer;
  delay : integer;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: SHUTDOWN <stop/halt/reboot/copyover> [time]'#13#10#13#10);
    ch.sendBuffer('If time is not given, a default of 30 seconds is assumed.'#13#10);
    ch.sendBuffer('Using "stop" as a parameter halts the shutdown.'#13#10);
    ch.sendBuffer('Using "now" as time value enables immediate shutdown.'#13#10);
    exit;
    end;
    
  serverInstance := GServer.Create();

    param := one_argument(param, haltparam);
  
    if (prep(param) = 'NOW') then
      delay := 0
    else
      try
      delay := StrToInt(param);
    except
          ch.sendBuffer('Boot timer must be a valid numeric value!'#13#10);
          exit;
    end;

  if (haltparam = 'stop') then
    begin
    act(AT_REPORT, 'Timer stopped.',false,ch,nil,nil,TO_CHAR);
    end
  else
  if (haltparam = 'reboot') then
    begin
    act(AT_REPORT,'REBOOT started.',false,ch,nil,nil,TO_CHAR);

    serverInstance.shutdown(SHUTDOWNTYPE_REBOOT, delay);
    end
  else
  if (haltparam = 'halt') then
    begin
    act(AT_REPORT,'SHUTDOWN started.',false,ch,nil,nil,TO_CHAR);

    serverInstance.shutdown(SHUTDOWNTYPE_HALT, delay);
    end
  else
  if (haltparam = 'copyover') then
    begin
    act(AT_REPORT, 'COPYOVER started.',false,ch,nil,nil,TO_CHAR);

    serverInstance.shutdown(SHUTDOWNTYPE_COPYOVER, delay);
    end
  else
    ch.sendBuffer('Illegal parameter: use "stop", "halt", "reboot" or "copyover".'#13#10);
  
  serverInstance.Free();
end;

// Send message to all players
procedure do_echo(ch : GCharacter; param : string);
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Usage: ECHO <text>'#13#10);
    exit;
    end;
    
  act(AT_LOG, param, false, ch, nil, nil, TO_CHAR);
  act(AT_ECHO, param, false, ch, nil, nil, TO_ALL);
end;

// Wizinvis
procedure do_wizinvis(ch : GCharacter; param : string);
var
  level : integer;
begin
  if (ch.IS_NPC) then
    exit;

  if (ch.IS_WIZINVIS) then
    begin
    act(AT_REPORT,'You feel yourself brightening.', false, ch, nil, nil, TO_CHAR);
    act(AT_REPORT,'A light shines and $n appears.', false, ch, nil, nil, TO_ROOM);
    
    REMOVE_BIT(GPlayer(ch).flags,PLR_WIZINVIS);
    GPlayer(ch).wiz_level := 0;
    end
  else
    begin
    if (length(param)>0) then
      try
        level := strtoint(param);
      except
        ch.sendBuffer('Invalid numeric format.'#13#10);
        exit;
      end
    else
      level := ch.level;

    act(AT_REPORT,'You wave your hand and disappear.', false, ch, nil, nil, TO_CHAR);
    act(AT_REPORT,'$n waves $s hand and disappears in a storm of colors.', false, ch, nil, nil, TO_ROOM);
    
    SET_BIT(GPlayer(ch).flags,PLR_WIZINVIS);
    GPlayer(ch).wiz_level := level;
    end;
end;

// Dymmy command to protect SLAY
procedure do_sla(ch : GCharacter; param : string);
begin
  ch.sendBuffer('You must type out the command.'#13#10);
end;

// Slay pc/npc
procedure do_slay(ch : GCharacter; param : string);
var
  t : GCharacter;
  dam : integer;
begin
  if (length(param) = 0) then
    ch.sendBuffer('Slay whom?'#13#10)
  else
    begin
    t := ch.room.findChar(ch, param);

    if (t = nil) then
      ch.sendBuffer('They are not here.'#13#10)
    else
    if (t = ch) then
      ch.sendBuffer('You can''t slay yourself!'#13#10)
    else
      begin
      act(AT_SLAY,'You slay $N in cold blood!', false, ch, nil, t, TO_CHAR);
      act(AT_SLAY,'$n slays you in cold blood!', false, ch, nil, t, TO_VICT);
      act(AT_SLAY,'$n slays $N in cold blood!', false, ch, nil, t, TO_NOTVICT);
      
      dam := UMax(t.max_hp, t.hp * 2);
      damage(ch, t, dam, TYPE_SLAY);
      end;
    end;
end;

// Advance pc to a higher level
procedure do_advance(ch : GCharacter; param : string);
var
  vict : GCharacter;
  lvl, num, a : integer;
  vict_nm : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Advance whom?'#13#10);
    exit;
    end;

  param := one_argument(param, vict_nm);
  vict := findcharworld(ch, vict_nm);

  if (vict.IS_NPC()) then
  begin
    ch.sendBuffer('This command does not work on NPCs.'#13#10);
    exit;
  end;

  try
    lvl := strtoint(param);
  except
    ch.sendBuffer('Invalid numeric format.'#13#10);
    exit;
  end;
  if (lvl > LEVEL_MAX) then
    ch.sendBuffer('Use GRACE to give a character immortal status.'#13#10)
  else
  if (vict = nil) then
    ch.sendBuffer('That character is not online right now.'#13#10)
  else
  begin
    num := lvl - vict.level;
    vict.in_command := true;

    for a:=1 to num do
      gain_xp(GPlayer(vict), GPlayer(vict).xptogo);

    act(AT_REPORT,'You have advanced $N to level '+inttostr(vict.level)+'.', false, ch, nil, vict, TO_CHAR);
    act(AT_REPORT,'$N has advanced you to level '+inttostr(vict.level)+'!', false, vict, nil, ch, TO_CHAR);

    vict.in_command := false;
  end;
end;

{Jago 5/Jan/2001 : repaired to work with v 0.3.0}
{ Xenon 22/Apr/2001: added (vict = nil) check }
// Grace pc Immortal status
procedure do_grace(ch : GCharacter; param : string);
var 
  vict : GCharacter;
  lev : integer;
  vict_nm : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer( 'Usage: GRACE <character> <level>'#13#10#13#10);
    ch.sendBuffer( 'Use this command to immortalize players.'#13#10);
    exit;
    end;

  param := one_argument(param, vict_nm);
  vict := findcharworld(ch, vict_nm);

  // Player not found
  if (vict = nil) then
    begin
    ch.sendBuffer('Couldn''t find that player online.'#13#10);
    exit;
    end;
  
  lev := strtointdef(param, 0);

  if (vict.IS_NPC) then
    ch.sendBuffer( 'Can only grace players.'#13#10)
  else
  if (ch.level < LEVEL_MAX) then
    ch.sendBuffer( 'That character is too low a level, use ADVANCE first.'#13#10)
  else
  if (lev > ch.level) then
    ch.sendBuffer( 'You cannot raise someone to that level.'#13#10)
  else
  if (vict = nil) then
    ch.sendBuffer( 'That character is not online right now.'#13#10)
  else
  if (lev < LEVEL_IMMORTAL) or (lev > LEVEL_MAX_IMMORTAL) then
    ch.sendBuffer( string('That level is not in the appropriate range. Use ' + inttostr(LEVEL_IMMORTAL) + ' to ' + inttostr(LEVEL_MAX_IMMORTAL) + '.'#13#10))
  else
    begin
    act(AT_REPORT,'You suddenly feel a pressure on you...', false, vict, nil, nil, TO_CHAR);
    act(AT_REPORT,'You have become more powerful!'#13#10, false, vict, nil, nil, TO_CHAR);

    if ((lev > LEVEL_MAX) and (lev <= LEVEL_MAX_IMMORTAL)) then         // Xenon 20/Feb/2001 : replaced vict.level = 500 with lev = 1000
      begin
      { Set hps etc. to immortal level }
      vict.max_hp := 15000;
      vict.max_mv := 15000;
      vict.max_mana := 15000;
      vict.hp := 15000;
      vict.mv := 15000;
      vict.mana := 15000;
      vict.str := 100;
      vict.con := 100;
      vict.dex := 100;
      vict.int := 100;
      vict.wis := 100;
      vict.sendBuffer(findHelp('M_IMMORTALIZE_').text);
      end
    else
      act(AT_REPORT,'You feel yourself growing... to a higher level of understanding.', false, vict, nil, nil, TO_CHAR);

    vict.level := lev;
    act(AT_REPORT,'You have attained the rank of '+IMM_Types[vict.level]+'.', false, vict, nil, nil, TO_CHAR);
    ch.sendBuffer('Ok.'#13#10);
    //recalcac(ch);
    ch.calcAC();
    end;
end;

// Destroy pc (deletes players)
procedure do_destroy(ch : GCharacter; param : string);
var
   vict : GCharacter;
   f : textfile;
   s,g : string;
   level : integer;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  DESTROY <player>'#13#10#13#10);
    ch.sendBuffer('Logs this player out and moves the playerfile to the backup directory.'#13#10);
    exit;
    end;

  // Search for player
  vict := findCharWorld(ch,param);

  if (vict <> nil) then
    begin
    if (vict.IS_NPC) then
      ch.sendBuffer('Can only destroy players.'#13#10)
    else
    if (vict.IS_IMMORT) then
      ch.sendBuffer('That player (online) cannot be destroyed.'#13#10)
    else
    if (vict = ch) then
      ch.sendBuffer('Use DELETE to erase yourself.'#13#10)
    else
      begin
      stopfighting(vict);
      vict.sendBuffer(#13#10 + findHelp('M_DESTROY_').text);
      vict.emptyBuffer;
      GPlayer(vict).quit;

      ch.sendBuffer('Ok.'#13#10);
      writeConsole(vict.name + ' has been destroyed.');

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

  if FileExists('players\' + param + '.usr') then
    begin

    assignfile(f,'players\' + param + '.usr');
    reset(f);

    repeat
      readln(f, s);

      g := uppercase(left(s, ':'));

      if (g = 'LEVEL') then
        begin
        level := strtoint(right(s, ' '));

        if (level >= 990) then
          begin
          ch.sendBuffer('That player (offline) cannot be destroyed.'#13#10);
          closefile(f);
          exit;
          end;
        end;
    until (eof(f));

    closefile(f);

    writeConsole(param + ' has been destroyed.');
    ch.sendBuffer('Ok.'#13#10);

    rename(f, 'backup\' + param + '.usr');
    end
  else
    begin
    ch.sendBuffer('That player cannot be found.'#13#10);
    exit;
    end;
end;

{Jago 5/Jan/01 : implemented do_force to use GCharacter instead of CHAR_DATA}
// Force a pc/npc
procedure do_force(ch : GCharacter; param : string);
var
  vict_node : GListnode;
  vict : GCharacter;
  //sub:array[0..63] of char;
  sub : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  FORCE <[name]/ALL/ALLPC> <command>'#13#10);
    exit;
    end;

  param := one_argument(param,sub);

  // Force ALL
  if (prep(sub) = 'ALL') then
    begin
    if  ch.getTrust < system_info.level_forcepc then
      begin
      ch.sendBuffer('You must be a higher level to force players.'#13#10);
      exit;
      end;
      
    act(AT_WHITE,'You force everybody to "'+param+'".', false, ch, nil, nil, TO_CHAR);

    vict_node := char_list.head;

    while vict_node <> nil do
      begin
      vict := GCharacter(vict_node.element);
      
      if vict <> ch then
        begin
        act(AT_WHITE,'$n forces you to "' + param + '"', false, ch, nil, vict, TO_VICT);
        interpret(vict,param);
        end;
        
      vict_node := vict_node.next;
      end;
    end
  else
  // Force ALL pc
  if (prep(sub) = 'ALLPC') then
    begin
    if ch.getTrust < system_info.level_forcepc then
      begin
      ch.sendBuffer('You must be a higher level to force players.'#13#10);
      exit;
      end;
      
    act(AT_WHITE,'You force all players to "'+param+'".', false, ch, nil, nil, TO_CHAR);

    vict_node := char_list.head;

    while vict_node <> nil do
      begin
      vict := GCharacter(vict_node.element);
      
      if (vict <> ch) and (not vict.IS_NPC) then
        begin
        act(AT_WHITE,'$n forces you to "' + param + '"', false, ch, nil, vict, TO_VICT);
        interpret(vict,param);
        end;
        
      vict_node := vict_node.next;
      end;
    end
  else
  // force <name>
    begin
    { first find victim in room, if any }
    vict := ch.room.findChar(ch,sub);

    if (vict = nil) then
      vict := FindCharWorld(ch,sub);
    if (vict = nil) then
      ch.sendBuffer('They aren''t here.'#13#10)
    else
      begin
      if (not vict.IS_NPC) and (ch.getTrust < system_info.level_forcepc) then
        begin
        ch.sendBuffer('You must be a higher level to force players.'#13#10);
        exit;
        end;
        
      act(AT_WHITE,'You force $N to "'+param+'".$A$7', false, ch, nil, vict, TO_CHAR);
      act(AT_WHITE,'$n forces you to "' + param + '"', false, ch, nil, vict, TO_VICT);
      
      interpret(vict,param);
      end;
    end;
end;

{Jago 5/Jan/01 : implemented do_transfer as done in MERC (implementation not quite identical to MERC)}
// Transfer pc/npc to room
procedure do_transfer( ch : GCharacter; param : string );
var
  arg1, arg2 : string;
  location : GRoom;
  victim : GCharacter;
  char_node : GListNode;
begin
  param := one_argument( param, arg1 ); // who to trans
  param := one_argument( param, arg2 ); // where to trans

  if (length(arg1) = 0) then
    begin
    ch.sendBuffer('Transfer whom (and where)?'#13#10);
    exit;
    end;

  // get the trans location.  could be ch.room or a location given by arg2
  if length(arg2) = 0 then
    location := ch.room
  else
    location := findLocation(ch, arg2);

  if (location = nil) then
    begin
    ch.sendBuffer('Transfer them where??');
    exit;
    end;

  // Tranfser ALL
  if (uppercase(arg1) = 'ALL') then
    begin
    char_node := char_list.head;

    while char_node <> nil do
      begin
      victim := GCharacter(char_node.element);

      // Players only
      if not (victim.IS_NPC) then
        begin
        if (victim.fighting <> nil) then
          stopFighting(victim);
          
        act(AT_WHITE,'$n disappears in a mushroom cloud.', false, victim, nil,nil, TO_ROOM);
        
        victim.fromRoom();
        victim.toRoom(location);
        
        act(AT_WHITE,'$n arrives from a puff of smoke.', false, victim, nil, nil, TO_ROOM);
        
        if (ch <> victim) then
          act(AT_WHITE,'$n has transferred you.', false, ch, nil, victim, TO_VICT);
          
        interpret(victim, 'look _AUTO');
        end;

      char_node := char_node.next;
      end;
    end
  else
  // transfer single victim
    begin
    victim := findCharWorld(ch, arg1);

    if (victim <> nil) then
      begin
      if (victim.fighting <> nil) then
        stopFighting(victim);
      
      act(AT_WHITE,'$n disappears in a mushroom cloud.',false,victim,nil,nil,TO_ROOM);
      
      victim.fromRoom();
      victim.toRoom(location);
      
      act(AT_WHITE,'$n arrives from a puff of smoke.',false,victim,nil,nil,TO_ROOM);

      if (ch <> victim) then
        act(AT_WHITE,'$n has transferred you.',false,ch,nil,victim,TO_VICT);

      interpret(victim, 'look _AUTO');
      end;
    end;
end;

{Jago 5/Jan/01 : implemented do_goto as done in MERC }
// Goto pc/npc/room
procedure do_goto(ch : GCharacter; param: string);
var
  location : GRoom;
  locn_name : string;
  vnum : integer;
  new_room : GRoom;
begin
  param := one_argument(param, locn_name);

  if (length(locn_name) = 0) then
    begin
    ch.sendBuffer('Goto where?' + #13#10);
    exit;
    end;

  // Find location
  location := findLocation(ch, locn_name);

  if (not ch.IS_NPC) and (location = nil) then // if vnum doesn't exist yet and vnum is in builders range, create the room
    begin
    try
      if (length(GPlayer(ch).area_fname) = 0) then
        raise Exception.Create('no area assigned');
  
      vnum := StrToInt(locn_name);
     
      if (vnum >= GPlayer(ch).r_lo) and (vnum < GPlayer(ch).r_hi) then
        if (GPlayer(ch).area = nil) then
          begin
          ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
          exit;
          end
        else
          begin
          ch.sendBuffer(ch.ansiColor(15) + 'Creating room #' + inttostr(vnum) + '.' + ch.ansiColor(7) + #13#10#13#10);
          new_room := createRoom(vnum, GPlayer(ch).area);
          ch.fromRoom();
          ch.toRoom(new_room);
          interpret(ch, 'look');
          exit;
          end
      else
        begin
        ch.sendBuffer('That vnum is not within your assigned room ranges.'#13#10);
        exit;
        end;
    except
      ch.sendBuffer('No such location!' + #13#10);
      exit;
    end;
    end;

  if (location.flags.isBitSet(ROOM_PRIVATE)) then
    begin
    ch.sendBuffer('That room is private right now.' + #13#10);
    exit;
    end;

  if (ch.fighting <> nil) then
    stopFighting(ch);

 {goto while hunting not tested! - result may be unpredictable!!}
 {if ch.hunting <> nil then
 begin
  ch.hunting := nil;
  REMOVE_BIT(ch.act_flags, ACT_HUNTING);
 end;}

  if (not ch.IS_WIZINVIS) and (not ch.IS_NPC) then
    begin
    if (GPlayer(ch).bamfout <> '') then
      act(AT_WHITE, GPlayer(ch).bamfout,false,ch,nil,nil,TO_ROOM)
    else
      act(AT_WHITE,'$n leaves in a swirling mist.',false,ch,nil,nil,TO_ROOM);
    end;
  
  ch.fromRoom();
  ch.toRoom(location);

  if (not ch.IS_WIZINVIS) and (not ch.IS_NPC) then
    begin
    if (GPlayer(ch).bamfin <> '') then
      act(AT_WHITE, GPlayer(ch).bamfin,false,ch,nil,nil,TO_ROOM)
    else
      act(AT_WHITE,'$n appears in a swirling mist.',false,ch,nil,nil,TO_ROOM);
    end;

  interpret(ch, 'look _AUTO');
end;

{Jago 5/Jan/2001 : repaired to work with v 0.3.0}
// Display list of active connections
procedure do_connections(ch : GCharacter; param : string);
var
  s : string;
  conn : GPlayerConnection;
  iterator : GIterator;
begin
  act(AT_REPORT, '$8[$B$1Nr.$A$8] [$B$1State           $A$8] [$B$1' + pad_string('IP', 32) + '$A$8] [$B$1Name$A$8]'#13#10,false,ch,nil,nil,TO_CHAR);

  iterator := connection_list.iterator();
  
  while (iterator.hasNext()) do
    begin
    conn := GPlayerConnection(iterator.next());
    
    if (conn.ch <> nil) and (not conn.ch.IS_NPC) and (IS_SET(GPlayer(conn.ch).flags, PLR_CLOAK)) then
      continue;

    if (conn.ch <> nil) then
      s := conn.ch.name
    else
      s := '-';

    act(AT_REPORT,'$7($B$7' + pad_integer_front(conn.socket.getDescriptor,3) + '$A$7) '+
        pad_string(conn.stateAsString(), 16) + '   ' +
        pad_string(conn.socket.ipString, 32) + '   ' +
        s,false,ch,nil,nil,TO_CHAR);
    end;
  
  iterator.Free();
end;

// Set battleground
procedure do_bgset(ch : GCharacter; param : string);
var
  lo, hi, secs : integer;
  obj : GObject;
  buf : string;
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Usage:  BGSET <lo range> <hi range> <seconds> [object]'#13#10#13#10);
    ch.sendBuffer('Initiates a battleground for players within the range.'#13#10);
    exit;
    end;

  try
    param := one_argument(param,buf);
    lo := strtoint(buf);
    param := one_argument(param,buf);
    hi := strtoint(buf);
    param := one_argument(param,buf);
    secs := strtoint(buf);
  except
    ch.sendBuffer('Invalid numeric format.');
    exit;
  end;

  obj := ch.findInventory(param);

  bg_info.count := secs;
  bg_info.winner := nil;
  bg_info.lo_range := lo;
  bg_info.hi_range := hi;

  if (obj <> nil) then
    begin
    obj.seperate();
    obj.fromChar();
    bg_info.prize := obj;
    end
  else
    bg_info.prize := nil;

  ch.sendBuffer('Started the battleground.'#13#10);
  battlegroundMessage;
end;

// Snoop all activity from pc/npc
procedure do_snoop(ch : GCharacter; param : string);
var
  vict : GCharacter;
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Usage:  SNOOP <character>'#13#10#13#10);
    ch.sendBuffer('Snoops/sniffs every byte that is sent to this character.'#13#10);
    ch.sendBuffer('When using this, your own output will be discarded to prevent'#13#10);
    ch.sendBuffer('your screen from overflowing. To stop, type SNOOP SELF.'#13#10);
    exit;
    end;

  // Search player
  vict := findCharWorld(ch, param);
  
  if (vict = nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end
  else
  if (vict = ch) then
    begin
    if (GPlayer(ch).snooping <> nil) then 
      begin
      GPlayer(ch).snooping.snooped_by := nil;
      GPlayer(ch).snooping := nil;
      ch.sendBuffer('No longer snooping.'#13#10);
      end
    else
      ch.sendBuffer('You aren''t snooping anyone.'#13#10);
      
    exit;
    end
  else
  if (vict.IS_IMMORT()) and (vict.level >= ch.level) then
    begin
    ch.sendBuffer('Cannot snoop a same or higher level immortal.'#13#10);
    exit;
    end
  else
  if (vict.snooped_by <> nil) then
    begin
    ch.sendBuffer('That character is already being snooped by somebody.'#13#10);
    exit;
    end;

  act(AT_YELLOW,'Started snooping $N.', false, ch, nil, vict, TO_CHAR);
  
  GPlayer(ch).snooping := vict;
  vict.snooped_by := ch;
end;

// Loadup player
procedure do_loadup(ch : GCharacter; param : string);
var
  vict : GPlayer;
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Loadup whom?'#13#10);
    exit;
    end;

  if (not FileExists('players\' + param + '.usr')) then
    begin
    ch.sendBuffer('That player does not exist.'#13#10);
    exit;
    end
  else
  if (findCharWorld(ch, param) <> nil) then
    begin
    ch.sendBuffer('That player is already online.'#13#10);
    exit;
    end;

  act(AT_REPORT,'Loading '+param+'...', false, ch, nil, nil, TO_CHAR);

  vict := GPlayer.Create(nil);
  vict.load(param);
  
  SET_BIT(vict.flags,PLR_LOADED);
  SET_BIT(vict.flags,PLR_LINKLESS);

  vict.node_world := char_list.insertLast(vict);

  vict.toRoom(vict.room);
  act(AT_REPORT,'$N loaded.', false, ch, nil, vict, TO_CHAR);
  interpret(ch, 'goto '+vict.name);
end;

function yes_no(v:boolean):string;
begin
  if v then
    yes_no:='yes'
  else
    yes_no:='no';
end;

// System configuration
procedure do_sconfig(ch : GCharacter; param : string);
var
  sub : string;
  t : TInAddr;
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Usage:  SCONFIG <field> <value>'#13#10#13#10);
    ch.sendBuffer('Field can be one of the following:'#13#10#13#10);
    ch.sendBuffer('  show - to view current settings'#13#10#13#10);
    ch.sendBuffer('  name email port ip forcepc log'#13#10);
    ch.sendBuffer('  lookup denyconns denyplayers noback'#13#10);
    exit;
    end;

  if (param = 'show') then
    begin
    ch.sendBuffer('Current server configuration:'#13#10#13#10);
    act(AT_REPORT,'Name:            '+system_info.mud_name,false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'E-Mail:          '+system_info.admin_email,false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Port:            '+inttostr(system_info.port),false,ch,nil,nil,TO_CHAR);
    t.s_addr:=system_info.bind_ip;
    act(AT_REPORT,'IP:              '+inet_ntoa(t),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Level_forcepc:   '+inttostr(system_info.level_forcepc),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Level_log:       '+inttostr(system_info.level_log),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Host lookup:     '+yes_no(system_info.lookup_hosts),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Deny conns:      '+yes_no(system_info.deny_newconns),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'Deny players:    '+yes_no(system_info.deny_newplayers),false,ch,nil,nil,TO_CHAR);
    exit;
    end;

  param := one_argument(param,sub);

  if (length(param) = 0) then
  begin
    ch.sendBuffer('Please specify a new value for this option.'#13#10);
    exit;
  end;

  if (sub = 'name') then
    system_info.mud_name := param
  else
  if (sub = 'email') then
    system_info.admin_email := param
  else
  if (sub = 'port') then
    system_info.port := strtoint(param)
  else
  if (sub = 'ip') then
    system_info.bind_ip := inet_addr(pchar(param))
  else
  if (sub = 'forcepc') then
    system_info.level_forcepc := strtoint(param)
  else
  if (sub = 'log') then
    system_info.level_log := strtoint(param)
  else
  if (sub = 'lookup') then
    system_info.lookup_hosts := (param = '1') or (param = 'yes')
  else
  if (sub = 'denyconns') then
    system_info.deny_newconns := (param = '1') or (param = 'yes')
  else
  if (sub = 'denyplayers') then
    system_info.deny_newplayers := (param = '1') or (param = 'yes')
  else
    begin
    ch.sendBuffer('Invalid option.'#13#10);
    exit;
    end;

  saveSystem();

  ch.sendBuffer('Ok. New config saved.'#13#10);
end;

// Ban site
procedure do_ban(ch : GCharacter; param : string);
var
   a, count : integer;
   buf : string;
begin
  if (length(param) = 0) then
    begin
    if (banned_masks.count=0) then
      begin
      ch.sendBuffer('No sites are currently banned.'#13#10);
      exit;
      end;

    buf := #13#10 + ch.ansiColor(3) + ' ' + add_chars(78, '---- Banned sites ', '-') + ch.ansiColor(7) + #13#10#13#10;
    ch.sendPager(buf);

    count := 0;

    for a := 0 to banned_masks.count - 1 do
      begin
      ch.sendPager(pad_string(banned_masks[a], 19));
      inc(count);

      if (count = 4) then
        begin
        ch.sendPager(#13#10);
        count := 0;
        end;
      end;

    ch.sendPager(#13#10);
    exit;
    end;

  act(AT_REPORT, 'Banned mask ''' + param + ''' has been added.', false, ch, nil, nil, TO_CHAR);
  banned_masks.add(param);
  
  saveSystem();
end;

// Allow banned site
procedure do_allow(ch : GCharacter; param : string);
var
  a : integer;
begin
  if (length(param) = 0) then
    begin
    do_ban(ch, param);
    exit;
    end;

  a := banned_masks.indexOf(param);
  if (a >= 0) then
    begin
    ch.sendBuffer('Ok.'#13#10);
    banned_masks.delete(a);    
    saveSystem();
    end
  else
    ch.sendBuffer('That mask is not in the ban list.'#13#10);
end;

// Log player activity
procedure do_log(ch : GCharacter; param : string);
var
  victim : GCharacter;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  LOG <all/player>'#13#10#13#10);
    ch.sendBuffer('Either logs all player activity or sets the log flag'#13#10);
    ch.sendBuffer('on a single player.'#13#10);
    exit;
    end;

  // Log ALL
  if (prep(param) = 'ALL') then
    begin
    system_info.log_all:=(not system_info.log_all);
    
    if (system_info.log_all) then
      ch.sendBuffer('Log ALL has been enabled.'#13#10)
    else
      ch.sendBuffer('Log ALL has been disabled.'#13#10);
      
    exit;
    end;

  // Search player
  victim := findCharWorld(ch,param);
  
  if (victim = nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  if (victim.logging) then
    begin
    victim.logging := false;
    act(AT_REPORT,'No longer logging $N.', false, ch, nil, victim, TO_CHAR);
    end
  else
    begin
    victim.logging := true;
    act(AT_REPORT,'Started logging $N.', false, ch, nil, victim, TO_CHAR);
    end;
end;

{Jago 5/Jan/2001 : repaired to work with v 0.3.0}
// Check server uptime
procedure do_uptime(ch : GCharacter; param : string);
var 
  i, total : integer;
  hv : GHashValue;
  room : GRoom;
  char : GCharacter;
  iterator : GIterator;
begin
  calculateonline;
  act(AT_REPORT,'[' + version_info + ', ' + version_number + '] '#13#10 + system_info.mud_name+#13#10,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT,'Online time:       ' + online_time,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT,'System time:       ' + DateTimeToStr(Now),false,ch,nil,nil,TO_CHAR);

{$IFDEF WIN32}
  status:=GetHeapStatus;
  act(AT_REPORT,'Heap allocated:    ' + inttostr(status.totalallocated)+' byte(s)',false,ch,nil,nil,TO_CHAR);
{$ENDIF}

  total := 0;
  iterator := room_list.iterator();
  
  while (iterator.hasNext()) do
    begin
    room := GRoom(iterator.next());
    
    inc(total, room.InstanceSize());
    inc(total, room.exits.size() * GExit.InstanceSize());
    inc(total, room.tracks.size() * GTrack.InstanceSize());
    inc(total, room.extra.size() * GExtraDescription.InstanceSize());
    end;

  iterator.Free();
  ch.sendBuffer('Rooms: ' + IntToStr(total) + #13#10);
  ch.sendBuffer('NPC indices: ' + IntToStr(GNPCIndex.InstanceSize() * npc_list.size()) + #13#10);
  ch.sendBuffer('Object indices: ' + IntToStr(GObject.InstanceSize() * objectIndices.size()) + #13#10);
  ch.sendBuffer('Object instances: ' + IntToStr(GObject.InstanceSize() * objectList.size()) + #13#10);

  total := 0;
  iterator := char_list.iterator();
  
  while (iterator.hasNext()) do
    begin
    char := GCharacter(iterator.next());
    
    if (char is GPlayer) then
      inc(total, GPlayer.InstanceSize())
    else
    if (char is GNPC) then
      inc(total, GNPC.InstanceSize());
    end; 
  
  iterator.Free();
  ch.sendBuffer('Characters: ' + IntToStr(total) + #13#10);

  total := 0;

  for i := 0 to str_hash.bucketcount - 1 do
    begin
    iterator := str_hash.buckets[i].iterator();

    while (iterator.hasNext()) do
      begin
      hv := GHashValue(iterator.next());

      inc(total, hv.refcount * length(GString(hv.value).value));
      end;

    iterator.Free();
    end;
    
  ch.sendBuffer('String buffer: ' + IntToStr(total) + #13#10);
  ch.sendBuffer('Programs: ' + IntToStr(GCodeBlock.InstanceSize() * codeCache.size()) + #13#10);
end;

// Switch into NPC
procedure do_switch(ch : GCharacter; param : string);
var
  vict : GCharacter;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  SWITCH <character>'#13#10);
    exit;
    end;

  // Search NPC
  vict := findCharWorld(ch,param);

  // NPC not found
  if (vict = nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  // Vict is not NPC
  if (not vict.IS_NPC) then
    begin
    ch.sendBuffer('Can not switch into players.'#13#10);
    exit;
    end;

  // NPC is already switched
  if (vict.snooped_by <> nil) then
    begin
    act(AT_REPORT,'$N is already switched.', false, ch, nil, vict, TO_CHAR);
    exit;
    end;

  ch.sendBuffer('Ok.'#13#10);

  GPlayer(ch).switching := vict;
  vict.snooped_by := ch;
end;

// Return from switched npc
procedure do_return(ch : GCharacter; param : string);
var
  vict : GCharacter;
begin
  if (ch.snooped_by = nil) or (GPlayer(ch.snooped_by).switching <> ch) then
    begin
    act(AT_REPORT,'You aren''t switched.', false, ch, nil, nil, TO_CHAR);
    exit;
    end;

  vict := ch.snooped_by;
  GPlayer(ch.snooped_by).switching := nil;
  ch.snooped_by := nil;
  
  vict.sendBuffer('Ok.'#13#10);

  vict.emptyBuffer();
end;

// All available immortal commands
procedure do_wizhelp(ch : GCharacter; param : string);
var
  iterator : GIterator;
  cmd : GCommand;
  cmdList : TStringList;
  i, lev : integer;
  buf : string;
begin
  cmdList := TStringList.Create();
  lev := ch.getTrust;
  
  iterator := commandList.iterator();
  
  while (iterator.hasNext()) do
    begin
    cmd := GCommand(iterator.next());
  
    // Show only immortal commands available at your level
    if (cmd.level > LEVEL_MAX) and (cmd.level <= lev) then
      cmdList.Add(lowercase(cmd.name));
    end;
    
  iterator.Free();
  
  // Sort the list
  cmdList.Sort();  
  
  buf := #13#10 + ch.ansiColor(3) + ' ' + add_chars(78, '---- Available immortal commands ', '-') + ch.ansiColor(7) + #13#10;
  
  for i := 0 to pred(cmdList.Count) do
    begin
    if (i mod 5 = 0) then
      buf := buf + #13#10 + pad_string(cmdList[i], 15)
    else
      buf := buf + pad_string(cmdList[i], 15);
    end;
  
  buf := buf + #13#10;
  
  cmdList.Free();
 
  ch.sendPager(buf);
end;

{Jago 5/Jan/01 : implemented do_restore to use GCharacter instead of CHAR_DATA, }
{             added restore all functionality}
// Regenerate hp/mana/moves
procedure do_restore(ch : GCharacter; param : string);
var
  victim : GCharacter;
  vict_node : GListNode;
begin
  if (length(param)=0) then
  begin
    ch.sendBuffer('Usage:  RESTORE <[character]/ALL>'#13#10);
    exit;
  end;

  // Restore ALL
  if (uppercase(param) = 'ALL') then
  begin
    vict_node := char_list.head;

    while vict_node <> nil do
      begin
      victim  := GCharacter(vict_node.element);
      if (victim <> ch) and (not victim.IS_NPC) then
        begin
        victim.hp := victim.max_hp;
        victim.mv := victim.max_mv;
        victim.mana := victim.max_mana;
        act(AT_REPORT,'$N has restored you.', false, victim, nil, ch, TO_CHAR);
        end;

      vict_node := vict_node.next;
      end; {while}
     ch.sendBuffer('Ok.'#13#10);
  end
  else
  // restore single char
    begin
    victim := FindCharWorld(ch,param);

    if (victim = nil) then
    begin
      ch.sendBuffer('That character does not exist.'#13#10);
      exit;
    end;

    victim.hp := victim.max_hp;
    victim.mv := victim.max_mv;
    victim.mana := victim.max_mana;

    ch.sendBuffer('Ok.'#13#10);
    act(AT_REPORT,'$N has restored you.', false, victim, nil, ch, TO_CHAR);
    end;
end;

{ Xenon 12/Apr/2001: freeze now only works on players lowerlevel than you and you cannot freeze yourself anymore :P }
procedure do_freeze(ch : GCharacter; param : string);
var 
  victim : GPlayer;
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Usage:  FREEZE <character>'#13#10#13#10);
    ch.sendBuffer('If the character is already frozen, this will unfreeze.'#13#10);
    exit;
    end;

  victim := GPlayer(findPlayerWorld(ch,param));
  
  if (victim = nil) then
    begin
    ch.sendBuffer('That character isn''t online.'#13#10);
    exit;
    end;

  if (victim = ch) then
    begin
    ch.sendBuffer('You cannot freeze yourself.'#13#10);
    exit;
    end;

  if (victim.level >= ch.level) then
    begin
    ch.sendBuffer('Can only freeze players lower level than you.'#13#10);
    exit;
    end;

  if (IS_SET(victim.flags,PLR_FROZEN)) then
    begin
    act(AT_REPORT,Format('You have defrosted $B$5%s$A$7.', [victim.name]),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'You have been un-frozen by $N.',false,victim,nil,ch,TO_CHAR);
    REMOVE_BIT(victim.flags,PLR_FROZEN);
    end
  else
    begin
    act(AT_REPORT,Format('You have frozen $B$5%s$A$7.', [victim.name]),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'You have been frozen by $N.',false,victim,nil,ch,TO_CHAR);
    SET_BIT(victim.flags,PLR_FROZEN);
    end;
end;

procedure do_silence(ch : GCharacter; param : string);
var 
  victim : GPlayer;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer( 'Usage:  SILENCE <character>'#13#10#13#10);
    ch.sendBuffer( 'If the character is already silenced, this will unsilence.'#13#10);
    exit;
    end;

  victim := GPlayer(findPlayerWorld(ch,param));
  
  if (victim = nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  if (victim = ch) then
    begin
    ch.sendBuffer('You cannot silence yourself.'#13#10);
    exit;
    end;

  if (victim.level >= ch.level) then
  begin
    ch.sendBuffer('Can only silence players lower level than you.'#13#10);
    exit;
  end;

//  ch.sendBuffer('Ok.'#13#10);
  if (IS_SET(victim.flags,PLR_SILENCED)) then
    begin
    act(AT_REPORT,Format('You have unsilenced $B$5%s$A$7.', [victim.name]),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'You have been un-silenced by $N.',false,victim,nil,ch,TO_CHAR);
    REMOVE_BIT(victim.flags,PLR_SILENCED);
    end
  else
    begin
    act(AT_REPORT,Format('You have silenced $B$5%s$A$7.', [victim.name]),false,ch,nil,nil,TO_CHAR);
    act(AT_REPORT,'You have been silenced by $N.',false,victim,nil,ch,TO_CHAR);
    SET_BIT(victim.flags,PLR_SILENCED);
    end;
end;

{Jago 5/Jan/2001 : repaired to work with v 0.3.0}
procedure do_peace(ch : GCharacter; param : string);
var
  rch : GCharacter;
  rch_node : GListNode;
begin
  act(AT_REPORT, '$n BOOOOMS: ''PEACE!!!''', false, ch, nil, nil, TO_ROOM);

  rch_node := ch.room.chars.head;
  while rch_node <> nil do
  begin
    rch := GCharacter(rch_node.element);
    if (rch.fighting <> nil) then
    begin
      stopfighting(rch);
    end;

    if rch <> ch then
      interpret(rch, 'sit');

    rch_node := rch_node.next;
  end;

  ch.sendBuffer( 'Ok.'#13#10);
end;

{Jago 5/Jan/2001 : repaired to work with v 0.3.0}
{ Xenon 28/Apr/2001 : renamed do_areas() to do_vnums() }
procedure do_vnums(ch : GCharacter; param : string);
var
  area : GArea;
  iterator : GIterator;
begin
  act(AT_DCYAN, 'Area name                          Filename                  Author              VNum Range'#13#10, false, ch, nil, nil, TO_CHAR);

  iterator := area_list.iterator();

  while (iterator.hasNext()) do
    begin
    area := GArea(iterator.next());

    act(AT_REPORT, pad_string(area.name, 29) + pad_string(area.fname, 15) + ' ' + pad_string(area.author, 17) + ' ' + pad_integer(area.r_lo, 5) + ' - ' + pad_integer(area.r_hi, 5), false, ch, nil, nil, TO_CHAR);
    end;
end;

{Jago 6/Jan/2001 - repaired for v 0.3}
// Destroys an active connection
procedure do_disconnect(ch : GCharacter; param : string);
var
  sock : integer;
  conn : GPlayerConnection;
  conn_f : GPlayerConnection;
  iterator : GIterator;
begin
  if (length(param) = 0) then
  begin
    ch.sendBuffer( 'Usage:  DISCONNECT <socket number>'#13#10#13#10);
    ch.sendBuffer( 'Disconnects a socket on the server.'#13#10);
    exit;
  end;

  try
    sock := StrToInt(param);
  except
    ch.sendBuffer( 'Please use a valid number.'#13#10);
    exit;
  end;

  iterator := connection_list.iterator();
  conn_f := nil;
  
  while (iterator.hasNext()) do
    begin
    conn := GPlayerConnection(iterator.Next());

    if (conn.socket.getDescriptor = sock) then
      begin
      conn_f := conn;
      break;
      end;
    end;

  iterator.Free();

  if (conn_f = nil) then
    begin
    ch.sendBuffer( 'That socket number was not found.'#13#10);
    exit;
    end;

  ch.sendBuffer( 'Ok.'#13#10);

  conn_f.Terminate();
end;

// Set bamfin message
procedure do_bamfin(ch : GCharacter; param : string);
begin
  if (ch.IS_NPC) then
    exit;

  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  BAMFIN <line or NULL to reset>'#13#10);

    if (GPlayer(ch).bamfin <> '') then
      ch.sendBuffer('Currently: ' + GPlayer(ch).bamfin + #13#10);
    exit;
    end;

  if (uppercase(param) = 'NULL') then
    GPlayer(ch).bamfin := ''
  else
    GPlayer(ch).bamfin := param;

  ch.sendBuffer('Ok.'#13#10);
end;

// Set bamfout message
procedure do_bamfout(ch : GCharacter; param : string);
begin
  if (ch.IS_NPC) then
    exit;

  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  BAMFOUT <line or NULL to reset>'#13#10);

    if (GPlayer(ch).bamfout <> '') then
      ch.sendBuffer('Currently: ' + GPlayer(ch).bamfout + #13#10);
    exit;
    end;

  if (uppercase(param) = 'NULL') then
    GPlayer(ch).bamfout := ''
  else
    GPlayer(ch).bamfout := param;

  ch.sendBuffer('Ok.'#13#10);
end;

// Set skills
procedure do_sset(ch : GCharacter; param : string);
var
  vict : GCharacter;
  victim, skill : string;
  perc : integer;
  sn : GSkill;
  node : GListNode;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  SSET <character> <skill> <percentage>'#13#10);
    exit;
    end;

  param := one_argument(param, victim);
  param := one_argument(param, skill);

  try
    perc := strtoint(param);
  except
    ch.sendBuffer('Percentage must be a number.'#13#10);
    exit;
  end;

  vict := findCharWorld(ch, victim);

  if (vict=nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  if (ch.getTrust < LEVEL_GOD) and (not vict.IS_NPC) then
    begin
    ch.sendBuffer('You can only use this on mobiles.'#13#10);
    exit;
    end;

  if (skill = 'all') then
    begin
    node := skill_table.head;

    while (node <> nil) do
      begin
      vict.SET_LEARNED(perc, node.element);

      node := node.next;
      end;

    vict.sendBuffer('You feel a great power increasing your skills.'#13#10);
    end
  else
    begin
    sn := findSkill(skill);

    if (sn = nil) then
      begin
      ch.sendBuffer('That skill does not exist.'#13#10);
      exit;
      end;

    vict.SET_LEARNED(perc, sn);

    vict.sendBuffer('You feel a great power increasing your skills.'#13#10);
    end;

  ch.sendBuffer('Ok.'#13#10);
end;

// Nourish: regenerates condition values
procedure do_nourish(ch : GCharacter; param : string);
var
  victim : GPlayer;
  vict_node : GListnode;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  NOURISH <[character]/ALL>'#13#10);
    exit;
    end;

  { nourish ALL }
  if uppercase(param) = 'ALL' then
  begin
    vict_node := char_list.head;

    while (vict_node <> nil) do
      begin
      if (vict_node.element <> ch) and (TObject(vict_node.element) is GPlayer) then
        begin
        victim := GPlayer(vict_node.element);

        victim.condition[COND_FULL]:=100;
        victim.condition[COND_THIRST]:=100;
        victim.condition[COND_DRUNK]:=0;
        victim.condition[COND_HIGH]:=0;
        victim.condition[COND_CAFFEINE]:=0;

        act(AT_REPORT,'You have nourished $N.', false, ch, nil, victim, TO_CHAR);
        act(AT_REPORT,'$N has nourished you.', false, victim, nil, ch, TO_CHAR);
        end;

      vict_node := vict_node.next;
      end; {while}

    ch.sendBuffer('Ok.'#13#10);
  end
  else
    { Nourish single char }
    begin
    victim := GPlayer(findPlayerWorld(ch,param));

    if (victim = nil) then
      begin
      ch.sendBuffer('That player does not exist.'#13#10);
      exit;
      end;
    
    victim.condition[COND_FULL]:=100;
    victim.condition[COND_THIRST]:=100;
    victim.condition[COND_DRUNK]:=0;
    victim.condition[COND_HIGH]:=0;
    victim.condition[COND_CAFFEINE]:=0;

    act(AT_REPORT,'You have nourished $N.', false, ch, nil, victim, TO_CHAR);
    act(AT_REPORT,'$N has nourished you.', false, victim, nil, ch, TO_CHAR);
  end;
end;

// Revive player when killed
procedure do_revive(ch : GCharacter; param : string);
var 
  obj : GObject;
  corpseroom : GRoom;
  victim : GCharacter;
  number, count : integer;
  conn : GPlayerConnection;
  iterator : GIterator;
  buf : string;
begin
  // Without argument shows existing corpses, decay timer and VNUM.
  if (length(param) = 0) then
    begin
    act(AT_REPORT,'Timer - Existing corpses:' + #13#10,false,ch,nil,nil,TO_CHAR);

    count := 0;

    iterator := connection_list.iterator();

    while (iterator.hasNext()) do
      begin
      conn := GPlayerConnection(iterator.next());

      obj := findObjectWorld('the corpse of ' + conn.ch.name);

      if (obj <> nil) then
        begin
        inc(count);

        buf := buf + ' (' + ansiColor(7,0) + pad_integer_front(obj.timer,2) +
               ansiColor(2,0) + ') ' + obj.name + ' in room: ' + ansiColor(6,0) +
               inttostr(obj.room.vnum) + ansiColor(2,0) + '.' + #13#10;
        end;
      end;
      
    iterator.Free();

    if (count = 0) then
      buf := ' None.' + #13#10;

    ch.sendBuffer(buf);

    exit;
    end;

  number := findNumber(param);
  
  // You can use 2.<player> in case of multiple corpses of same player.
  obj := findObjectWorld(inttostr(number) + '.corpse of ' + param);

  victim := findCharWorld(ch, param);

  if (obj = nil) then
    begin
    ch.sendBuffer('That corpse does not exist.'#13#10);
    exit;
    end;

  if (victim = nil) then
    begin
    ch.sendBuffer('That player is not logged in anymore.'#13#10);
    exit;
    end;

  // You don't want to revive NPC's :)
  if (victim.IS_NPC) then
    begin
    ch.sendBuffer('You can''t revive NPC''s.'#13#10);
    exit;
    end;

  corpseroom := obj.room;
  victim.fromRoom();
  victim.toRoom(corpseroom);

  act(AT_REPORT,'$N has revived you!', false, victim, nil, ch, TO_CHAR);
  act(AT_REPORT,'You have revived ' + uppercase(param) + '.', true, ch, nil, nil, TO_CHAR);
  
  interpret(victim, 'look _AUTO');
end;

// Hash statistics
procedure do_hashstats(ch : GCharacter; param : string);
var
  node : GListNode;
  n, c : integer;
  g : GHashValue;
begin
  ch.sendPager('Allocated hash entries: '#13#10#13#10);
  c := 0;

  for n := 0 to str_hash.bucketcount - 1 do
    begin
    node := str_hash.buckets[n].head;
    while (node <> nil) do
      begin
      g := GHashValue(node.element);

      ch.sendPager('(' + pad_integer_front(c, 3) + ') ' + GString(g.value).value + ' [' + inttostr(g.refcount) + ']'#13#10);

      inc(c);

      node := node.next;
      end;
    end;
end;

// Toggle holywalk
procedure do_holywalk(ch : GCharacter; param : string);
begin
  if (ch.IS_NPC) then
    exit;

  if (IS_SET(GPlayer(ch).flags, PLR_HOLYWALK)) then
    begin
    ch.sendBuffer('Holy walk off.'#13#10);
    REMOVE_BIT(GPlayer(ch).flags, PLR_HOLYWALK);
    end
  else
    begin
    ch.sendBuffer('Holy walk on.'#13#10);
    SET_BIT(GPlayer(ch).flags, PLR_HOLYWALK);
    end;
end;

// Toggle holylight
procedure do_holylight(ch : GCharacter; param : string);
begin
  if (ch.IS_NPC) then
    exit;

  if (IS_SET(GPlayer(ch).flags, PLR_HOLYLIGHT)) then
    begin
    ch.sendBuffer('Holy light off.'#13#10);
    REMOVE_BIT(GPlayer(ch).flags, PLR_HOLYLIGHT);
    end
  else
    begin
    ch.sendBuffer('Holy light on.'#13#10);
    SET_BIT(GPlayer(ch).flags, PLR_HOLYLIGHT);
    end;
end;

{ Xenon 20/Feb/2001: take an object from a player }
procedure do_take(ch : GCharacter; param : string);
var
   victstr,objstr : string;
   vict : GCharacter;
   obj : GObject;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  TAKE <object> <character>'#13#10);
    exit;
    end;

  param := one_argument(param, objstr);
  param := one_argument(param, victstr);

  // First search in room
  vict := ch.room.findChar(ch, victstr);

  // Then search global
  if (vict = nil) then
    vict := findCharWorld(ch, victstr);

  if (vict=nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  obj := vict.findEquipment(objstr);
  if (obj = nil) then
  obj := vict.findInventory(objstr);

  if (obj = nil) then
    begin
    ch.sendBuffer('That character does not have that object.'#13#10);
    exit;
    end;

  obj.worn := '';       // put it in inv no matter what

  obj.seperate();
  obj.fromChar();
  obj.toChar(ch);

  act(AT_REPORT,'$N takes $p from you.',false, vict, obj, ch, TO_CHAR);
  act(AT_REPORT,'$n takes $p from $N.',false, ch, obj, vict, TO_NOTVICT);
  act(AT_REPORT,'You take $p from $N.',false, ch, obj, vict, TO_CHAR);
end;

{ Xenon 21/Feb/2001: rename a player online }
procedure do_prename(ch : GCharacter; param : string);
var
   curr_name, new_name : string;
   vict : GPlayer;
   buf : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  PRENAME <current_name> <new_name>'#13#10);
    exit;
    end;

  param := one_argument(param, curr_name);
  param := one_argument(param, new_name);

  curr_name := cap(curr_name);
  new_name := cap(new_name);

  vict := GPlayer(findPlayerWorld(ch, curr_name));

  if (vict = nil) then
    begin
    ch.sendBuffer('That character isn''t online.'#13#10);
    exit;
    end;
  
  if (length(new_name) < 3) or (length(new_name) > 15) then
    begin
    ch.sendBuffer('New name must be between 3 and 15 characters long.'#13#10);
    exit;
    end;

  if (vict.IS_NPC) then
    begin
    ch.sendBuffer('This command doesn''t work on mobs.'#13#10);
    exit;
    end;

  if (FileExists('players\' + new_name + '.usr')) then
    begin
    ch.sendBuffer('That name is already in use.'#13#10);
    exit;
    end;

  with vict do
    begin
    name := cap(new_name);
    short := cap(new_name) + ' is here';
    long := cap(new_name) + ' is standing here';
    vict.save(vict.name);
    end;

  deleteFile('players\' + curr_name + '.usr');

  writeConsole(ch.name + ' has renamed ' + curr_name + ' to ' + new_name);

  buf := Format('$B$5%s$A$7 has renamed you to $B$5%s$A$7.', [ch.name, new_name]);
  act(AT_REPORT,buf,false,vict,nil,nil,TO_CHAR);
  buf := Format('$B$5%s$A$7 has been renamed to $B$5%s$A$7.', [curr_name, new_name]);
  act(AT_REPORT,buf,false,vict,nil,nil,TO_NOTVICT);
end;

{ Xenon 12/Apr/2001: execute a command at a players location }
procedure do_at(ch : GCharacter; param : string);
var
   target : string;
   saveroom, location : GRoom;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  AT <player> <command>'#13#10);
    ch.sendBuffer('        AT <roomvnum> <command>'#13#10);
    exit;
    end;

  param := one_argument(param, target);

  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  AT <player> <command>'#13#10);
    ch.sendBuffer('        AT <roomvnum> <command>'#13#10);
    exit;
    end;

  location := findLocation(ch, target);

  if (location = nil) then
    begin
    ch.sendBuffer('Location could not be found.'#13#10);
    exit;
    end;

  saveroom := ch.room;
  
  ch.fromRoom();
  ch.toRoom(location);
  
  interpret(ch, param);
  
  ch.fromRoom();
  ch.toRoom(saveroom);
end;

// Name generator
procedure do_namegen(ch : GCharacter; param : string);
var
  i : integer;
  node : GListNode;
  nt : TNameTemplate;
  template_nr : integer;
  amount_str : string;
  amount, count : integer;
  arg1 : string;
begin
  nt := nil;
  count := 1;
  
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  NAMEGEN list|reload|<template #> [amount to generate]'#13#10);
    exit;
    end;

  if (not namegenerator_enabled or (PhonemeList = nil) or (NameTemplateList = nil)) then
    begin
    ch.sendBuffer('Namegenerator is not enabled at this moment. (Error loading tables? File missing?)'#13#10);
    exit;
    end;

  param := one_argument(param, arg1);
  
  if (arg1 = 'list') then
    begin
    node := NameTemplateList.head;
    
    for i := 1 to (NameTemplateList.size()) do
      begin
      if (node = nil) then
        break;
        
      nt := TNameTemplate(node.element);
      act(AT_REPORT, Format('   $B$1[$7%2d$1]$A$7   %s', [i, nt.name]), false, ch, nil, nil, TO_CHAR);

      node := node.next;
      end;
      
    exit;
    end;

  if (arg1 = 'reload') then
    begin
    reloadNameTables();
    ch.sendBuffer('Done reloading nametables.'#13#10);
    exit;
    end;

  try
    template_nr := StrToInt(arg1);
  except
    on E: EConvertError do
    begin
      ch.sendBuffer(Format('Invalid argument ''%s''.'#13#10, [arg1]));
      exit;
    end;
  end;

  if ((template_nr > NameTemplateList.size()) or (template_nr < 1)) then
    begin
    ch.sendBuffer('Template number out of range.'#13#10);
    exit;
    end;
  
  param := one_argument(param, amount_str);
  if (amount_str <> '') then
    begin
    try
      amount := StrToInt(amount_str);
    except
      ch.sendBuffer('Please specify a number for amount to generate.'#13#10);
      exit;
    end;
    
    if ((amount > 20) or (amount < 1)) then
      begin
      ch.sendBuffer('Amount to generate out of range (1 < amount < 20).'#13#10);
      exit;
      end
    else
      count := amount;
    end;

  node := NameTemplateList.head;
  
  for i := 1 to template_nr do
    begin
    if (node = nil) then
      break;
      
    nt := TNameTemplate(node.element);
    node := node.next;
    end;
  
  act(AT_REPORT, Format('$B$1[$7Nametemplate ''%s''$1]$A$7', [nt.name]) + #13#10, false, ch, nil, nil, TO_CHAR);
  
  for i := 1 to count do
    begin
    act(AT_REPORT, Format('  $B$1[$7%2d$1]$A$7   %s', [i, generateName(nt.name)]), false, ch, nil, nil, TO_CHAR);
    end
end;

procedure createCoordinates(ch : GCharacter; startroom : GRoom);
var
  iterator : GIterator;
  room : GRoom;
  ex : GExit;
begin
  iterator := startroom.exits.iterator();

  while (iterator.hasNext()) do
    begin
    ex := GExit(iterator.next());
    
    room := ex.to_room;

    if (room.areacoords = nil) then
      begin
      room.areacoords := GCoords.Create(startroom.areacoords);
      case ex.direction of
        DIR_NORTH:
          begin
            inc(room.areacoords.y);
          end;
        DIR_EAST:
          begin
            inc(room.areacoords.x);
          end;
        DIR_SOUTH:
          begin
            dec(room.areacoords.y);
          end;
        DIR_WEST:
          begin
            dec(room.areacoords.x);
          end;
        DIR_DOWN:
          begin
            dec(room.areacoords.z);
          end;
        DIR_UP:
          begin
            inc(room.areacoords.z);
          end;
      end;
      ch.sendBuffer('Created coords (#' + IntToStr(room.vnum) + '): ' + room.areacoords.toString() + #13#10);
      createCoordinates(ch, room);
      end;
    end;
    
  iterator.Free();
end;

procedure do_coordgen(ch : GCharacter; param : string);
var
  room : GRoom;
begin
  ch.sendBuffer('NOTE: This command is still experimental and it''s use is discouraged.'#13#10);
  ch.sendBuffer('      It should only be used when you know what you''re doing. And even then... :P'#13#10#13#10);
  
  if (length(param) = 0) then
  begin
    ch.sendBuffer('Usage: COORDGEN <vnum>'#13#10#13#10);
    ch.sendBuffer('Generates coordinates with specifief vnum as (0,0,0).'#13#10);
    exit;
  end;

  try
    room := findRoom(StrToInt(param));
  except
    on E: EConvertError do
    begin
      ch.sendBuffer('That vnum doesn''t exit.');
      exit;
    end;
  end;

  if (room = nil) then
  begin
    ch.sendBuffer('A room with that vnum could not be found.'#13#10);
    exit;
  end;
  
  room.areacoords := GCoords.Create();
  room.areacoords.x := 0;
  room.areacoords.y := 0;
  room.areacoords.z := 0;
  createCoordinates(ch, room);
end;

{ this function *always* returns a positive value if it succeeds and a negative
  value if it doesn't }
function goalDistEstimate(currRoom : GRoom; destRoom : GRoom) : single;
begin
//  Assert(currRoom.areacoords <> nil, 'currRoom.areacoords = nil');
//  Assert(destRoom.areacoords <> nil, 'destRoom.areacoords = nil');
  if (currRoom.areacoords = nil) then
  begin
    bugreport('goalDistEstimate', 'cmd_imm.inc', 'currRoom.areacoords = nil; this probably means no areacoordinates have been created, see immcommand coordgen');
    raise Exception.Create('currRoom.areacoords = nil');
    Result := -1;
    exit;
  end;
  if (destRoom.areacoords = nil) then
  begin
    bugreport('goalDistEstimate', 'cmd_imm.inc', 'destRoom.areacoords = nil; this probably means no areacoordinates have been created, see immcommand coordgen');
    raise Exception.Create('destRoom.areacoords = nil');
    Result := -1;
    exit;
  end;

{$IFNDEF UseStraightLine}
// this is "Manhattan" distance, more appriopriate for A* and thus default
  Result := abs(destRoom.areacoords.x - currRoom.areacoords.x) +
            abs(destRoom.areacoords.y - currRoom.areacoords.y) +
            abs(destRoom.areacoords.z - currRoom.areacoords.z);
{$ELSE}            
// this is straight line distance
  if (currRoom.areacoords.z = destRoom.areacoords.z) then
    Result := power(
                power((destRoom.areacoords.x - currRoom.areacoords.x), 2) +
                power((destRoom.areacoords.y - currRoom.areacoords.y), 2),
                0.5)
  else
    Result := power(
                power((destRoom.areacoords.x - currRoom.areacoords.x), 2) +
                power((destRoom.areacoords.y - currRoom.areacoords.y), 2) +
                power((destRoom.areacoords.z - currRoom.areacoords.z), 2),
                1/3);
{$ENDIF}
end;

type
  TSearchNode =
    class
      f, g, h : single;
      room : GRoom;
      parent : TSearchNode;
      constructor Create(); overload;
      constructor Create(newg, newh : single; newroom : GRoom; newparent : TSearchNode); overload;
    end;

constructor TSearchNode.Create();
begin
  inherited Create();
  f := 0;
  g := 0;
  h := 0;
  room := nil;
  parent := nil;
end;

constructor TSearchNode.Create(newg, newh : single; newroom : GRoom; newparent : TSearchNode);
begin
  inherited Create();
  g := newg;
  h := newh;
  f := g + h;
  room := newroom;
  parent := newparent;
end;

procedure insertPriority(ll : GDLinkedList; snode : TSearchNode);
var
  node, ins : GListNode;
  n : TSearchNode;
begin
  ins := nil;
  node := ll.head;

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

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

    if (snode.f > n.f) then
      begin
      ins := node;
      end
    else
      begin
      ll.insertBefore(node, snode);
      exit;
      end;
    
    node := node.next;
    end;

  ll.insertAfter(ins, snode);  
end;
    
function findRoomAStar(ll : GDLinkedList; froom : GRoom) : GListNode;
var
  node : GListNode;
  snode : TSearchNode;
begin
  Result := nil;
  
  node := ll.head;
  while (node <> nil) do
    begin
    snode := TSearchNode(node.element);
    if (snode.room = froom) then
      begin
      Result := node;
      exit;
      end;
    node := node.next;
    end;
end;

{ Implementation of A* search algorithm }
{ this piece of code is ugly ;) }
function mpFindPath(startroom, destroom : GRoom; var resultdirs : string) : boolean;
var
  room, droom : GRoom;
  snode : TSearchNode;
  olnode, clnode : GListNode;
  new_snode, found_node : TSearchNode;
  llopen : GDLinkedList;
  llclosed : GDLinkedList;
  i : integer;
  node : GListNode;
  newg : single;
  found : boolean;
  dirs : string;
begin
  Result := false;
  dirs := '';
  found_node := nil;

  if (startroom = destroom) then
  begin
    Result := true;
    resultdirs := '';
    exit;
  end;
  
  llopen := GDLinkedList.Create();
  llclosed := GDLinkedList.Create();
  
  snode := TSearchNode.Create(0, goalDistEstimate(startroom, destroom), startroom, nil);

  insertPriority(llopen, snode);

  found := false;
  
  while (llopen.size() > 0) do
  begin
    node := llopen.head;
    snode := TSearchNode(node.element);
    room := snode.room;

    if (room = destroom) then
    begin
      found := true;
      llopen.remove(node);
      found_node := snode;
      break;
    end;

    if (room = nil) then
    begin
      writeConsole('room = nil');
      continue;
    end;
    
    llopen.remove(node);

    insertPriority(llclosed, snode);
    
    for i := DIR_NORTH to DIR_UP do
    begin
      droom := room.isConnectedTo(i);
      if (droom <> nil) then
      begin
        newg := snode.g + 1; // cost
        olnode := findRoomAStar(llopen, droom);
        clnode := findRoomAStar(llclosed, droom);
        if (olnode <> nil) and (TSearchNode(olnode.element).g <= newg) then
          continue;
        if (clnode <> nil) and (TSearchNode(clnode.element).g <= newg) then
          continue;
        if (clnode <> nil) then
          llclosed.remove(clnode);
        if (olnode = nil) then
        begin
          if (goalDistEstimate(droom, destroom) < 0) then
          begin
            bugreport('do_findpath', 'cmd_imm.inc', 'goalDistEstimate return value < 0 (2)');
            exit;
          end;
          new_snode := TSearchNode.Create(newg, goalDistEstimate(droom, destroom), droom, snode);
          insertPriority(llopen, new_snode);
        end;
      end;
    end;
  end;

  if (found) then
  begin
    Result := true;
    
    dirs := '';
    snode := found_node;
    while (snode.parent <> nil) do
    begin
//      ch.sendBuffer(Format('- #%d'#13#10, [snode.room.vnum]));
      dirs := dirs + findDirectionShort(snode.room, snode.parent.room);
      snode := snode.parent;
    end;

    resultdirs := '';
    for i := length(dirs) downto 1 do
    begin
      resultdirs := resultdirs + headings_short_i[findHeading(dirs[i])];
    end;
  end
  else
  begin
    Result := false;
    resultdirs := '';
  end;

  llopen.Clear();
  llopen.Free();
  llclosed.Clear();
  llclosed.Free();
end;

procedure do_findpath(ch : GCharacter; param : string);
var
  goalroom : GRoom;
  dirs : string;
  found : boolean;
  arg1, arg2 : string;
  i : integer;
begin
  dirs := '';

  if (length(param) = 0) then
  begin
    ch.sendBuffer('Usage: FINDPATH <vnum> [GO]'#13#10#13#10);
    ch.sendBuffer('This is a command to test the pathfinding functions.'#13#10);
    ch.sendBuffer('Supply a vnum as destination, and to optional keyword GO to'#13#10);
    ch.sendBuffer('follow a path if one is found.'#13#10);
    ch.sendBuffer(#13#10'IMPORTANT: don''t forget you need to create areacoordinates first (using immcommand ''coordgen'').'#13#10);
    exit;
  end;
  
  param := one_argument(param, arg1);
  param := one_argument(param, arg2);
  try
    goalroom := findRoom(StrToInt(arg1));
  except
//    on E: EConvertError do
    begin
      ch.sendBuffer('That vnum doesn''t exit.'#13#10);
      exit;
    end;
  end;

  if (goalroom = nil) then
  begin
    ch.sendBuffer('A room with that vnum could not be found.'#13#10);
    exit;
  end;

  if (goalDistEstimate(ch.room, goalroom) < 0) then
  begin
    bugreport('do_findpath', 'cmd_imm.inc', 'goalDistEstimate return value < 0 (2)');
    exit;
  end;

  ch.sendBuffer(Format('Distance: %g'#13#10, [goalDistEstimate(ch.room, goalroom)]));

  found := mpFindPath(ch.room, goalroom, dirs);
  if (found) then
  begin
    ch.sendBuffer('A path was found: ' + dirs + #13#10);
  end
  else
  begin
    ch.sendBuffer('There was no valid path found.'#13#10);
  end;

  if (trim(uppercase(arg2)) = 'GO') then
  begin
    if (length(dirs) = 0) then
    begin
      ch.sendBuffer('mpFindPath returned true, but an empty direction string. Perhaps you''re already at the specified vnum?'#13#10);
      exit;
    end;
    
    ch.sendBuffer('Following the path... hold on tight!'#13#10#13#10);
    for i := 1 to length(dirs) do
    begin
      interpret(ch, dirs[i]);
    end;
  end;
end;

procedure do_reload(ch : GCharacter; param : string);
var
  cmd : string;
  iterator : GIterator;
  npc : GNPCIndex;
  vict : GCharacter;
  count1, count2 : integer;
begin
  count1 := 0; count2 := 0;
  
  if (ch.IS_NPC()) then
  begin
    ch.sendBuffer('This command is only available to imms.'#13#10);
    exit;
  end;

  if (length(param) = 0) then
  begin
    ch.sendBuffer('Usage: RELOAD progs|namegen [silent]'#13#10#13#10);
    ch.sendBuffer('This command will reload certain parts of the mud online. When the '#13#10 +
                  'argument progs is used together with the argument silent, mobs won''t'#13#10 +
                  'emote when their mobprog is being reloaded.'#13#10);
    exit;
  end;

  param := one_argument(param, cmd);
  cmd := uppercase(cmd);

  if (cmd = 'PROGS') then
    begin
    iterator := npc_list.iterator();
    while (iterator.hasNext()) do
      begin
      npc := GNPCIndex(iterator.next());
      
      if (length(npc.progfile) <> 0) then
        begin
        if (npc.prog <> nil) then
          begin
          codeCache.remove(npc.progfile);
          npc.prog.Free();
          npc.prog := nil;
          end;
        
        npc.prog := loadCode(npc.progfile);
        inc(count1);
        end;
      end;
    iterator.Free();

    iterator := char_list.iterator();
    while (iterator.hasNext()) do
      begin
      vict := GCharacter(iterator.next());
      
      if (vict.IS_NPC() and (GNPC(vict).npc_index <> nil)) then
        begin
        if (length(GNPC(vict).npc_index.progfile) = 0) then
          continue;
        
        if (GNPC(vict).context <> nil) then
          begin
          GNPC(vict).context.Free();
          GNPC(vict).context := nil;
          end;
          
        GNPC(vict).context := GContext.Create(vict);
        GNPC(vict).context.load(GNPC(vict).npc_index.prog);
        
        if (uppercase(param) <> 'SILENT') then
          interpret(vict, 'emote receives new instructions and twitches violently.');
          
        inc(count2);
        end;
      end;
    iterator.Free();

    ch.sendBuffer(Format('Reloaded progs on %d NPC indices and reinitialised contexts on %d mobs.'#13#10, [count1, count2]));
  end
  else
  if (cmd = 'NAMEGEN') then
  begin
    interpret(ch, 'namegen reload');
  end
  else
  begin
    ch.sendBuffer('Unrecognized option.');
  end;
end;

{procedure do_thunder(ch:GCharacter;param:string);
begin
  if (length(param)=0) then
    begin
    ch.sendBuffer('Thunder what?'#13#10);
    exit;
    end;

  talk_channel(ch,param,CHANNEL_THUNDER,'thunder',AT_THUNDER);
end;}

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

  if (IS_SET(GPlayer(ch).flags, PLR_CLOAK)) then
    begin
    ch.sendBuffer('Cloak off.'#13#10);
    REMOVE_BIT(GPlayer(ch).flags, PLR_CLOAK);
    end
  else
    begin
    ch.sendBuffer('Cloak on.'#13#10);
    SET_BIT(GPlayer(ch).flags, PLR_CLOAK);
    end;
end;

// Purge objects from char - Nemesis
procedure do_purge(ch : GCharacter; param : string);
var 
  obj : GObject;
  vict : GCharacter;
  objstr, victstr : string;
  iterator : GIterator;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: PURGE <object>/ALL <target>'#13#10);
    ch.sendBuffer('       PURGE ROOM'#13#10);
    exit;
    end;

  if (uppercase(param) = 'ROOM') then
    begin
    iterator := ch.room.objects.iterator();

    while (iterator.hasNext()) do
      begin
      obj := GObject(iterator.Next());

      obj.Free();
      end;

    iterator.Free();

    ch.sendBuffer('Ok, room purged.'#13#10);
    exit;
    end;

  param := one_argument(param, objstr);
  param := one_argument(param, victstr);

  vict := ch.room.findChar(ch, victstr);

  if (vict = nil) then
    begin
    ch.sendBuffer('That character does not exist.'#13#10);
    exit;
    end;

  if (uppercase(objstr) = 'ALL') then
    begin
    iterator := vict.inventory.iterator();

    while (iterator.hasNext()) do
      begin
      obj := GObject(iterator.Next());

      obj.fromChar();
      obj.Free();
      end;
      
    iterator.Free();

    iterator := vict.equipment.iterator();

    while (iterator.hasNext()) do
      begin
      obj := GObject(iterator.Next());

      vict.affectObject(obj, true);

      obj.fromChar();
      obj.Free();
      end;
      
    iterator.Free();

    act(AT_REPORT,'All your items have been purged by $N.', false, vict, nil, ch, TO_CHAR);
    act(AT_REPORT,'You have purged all items of $N.', false, ch, nil, vict, TO_CHAR);
    exit;
    end;

  obj := vict.findInventory(objstr);

  if (obj = nil) then
    obj := vict.findEquipment(objstr);

  if (obj = nil) then
    obj := vict.findInventory(objstr);

  if (obj = nil) then
    begin
    ch.sendBuffer('That character does not have that object.'#13#10);
    exit;
    end;

  if (obj.worn <> '') then
    vict.affectObject(obj, true);

  act(AT_REPORT,'$p has been purged by $N.',false, vict, obj, ch, TO_CHAR);
  act(AT_REPORT,'You have purged $p of $N.',false, ch, obj, vict, TO_CHAR);

  obj.fromChar();
  obj.Free();
end;