/
clans/
include/CVS/
manual/CVS/
races/CVS/
system/CVS/
text/
text/CVS/
todo/
todo/CVS/
units/CVS/
const room_flags:array[0..30] of string = ('dark','death','nomob',
                                        'indoors','good','evil',
                                        'nocast','tunnel','private',
                                        'safe','solitary','norecall',
                                        'nodropall','nosummon',
                                        'clanstore','teleport',
                                        'nofloor','manaroom','bv18',
                                        'bv19','bv20','bv21','bv22',
                                        'bv23','bv24','bv25','bv26',
                                        'bv27','bv28','bv29','proto');

const exit_flags:array[0..12] of string = ('isdoor','closed','locked',
                                        'pickproof','secret','swim',
                                        'fly','clibm','portal',
                                        'nobreak','nomob','enter',
                                        'underwater');

{Jago 10/Jan/2001 : new imm commands, copied from MERC }
{RSTAT : return data about a room}
procedure do_rstat(ch : GCharacter; param : string);
var
	buf, buf1, arg : string;
  location : GRoom;
  location_node : GListNode;
  obj_data : GObject;
  obj_node : GListNode;
  rch : GCharacter;
  rch_node : GListNode;
  door : integer;
  exit_data : GExit;
  exit_node : GListNode;
  a : integer;
begin
  param := one_argument( param, arg );

  if arg = '' then
  	location := ch.room
  else
  	location := findLocation(ch, arg);

  if location = nil then
  begin
  	ch.sendBuffer('No such location' + #13#10);
   exit;
  end;

  // allow rstat of private rooms

  buf1 := '';
  buf := Format('Name: %s.' + #13#10 + 'Area: %s.' + #13#10 + 'Author: %s' + #13#10#13#10,
                 [location.name, location.area.name, location.area.author]);

  buf1 := buf1 + buf;

  buf := Format('Vnum %d, sector [%s].' + #13#10,
                [location.vnum, sector_types[location.sector]]);

  buf1 := buf1 + buf;

  buf := '';

  if (location.flags = 0) then
    buf := 'none'
  else
  for a:=0 to High(room_flags) do
   if IS_SET(location.flags, 1 shl a) then
    buf := buf + room_flags[a] + ' ';

  buf := Format('Room flags: [%s].' + #13#10#13#10 + 'Description: ' + #13#10 + '%s'#13#10,
                [buf, location.description]);

  buf1 := buf1 + buf;

  buf1 := buf1 + 'Characters: ';

  rch_node := location.chars.head;
  while rch_node <> nil do
  begin
    rch := GCharacter(rch_node.element);

    buf := rch.name^;
    buf1 := buf1 + buf;
    buf1 := buf1 + ', ';

    rch_node := rch_node.next;
  end;

  buf1 := buf1 + #13#10;
  buf1 := buf1 + 'Objects: ';

  obj_node := location.objects.head;
  while obj_node <> nil do
  begin
    obj_data := GObject(obj_node.element);

    buf := obj_data.name^;
    buf1 := buf1 + buf;
    buf1 := buf1 + ', ';

    obj_node := obj_node.next;
  end;

  buf1 := buf1 + #13#10#13#10;

  door := 0;
  exit_node := location.exits.head;
  while exit_node <> nil do begin
    exit_data := GExit(exit_node.element);

    inc(door);

    if (exit_data.flags = 0) then
      buf := 'none'
    else
      begin
      buf := '';
      for a:=0 to High(exit_flags) do
       if IS_SET(exit_data.flags,1 shl a) then
        buf := buf + exit_flags[a] + ' ';
      end;

    buf := Format('Door: %d.  To: %d.  Key: %d.  Exit flags: [%s].' +
    							 #13#10 + 'Keyword: "%s".',
                  [door,
                  exit_data.to_room.vnum,
                  exit_data.key,
                  buf,
                  exit_data.keywords^]);

    buf1 := buf1 + buf;
    buf1 := buf1 + #13#10;

    exit_node := exit_node.next;
  end;

  buf1 := buf1 + #13#10;
  ch.sendBuffer(buf1);
end;

{Jago 10/Jan/2001 - utility function}
function actBitName(vector : integer) : String;
begin
  Result := '';

	if (vector and ACT_NPC) = ACT_NPC then Result := Result + ' npc';
	if (vector and ACT_SENTINEL) = ACT_SENTINEL then Result := Result + 'sentinel';
	if (vector and ACT_SCAVENGER) = ACT_SCAVENGER then Result := Result + 'scavenger';
	if (vector and ACT_AGGRESSIVE) = ACT_AGGRESSIVE then Result := Result + 'aggressive';
	if (vector and ACT_STAY_AREA) = ACT_STAY_AREA then Result := Result + 'stay_area';
	if (vector and ACT_TEACHER) = ACT_TEACHER then Result := Result + 'teacher';
end;

{Jago 10/Jan/2001 - utility function}
function affectBitName(vector : integer) : String;
begin
  Result := '';

	if (vector and AFF_BLIND) = AFF_BLIND then Result := Result + ' blind';
	if (vector and AFF_INVISIBLE) = AFF_INVISIBLE then Result := Result + 'invisible';
	if (vector and AFF_DETECT_INVIS) = AFF_DETECT_INVIS then Result := Result +' detect invis';
	if (vector and AFF_DETECT_HIDDEN) = AFF_DETECT_HIDDEN then Result := Result+ ' detect hidden';
	if (vector and AFF_SANCTUARY) = AFF_SANCTUARY then Result := Result + 'sanctuary';
	if (vector and AFF_POISON) = AFF_POISON then Result := Result + ' poison';
	if (vector and AFF_SNEAK) = AFF_SNEAK then Result := Result + ' sneak';
	if (vector and AFF_HIDE) = AFF_HIDE then Result := Result + ' hide';
	if (vector and AFF_FLYING) = AFF_FLYING then Result := Result + ' flying';
	if (vector and AFF_INFRAVISION) = AFF_INFRAVISION then Result := Result + 'infravision';
	if (vector and AFF_BERSERK) = AFF_BERSERK then Result := Result + 'beserk';
	if (vector and AFF_AQUA_BREATH) = AFF_AQUA_BREATH then Result := Result + 'aqua breath';
	if (vector and AFF_PLAGUE) = AFF_PLAGUE then Result := Result + ' plague';
	if (vector and AFF_ENCHANT) = AFF_ENCHANT then Result := Result + 'enchant';

  if Result = '' then
	  Result := 'none';
end;

{Jago 10/Jan/2001 - utility function}
function affectLocName(location : integer) : string;
begin
	Result := '';    // dummy func, affect locations not implemented yet??
end;

{Jago 10/Jan/2001
MSTAT : return data about a mobile - can also be used on players}
{ Xenon 20/Feb/2001: renamed do_mstat() to do_pstat() }
procedure do_pstat(ch : GCharacter; param : string);
var
	buf, buf1, arg, gender, exp, vnum, room_vnum, wimpy : string;
{fighting,} master, leader : string;
{affect_node, victim_node,} paf_node : GListNode;
paf : GAffect;
victim : GCharacter;
begin

  one_argument( param, arg );

  if length(arg) = 0 then
  begin
    ch.SendBuffer('Pstat whom?' + #13#10);
    exit;
  end;

  victim := findCharWorld(ch, arg);

  if victim = nil then
  begin
    ch.sendBuffer('They aren''t here.' + #13#10);
    exit;
  end;

  buf1 := '';
  buf := 'Name: ' + victim.name^ + '.' + #13#10;
  buf1 := buf1 + buf;

  if victim.IS_NPC then
  begin
   if victim.npc_index <> nil then
    vnum := IntToStr(victim.npc_index.vnum)
   else
    vnum := '?';
  end
  else
  	vnum := '0';

  if victim.sex = 0 then
  	gender := 'male'
  else if victim.sex = 1 then
  	gender := 'female'
  else if victim.sex = 2 then
  	gender := 'neutral'
  else
  	gender := 'unknown!';

  if victim.room = nil then
  	room_vnum := ''
  else
   room_vnum := IntToStr(victim.room.vnum);

  buf := Format('Vnum: %s. Sex: %s. Room: %s' + #13#10,
                [vnum, gender, room_vnum]);

  buf1 := buf1 + buf;

  buf := Format('Str: %d.  Int: %d.  Wis: %d.  Dex: %d.  Con: %d.' + #13#10,
                [victim.ability.str,
                victim.ability.int,
                victim.ability.wis,
                victim.ability.dex,
                victim.ability.con]);

  buf1 := buf1 + buf;

  buf := Format('Hp: %d/%d.  Mana: %d/%d.  Move: %d/%d.' + #13#10,
                [victim.point.hp, victim.point.max_hp,
                victim.point.mana, victim.point.max_mana,
                victim.point.mv, victim.point.max_mv]);

  buf1 := buf1 + buf;

  if victim.IS_NPC then
  	exp := 'none'
  else
  	exp := IntToStr(victim.player.xptot);

  buf := Format('Level: %d.  Align: %d.  AC: %d.  Gold: %d.  Exp: %s.' + #13#10,
                [victim.level, victim.alignment, victim.point.ac,
                victim.gold, exp]);

  buf1 := buf1 + buf;

  if victim.IS_NPC then
  	wimpy := 'none'
  else
  	wimpy := IntToStr(victim.player.wimpy);

  buf := Format('Hitroll: %d.  Position: %d.  Wimpy: %s.' + #13#10,
                [victim.point.hitroll,
                victim.position,
                wimpy]);

  buf1 := buf1 + buf;

  if not victim.IS_NPC then
  	buf1 := buf1 + 'Page Lines: ' + IntToStr(victim.player.pagerlen) + '.' + #13#10;

  if victim.fighting <> nil then
    buf1 := buf1 + 'Fighting: ' + victim.fighting.name^ + '.' + #13#10
  else
    buf1 := buf1 + 'Fighting: (none).' + #13#10;

  if not victim.IS_NPC then
  begin
  	buf := Format('Thirst: %d.  Full: %d.  Drunk: %d.' + #13#10,
                 [victim.player^.condition[COND_THIRST],
                 victim.player^.condition[COND_FULL],
                 victim.player^.condition[COND_DRUNK]]);
   buf1 := buf1 + buf;

   // how to get # of items carried?
   buf := Format('Carry number: .  Carry weight: %d.' + #13#10,
                [victim.carried_weight]);

   buf1 := buf1 + buf;

   buf := Format('Age: %d.  Played: %d.  Timer: %d.  Act: %s.' + #13#10,
                [victim.player.age,
                round(victim.player.played),
                victim.wait,
                actBitName(victim.act_flags)]);

   buf1 := buf1 + buf;
  end;

  if victim.master <> nil then
  	master := victim.master.name^
  else
  	master := '(none)';

  if victim.leader <> nil then
  	master := victim.leader.name^
  else
  	master := '(none)';

  buf := Format('Master: %s.  Leader: %s.  Affected by: %s.' + #13#10,
                [master, leader, affectBitName(victim.aff_flags)]);

  buf1 := buf1 + buf;

  buf := Format('Short description: %s.' + #13#10 + 'Long description: %s' + #13#10,
                [victim.short^, victim.long^]);

  buf1 := buf1 + buf;


  if victim.IS_NPC then
     if victim.npc_index <> nil then
     	if (victim.npc_index.programs.getSize > 0) then
       	buf1 := buf1 + 'Mobile has mobprogs.' + #13#10;


  paf_node := victim.affects.head;
  while paf_node <> nil do
  begin
  	paf := GAffect(paf_node.element);

   buf := Format('Spell: "%s" modifies %s by %d for %d hours with bits %s.' 
+ #13#10,
                 [skill_table[paf.sn].name,
                 '?', // affLocName(paf.location
                 paf.modifier,
                 paf.duration,
                 affectBitName(paf.aff_flag)]);

   buf1 := buf1 + buf;

   paf_node := paf_node.next;
  end;

  act(AT_REPORT, buf1, false, ch, nil, nil, TO_CHAR);
end;

{Jago 10/Jan/2001 OSTAT : return data about an object}
{ Revised 28/Jan/2001 - Nemesis }
{ 19/Feb/2001 - Xenon : fixed bug that made grendel crash on ostat <object> }
procedure do_ostat(ch : GCharacter; param : string);
var buf, buf1, arg : string;
{    aff_node, obj_node : GListNode;
    aff_data : GAffect; }
    obj: GObject;
    room :integer;
    in_obj, carried_by : string;
begin

  one_argument( param, arg );

  if length(arg) = 0 then
    begin
    ch.sendBuffer('Ostat what?' + #13#10);
    exit;
    end;

  obj := ch.findInventory(arg);

  if (obj = nil) then
    obj := ch.room.findObject(arg);

  if (obj = nil) then
    obj := findObjectWorld(arg);

  if (obj = nil) then
    begin
    ch.sendBuffer('Nothing like that in hell, earth, or heaven.' + #13#10);
    exit;
    end;

  buf1 := 'Name: ' + obj.name^ + '.' + #13#10;

  buf := Format('Vnum: %d.  Type: %s.' + #13#10 +
                'Short description: %s.' + #13#10 +
                'Long description: %s' + #13#10,
                [obj.obj_index.vnum,
                obj.name^,
                obj.short^,
                obj.long^]);

  buf1 := buf1 + buf;

  buf := Format('Wear bits: %d.' + #13#10,
                [obj.flags]);

  buf1 := buf1 + buf;

  // note : objects dont have a level??
  buf := Format('Weight: %d. Cost: %d.  Timer: %d.  {Level: 0.}' + #13#10,
                [obj.getWeight,
                obj.cost,
                obj.timer]); //, obj.level]);

  buf1 := buf1 + buf;

  if obj.room = nil then
  	room := 0
  else
  	room := obj.room.vnum;

  if obj.in_obj = nil then
  	in_obj := '(none)'
  else
   in_obj := obj.in_obj.name^;

  {if obj.carried_by = nil then
  	carried_by := ''
  else
  	carried_by := obj.carried_by.name;}
  carried_by := '(none)';

  buf := Format('In room: %d.  In object: %s.  Carried by: %s.  {Wear_loc:}.' + #13#10,
                [room, in_obj, carried_by]);

  buf1 := buf1 + buf;

  buf := Format('Values: %d %d %d %d.' + #13#10,
                [obj.value[1],
                obj.value[2],
                obj.value[3],
                obj.value[4]]);

  buf1 := buf1 + buf;

  // [no extra descriptions]
  // [no obj affects]

  act(AT_REPORT, buf1, false, ch, nil, nil, TO_CHAR);
end;

{Jago 17/Jan/2001 - utility function, move to util.pas}
function is_number( param : string ) : boolean;
var
temp : integer;
begin
  Result := True;
  try
    temp := StrToInt(param);
  except
    Result := False;
  end;
end;

{Jago 17/Jan/2001 - OLOAD - load an object}
procedure do_oload(ch : GCharacter; param : string);
var
  arg1, arg2 : string;
  obj_index : GObjectIndex;
  obj : GObject;
  node : GListNode;
  level : integer;
begin
  param := one_argument( param, arg1 );
  param := one_argument( param, arg2 );
  if (length(arg1) = 0) or (not is_number(arg1)) then
  begin
     ch.sendBuffer('Syntax: oload <vnum> <level>.' + #13#10);
     exit;
  end;

  if length(arg2) = 0 then
     level := umax(ch.level, ch.getTrust)
  else if (not is_number(arg2)) then
  begin
     ch.sendBuffer('Syntax: oload <vnum> <level>.' + #13#10);
     exit;
  end else begin
     level := StrToInt(arg2);

     if (level < 0) or (level > ch.getTrust) then
     begin
       ch.sendBuffer('Limited to your trust level.' + #13#10);
       exit;
     end;
  end;

  // get the obj index
  obj_index := findObjectIndex(strtoint(arg1));

  if obj_index = nil then
  begin
     ch.sendBuffer('No object has that vnum.' + #13#10);
     exit;
  end;

  // create the obj
  obj := instanceObject(obj_index);

  // give obj to ch
  obj.toChar(ch);

  act(AT_WHITE, '$n has created $p!', false, ch, obj, nil, TO_ROOM);
  ch.sendBuffer('Ok.');
end;

{jago - utility func, move to area.pas}
function instanceNPC(npcindex : GNPCIndex) : GCharacter;
var
npc : GCharacter;
begin

  // note : this func doesnt check
  // npcindex.count + 1 < reset.max
  // this is so imms can mload more npcs than the reset maximum

  // this func does not place the npc in a room, the calling func is
  // responsible for that

  if (npcindex = nil) then
  begin
    bugreport('instanceNPC', 'area.pas', 'npc_index null',
              'The index to create a npc from is invalid.');
    Result := nil;
    exit;
  end;

  npc := GCharacter.Create;

  with npc do
  begin
    ability.str:=npcindex.str;
    ability.con:=npcindex.con;
    ability.dex:=npcindex.dex;
    ability.int:=npcindex.int;
    ability.wis:=npcindex.wis;
    point.hp:=npcindex.hp;
    point.max_hp:=npcindex.hp;
    point.mv:=npcindex.mv;
    point.max_mv:=npcindex.mv;
    point.mana:=npcindex.mana;
    point.max_mana:=npcindex.mana;
    point.natural_ac:=npcindex.natural_ac;
    point.ac_mod:=0;
    point.hitroll:=npcindex.hitroll;

    point.damnumdie:=npcindex.damnumdie;
    point.damsizedie:=npcindex.damsizedie;
    point.apb:=npcindex.apb;
    move(npcindex.learned,learned,sizeof(learned));
    clan:=npcindex.clan;
    conn:=nil;

    npc.room := nil;//findRoom(reset.arg2);

    position:=POS_STANDING;
    npc.npc_index := npcindex;

    name := npcindex.name;
    short := npcindex.short;
    long := npcindex.long;

    sex:=npcindex.sex;
    race:=npcindex.race;
    alignment:=npcindex.alignment;
    level:=npcindex.level;
    weight:=npcindex.weight;
    height:=npcindex.height;
    act_flags:=npcindex.act_flags;
  end; {with}

  inc(npcindex.count);
  npc.node_world := char_list.insertLast(npc);

  npc.calcAC;

  Result := npc;
end;

{Jago 17/Jan/2001 - MLOAD - load a NPC}
procedure do_mload(ch : GCharacter; param : string);
var
  arg : string;
  mob_index : GNPCIndex;
  victim : GCharacter;
begin
  one_argument(param, arg);

  if length(arg) = 0 then
  begin
     ch.sendBuffer('Syntax: mload <vnum>.' + #13#10);
     exit;
  end;

  if not is_number(arg) then
  begin
     ch.sendBuffer('Mload what?.' + #13#10);
     exit;
  end;

  mob_index := findNPCIndex(StrToInt(arg));

  if mob_index = nil then
  begin
     ch.sendBuffer('No mob has that vnum.' + #13#10);
     exit;
  end;

  victim := instanceNPC(mob_index);

  if victim = nil then
  begin
     ch.sendBuffer('Mload who?.' + #13#10);
     exit;
  end;

  victim.toRoom(ch.room);
  act(AT_WHITE, '$n has created $N!', false, ch, nil, victim, TO_ROOM);
  ch.sendBuffer('Ok.');
end;

{Jago 18/Jan/2001 - OFIND - find an object}
{ Revised 25/Feb/2001 - Nemesis }
procedure do_ofind(ch : GCharacter; param : string);
var buf : string;
    obj : GObjectIndex;
    node : GListNode;
    found, fAll : boolean;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Ofind what?' + #13#10);
    exit;
    end;

  fAll := (uppercase(param) = 'ALL');
  buf := #13#10 + '[Vnum] [Name]' + #13#10;

  node := obj_list.head;

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

    if (fAll) or (isName(obj.name^, param)) then
      begin
      found := true;
      buf := buf + pad_integer_front(obj.vnum,5) + '   ' + obj.name^ + #13#10;
      end;

    node := node.next;
    end;

  if (not found) then
    begin
    ch.sendBuffer('Nothing like that in hell, earth, or heaven.' + #13#10);
    exit;
    end;

  ch.sendPager(buf);
end;

{Jago 18/Jan/2001 - MFIND - find a NPC}
{ Revised 25/Feb/2001 - Nemesis }
procedure do_mfind(ch : GCharacter; param : string);
var buf : string;
    found, fAll : boolean;
    node : GListNode;
    npc : GNPCIndex;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Mfind whom?' + #13#10);
    exit;
    end;

  found := False;
  fAll := (uppercase(param) = 'ALL');
  buf := #13#10 + '[Vnum] [Name]' + #13#10;

  node := npc_list.head;

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

    if (fAll) or (isName(npc.name^, param)) then
      begin
      found := True;
      buf := buf + pad_integer_front(npc.vnum,5) + '   ' + npc.name^ + #13#10;
      end;

    node := node.next;
    end;

  if (not found) then
    begin
    ch.sendBuffer('Nothing like that in hell, earth, or heaven.' + #13#10);
    exit;
    end;

  ch.sendPager(buf);
end;

{ Adjust scores NPC's and PC's - Nemesis }
{ Xenon 20/Feb/2001: renamed do_ascore() to do_pset() }
procedure do_pset(ch:GCharacter;param:string);
var arg,arg2,arg3 : string;
    vict : GCharacter;
    value : integer;
    buf : string;
begin
  param := one_argument(param, arg);
  param := one_argument(param, arg2);
  one_argument(param, arg3);

  if (length(arg) = 0) then
    begin
    ch.sendBuffer('Usage:  PSET <victim> <type> <value>'#13#10#13#10);
    ch.sendBuffer('Types for both NPC and PC: hp, mana, moves, strength,'#13#10);
    ch.sendBuffer('wisdom, intelligence, dexterity, constitution, ac, apb,'#13#10);
    ch.sendBuffer('hitroll, alignment, gold, sex.'#13#10#13#10);
    ch.sendBuffer('Types for PC only: bank, xptnl.'#13#10);
    exit;
    end;

  if (length(arg) <> 0) and (length(arg2) = 0) then
    begin
    ch.sendBuffer('Please select <type> and <value>.'#13#10);
    exit;
    end;

  if (length(arg) <> 0) and (length(arg2) <> 0) and (length(arg3) = 0) then
    begin
    ch.sendBuffer('Please enter a <value>.'#13#10);
    exit;
    end;

  try                            // Xenon 21/Feb/2001: added try..except block
    value := StrToInt(arg3);
  except
    on EConvertError do
    begin
      ch.sendBuffer('Value must be a number.'#13#10);
      exit;
    end;
  else
    ch.sendBuffer('Couldn''t convert value.'#13#10);
    exit;
  end;

  if (uppercase(arg) = 'SELF') then
    vict := ch
  else
    vict := FindCharWorld(ch,arg);

  if (vict = nil) then
    begin
    ch.sendBuffer('That player cannot be found.'#13#10);
    exit;
    end;

  if (uppercase(arg2) = 'HP') then
    begin
    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;

    vict.point.max_hp := value;
    buf := 'Max HP';
    end
  else
  if (uppercase(arg2) = 'MANA') then
    begin
    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;

    vict.point.max_mana := value;
    buf := 'Max MANA';
    end
  else
  if (uppercase(arg2) = 'STAMINA') then
    begin
    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;
      
    vict.point.max_mv := value;
    buf := 'Max STAMINA';
    end
  else
  if (uppercase(arg2) = 'STRENGTH') then
    begin
    if (value >= 100) then
      begin
      ch.sendBuffer('Max value is 99.'#13#10);
      exit;
      end;

    vict.ability.str := value;
    buf := 'STRENGTH';
    end
  else
  if (uppercase(arg2) = 'WISDOM') then
    begin
    if (value >= 100) then
      begin
      ch.sendBuffer('Max value is 99.'#13#10);
      exit;
      end;

    vict.ability.wis := value;
    buf := 'WISDOM';
    end
  else
  if (uppercase(arg2) = 'DEXTERITY') then
    begin
    if (value >= 100) then
      begin
      ch.sendBuffer('Max value is 99.'#13#10);
      exit;
      end;

    vict.ability.dex := value;
    buf := 'DEXTERITY';
    end
  else
  if (uppercase(arg2) = 'INTELLIGENCE') then
    begin
    if (value >= 100) then
      begin
      ch.sendBuffer('Max value is 99.'#13#10);
      exit;
      end;

    vict.ability.int := value;
    buf := 'INTELLIGENCE';
    end
  else
  if (uppercase(arg2) = 'CONSTITUTION') then
    begin
    if (value >= 100) then
      begin
      ch.sendBuffer('Max value is 99.'#13#10);
      exit;
      end;

    vict.ability.con:=value;
    buf := 'CONSTITUTION';
    end
  else
  if (uppercase(arg2) = 'AC') then
    begin
    vict.point.ac := value;
    buf := 'AC';
    end
  else
  if (uppercase(arg2) = 'HITROLL') then
    begin
    vict.point.hitroll := value;
    buf := 'HITROLL';
    end
  else
  if (uppercase(arg2) = 'ALIGNMENT') then
    begin
    vict.alignment := value;
    buf := 'ALIGNMENT';
    end
  else
  if (uppercase(arg2) = 'APB') then
    begin
    vict.point.apb := value;
    buf := 'APB';
    end
  else
  if (uppercase(arg2) = 'BANK') then
    begin
    if (vict.IS_NPC) then
      begin
      ch.sendBuffer('Type not possible for NPC.'#13#10);
      exit;
      end;

    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;

    vict.player^.bankgold := value;
    buf := 'BANK';
    end
  else
  if (uppercase(arg2) = 'GOLD') then
    begin
    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;

    vict.gold := value;
    buf := 'GOLD';
    end
  else
  if (uppercase(arg2) = 'XPTNL') then
    begin
    if (vict.IS_NPC) then
      begin
      ch.sendBuffer('Type not possible for NPC.'#13#10);
      exit;
      end;

    if (value <= 0) then
      begin
      ch.sendBuffer('Value must be > 0.'#13#10);
      exit;
      end;
      
    vict.player^.xptogo := value;
    buf := 'XP TNL';
    end
  else
  if (uppercase(arg2) = 'SEX') then
    begin
    if (value > 2) or (value < 0) then
      begin
      ch.sendBuffer('Value must be 0 (male), 1 (female) or 2 (neutral).'#13#10);
      exit;
      end;

    vict.sex := value;
    buf := 'SEX';
    end
  else
    begin
    ch.sendBuffer('Wrong <type>, use PSET to see available types.'#13#10);
    exit;
    end;

  act(AT_REPORT,buf + ' of $N set to ' + inttostr(value) + '.',false,ch,nil,vict,TO_CHAR);
end;


procedure do_ocreate(ch : GCharacter; param : string);
var
   oindex : GObjectIndex;
   obj : GObject;
   sub : string;
   vnum : integer;
begin
  if (ch.player^.area_fname='') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (ch.player^.area=nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: OCREATE <objectvnum> <name>'#13#10#13#10);
    ch.sendBuffer('Creates a new object index.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);

  try
    vnum := strtoint(sub);
  except
    ch.sendBuffer('Invalid numeric format.'#13#10);
    exit;
  end;

  if (vnum < ch.player^.o_lo) or (vnum > ch.player^.o_hi) then
    begin
    ch.sendBuffer('That vnum is outside your range.'#13#10);
    exit;
    end;

  if (findObjectIndex(vnum) <> nil) then
    begin
    ch.sendBuffer('That vnum has been used.'#13#10);
    exit;
    end;

  oindex := GObjectIndex.Create;
  oindex.area := ch.player^.area;
  oindex.vnum := vnum;
  oindex.name := hash_string(param);
  oindex.short := hash_string(param);
  oindex.long := hash_string(param);
  oindex.flags := OBJ_PROTO;
  obj_list.insertLast(oindex);

  obj := instanceObject(oindex);
  obj.toChar(ch);

  act(AT_REPORT,'You utter a few words and you create $p!',false,ch,obj,nil,TO_CHAR);
  act(AT_REPORT,'$n utters a few words and creates $p!',false,ch,obj,nil,TO_ROOM);
end;

const object_flags:array[0..30] of string=('nopickup','glow','hum',
                                          'antigood','antievil',
                                          'loyal','noremove',
                                          'nodrop','clanobject',
                                          'hidden','poison','missile',
                                          'nosac','bv13','bv14',
                                          'bv15','bv16','bv17','bv18',
                                          'bv19','bv20','bv21','bv22',
                                          'bv23','bv24','bv25','bv26',
                                          'bv27','bv28','bv29','proto');

const item_types:array[1..14] of string=('weapon','armor','food',
                                        'drink','light','trash',
                                        'money','special','gem',
                                        'container','corpse',
                                        'fountain','blood','portal');

const wear_types:array[1..26] of string=('rfinger','lfinger','neck1',
                                        'neck2','body','head','legs',
                                        'feet','hands','arms',
                                        'shield','about','waist',
                                        'rwrist','lwrist','float',
                                        'rhand','lhand','rshoulder',
                                        'lshoulder','face','rear',
                                        'lear','rankle','lankle','eyes');

procedure do_oedit(ch : GCharacter; param : string);
var sub : string;
    a : integer;
    obj : GObject;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  OEDIT <object> <field> [value]'#13#10#13#10);
    ch.sendBuffer('Field can be one of the following:'#13#10);
    ch.sendBuffer('  name short long flags'#13#10);
    ch.sendBuffer('  type wear1 wear2 weight cost'#13#10);
    ch.sendBuffer('  value1 value2 value3 value4'#13#10);
    exit;
    end;

  param := one_argument(param,sub);
  obj := ch.findInventory(sub);

  if (obj = nil) then
    begin
    ch.sendBuffer('Could not find that object.'#13#10);
    exit;
    end;

  if (IS_SET(obj.flags, OBJ_PROTO)) and (obj.obj_index = nil) then
    begin
    ch.sendBuffer('Illegal proto.'#13#10);
    exit;
    end;

  { make sure builders don't overwrite other areas }
  if (obj.obj_index <>nil) and
   ((obj.obj_index.vnum < ch.player^.o_lo) or (obj.obj_index.vnum > ch.player^.o_hi)) then
    begin
    ch.sendBuffer('This vnum is not in your range.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);

  if (sub = 'name') then
    begin
    unhash_string(obj.name);
    obj.name := hash_string(param);

    if IS_SET(obj.flags,OBJ_PROTO) then
      begin
      unhash_string(obj.obj_index.name);
      obj.obj_index.name := hash_string(param);
      end;
    end
  else
  if (sub = 'short') then
    begin
    unhash_string(obj.short);
    obj.short := hash_string(param);

    if IS_SET(obj.flags,OBJ_PROTO) then
      begin
      unhash_string(obj.obj_index.short);
      obj.obj_index.short := hash_string(param);
      end;
    end
  else
  if (sub = 'long') then
    begin
    unhash_string(obj.long);
    obj.long := hash_string(param);

    if IS_SET(obj.flags,OBJ_PROTO) then
      begin
      unhash_string(obj.obj_index.long);
      obj.obj_index.long := hash_string(param);
      end;
    end
  else
  if (sub = 'flags') then
    begin
    for a:=0 to High(object_flags) do
     if (pos(object_flags[a], param) > 0) then
      begin
      if IS_SET(obj.flags,1 shl a) then
        REMOVE_BIT(obj.flags,1 shl a)
      else
        SET_BIT(obj.flags,1 shl a);
      end;

    if IS_SET(obj.flags,OBJ_PROTO) then
      obj.obj_index.flags := obj.flags - OBJ_PROTO;
    end
  else
  if (sub = 'type') then
    begin
    for a:=0 to High(item_types) do
     if (pos(item_types[a], param ) > 0) then
      begin
      obj.item_type:=a;
      break;
      end;

    if IS_SET(obj.flags,OBJ_PROTO) then
      obj.obj_index.item_type:=obj.item_type;
    end
  else
  if (sub = 'wear1') then
    begin
    for a:=0 to High(wear_types) do
     if (pos(wear_types[a], param) > 0) then
      begin
      obj.wear1:=a;
      break;
      end;

    if IS_SET(obj.flags,OBJ_PROTO) then
      obj.obj_index.wear1:=obj.wear1;
    end
  else
  if (sub = 'wear2') then
    begin
    for a:=0 to High(wear_types) do
     if (pos(wear_types[a], param) > 0) then
      begin
      obj.wear2:=a;
      break;
      end;

    if IS_SET(obj.flags,OBJ_PROTO) then
      obj.obj_index.wear2:=obj.wear2;
    end
  else
    begin
    ch.sendBuffer('Unknown option.'#13#10);
    exit;
    end;

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

procedure do_olist(ch : GCharacter; param : string);
var num:integer;
    area : GArea;
    obj : GObjectIndex;
    node : GListNode;
begin
  if (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  area := ch.player^.area;
  if (area = nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  num:=0;
  act(AT_REPORT, '$B$1[$B$7Nr$B$1] [$B$7VNum$B$1]  [$B$7Name$B$1]$A$7',false,ch,nil,nil,TO_CHAR);
  node := obj_list.head;
  while (node <> nil) do
    begin
    obj := node.element;

    if (obj.area = area) then
      begin
      act(AT_REPORT, pad_integer_front(num, 4) + ' ' + pad_integer(obj.vnum,8) + ' $p',false, ch, obj, nil, TO_CHAR);
      inc(num);
      end;

    node := node.next;
    end;
end;

procedure do_redit(ch : GCharacter; param : string);
var
   location : GRoom;
   sub : string;
   a : integer;
   pexit : GExit;
begin
  if (ch.substate = SUB_ROOM_DESC) then
    begin
    location := ch.edit_dest;
    location.description := ch.edit_buffer;
    ch.stopEditing;

    ch.substate := SUB_NONE;
    exit;
    end;

  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage:  REDIT <field> [value]'#13#10#13#10);
    ch.sendBuffer('Field can be one of the following:'#13#10);
    ch.sendBuffer('  name desc flags sector'#13#10);
    ch.sendBuffer('  televnum teledelay minlevel maxlevel'#13#10);
    ch.sendBuffer('  exflags'#13#10);
    exit;
    end;

  { make sure builders don't overwrite other areas }
  if (ch.room.vnum < ch.player^.r_lo) or (ch.room.vnum > ch.player^.r_hi) then
    begin
    ch.sendBuffer('This vnum is not in your range.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);
  if (sub = 'name') then
    ch.room.name := hash_string(param)
  else
  if (sub = 'desc') then
    begin
    ch.substate := SUB_ROOM_DESC;
    ch.edit_dest := ch.room;
    ch.startEditing(ch.room.description);
    exit;
    end
  else
  if (sub = 'flags') then
    begin
    for a:=0 to High(room_flags) do
     if (pos(room_flags[a], param) > 0) then
      begin
      if IS_SET(ch.room.flags, 1 shl a) then
        REMOVE_BIT(ch.room.flags, 1 shl a)
      else
        SET_BIT(ch.room.flags, 1 shl a);
      end;
    end
  else
  if (sub = 'sector') then
    begin
    for a := 0 to High(sector_types) do
     if (pos(sector_types[a], param ) > 0) then
      begin
      ch.room.sector := a;
      break;
      end;
    end
  else
  if (sub = 'televnum') then
    ch.room.televnum := strtointdef(param, 0)
  else
  if (sub = 'teledelay') then
    ch.room.teledelay := strtointdef(param, 0)
  else
  if (sub = 'minlevel') then
    ch.room.min_level := strtointdef(param, 0)
  else
  if (sub = 'maxlevel') then
    ch.room.max_level:=strtoint(param)
  else
  if (sub = 'exflags') then
    begin
    param := one_argument(param,sub);

    a := findHeading(sub);
    pexit := ch.room.findExit(a);

    if (pexit=nil) then
      begin
      ch.sendBuffer('Can not find that exit.'#13#10);
      exit;
      end;

    for a:=0 to High(exit_flags) do
     if (pos(exit_flags[a], param) > 0) then
      begin
      if IS_SET(pexit.flags, 1 shl a) then
        REMOVE_BIT(pexit.flags, 1 shl a)
      else
        SET_BIT(pexit.flags, 1 shl a);
      end;
    end
  else
    begin
    ch.sendBuffer('Unknown option.'#13#10);
    exit;
    end;
    
  ch.sendBuffer('Ok.'#13#10);
end;

procedure do_rlink(ch : GCharacter; param : string);
var dir:integer;
    vnum:integer;
    to_room : GRoom;
    to_exit, from_exit : GExit;
    sub : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: RLINK <direction> <vnum>'#13#10#13#10);
    ch.sendBuffer('Creates a double linked exit to the designated vnum.'#13#10);
    exit;
    end;
  if (ch.getTrust < LEVEL_GOD) and (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (ch.getTrust < LEVEL_GOD) and (ch.player^.area = nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);
  dir := findHeading(sub);
  if (dir=-1) then
    begin
    ch.sendBuffer('Invalid direction.'#13#10);
    exit;
    end;

  one_argument(param,sub);

  try
    vnum := strtoint(sub);
  except
    ch.sendBuffer('Invalid numeric format.'#13#10);
    exit;
  end;

  to_room := findRoom(vnum);

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

  if (ch.room.findExit(dir) <> nil) then
    begin
    ch.sendBuffer('An exit in that direction already exists!'#13#10);
    exit;
    end;

  to_exit := GExit.Create;
  to_exit.direction := dir;
  to_exit.vnum := vnum;
  to_exit.to_room := to_room;

  ch.room.exits.insertLast(to_exit);

  from_exit := GExit.Create;
  from_exit.direction := dir_inv[dir];
  from_exit.vnum := ch.room.vnum;
  from_exit.to_room := ch.room;

  to_room.exits.insertLast(from_exit);

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

function findFreeVNum(ch : GCharacter) : integer;
var
   room : GRoom;
   node : GListNode;
   vnum : integer;
begin
  vnum := ch.player^.r_lo;

  node := room_list.head;
  while (node <> nil) do
    begin
    room := node.element;

    if (room.vnum > vnum) and (room.vnum<=ch.player^.r_hi) then
      vnum:=room.vnum;

    node := node.next;
    end;

  inc(vnum);

  if (vnum = ch.player^.r_hi) then
    Result := -1
  else
    Result := vnum;
end;

function createRoom(vnum : integer; area : GArea) : GRoom;
var
   room : GRoom;
begin
  room := GRoom.Create(vnum, area);
  room.name := hash_string('Floating in a void');
  room.description := 'Merely wisps of gas and steam, this room has not yet been clearly defined.';

  room.node := room_list.insertLast(room);

  Result := room;
end;

procedure do_rmake(ch : GCharacter; param : string);
var dir:integer;
    new_vnum:integer;
    to_exit, from_exit : GExit;
    new_room : GRoom;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: RMAKE <direction>'#13#10#13#10);
    ch.sendBuffer('Creates a new room within your vnum range linked to the current room,'#13#10);
    ch.sendBuffer('name and sector type are copied to the new room.'#13#10);
    exit;
    end;

  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area_fname='') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area=nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  dir := findHeading(param);

  if (dir = -1) then
    begin
    ch.sendBuffer('Invalid direction.'#13#10);
    exit;
    end;

  new_vnum:=FindFreeVNum(ch);
  if (new_vnum=-1) then
    begin
    ch.sendBuffer('No more vnums available in your range. Try decreasing the size'#13#10);
    ch.sendBuffer('of your area or asking another immortal for more a bigger range.'#13#10);
    exit;
    end;

  if (ch.room.findExit(dir) <> nil) then
    begin
    ch.sendBuffer('An exit in that direction already exists!'#13#10);
    exit;
    end;

  ch.sendBuffer('Creating room #' + inttostr(new_vnum) + '.'#13#10);

  new_room := createRoom(new_vnum, ch.room.area);

  new_room.name := hash_string(ch.room.name);
  new_room.sector := ch.room.sector;

  to_exit := GExit.Create;
  to_exit.direction := dir;
  to_exit.vnum := new_vnum;
  to_exit.to_room := new_room;

  ch.room.exits.insertLast(to_exit);

  from_exit := GExit.Create;
  from_exit.direction := dir_inv[dir];
  from_exit.vnum := ch.room.vnum;
  from_exit.to_room := ch.room;

  new_room.exits.insertLast(from_exit);

  interpret(ch,headings[dir]);
end;

procedure do_rclone(ch : GCharacter; param : string);
var dir : integer;
    new_vnum : integer;
    to_exit, from_exit : GExit;
    new_room : GRoom;
    area : GArea;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: RCLONE <direction>'#13#10#13#10);
    ch.sendBuffer('Creates a new room within your vnum range linked to the current room,'#13#10);
    ch.sendBuffer('cloning all the information, except for the exits.'#13#10);
    exit;
    end;

  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area = nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  dir := FindHeading(param);
  if (dir = -1) then
    begin
    ch.sendBuffer('Invalid direction. Please use north, south, west, east, down or up.'#13#10);
    exit;
    end;

  new_vnum := findFreeVNum(ch);
  if (new_vnum = -1) then
    begin
    ch.sendBuffer('No more vnums available in your range. Try decreasing the size'#13#10);
    ch.sendBuffer('of your area or asking another immortal for a bigger range.'#13#10);
    exit;
    end;

  if (ch.room.findExit(dir) <> nil) then
    begin
    ch.sendBuffer('An exit in that direction already exists!'#13#10);
    exit;
    end;

  ch.sendBuffer('Creating room #'+inttostr(new_vnum)+'.'#13#10);

  area := ch.player^.area;
  new_room := createRoom(new_vnum, area);
  new_room.name := hash_string(ch.room.name);
  new_room.description := ch.room.description;
  new_room.flags := ch.room.flags;
  new_room.televnum := ch.room.televnum;
  new_room.teledelay := ch.room.teledelay;
  new_room.min_level := ch.room.min_level;
  new_room.max_level := ch.room.max_level;
  new_room.sector := ch.room.sector;

  to_exit := GExit.Create;
  to_exit.direction := dir;
  to_exit.vnum := new_vnum;
  to_exit.to_room := new_room;

  ch.room.exits.insertLast(to_exit);

  from_exit := GExit.Create;
  from_exit.direction := dir_inv[dir];
  from_exit.vnum := ch.room.vnum;
  from_exit.to_room := ch.room;

  new_room.exits.insertLast(from_exit);

  interpret(ch,headings[dir]);
end;

{ Re-added area assign - Nemesis }
procedure do_aassign(ch:GCharacter;param:string);
var vict : GCharacter;
    area : GArea;
    sub : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: AASSIGN <player> <filename>'#13#10#13#10);
    ch.sendBuffer('Assigns an area to a player for online construction.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);
  vict := findCharWorld(ch,sub);

  if (vict = nil) or (vict.IS_NPC) then
    ch.sendBuffer('That player cannot be found.'#13#10)
  else
  if (vict.level < LEVEL_BUILD) then
    ch.sendBuffer('That character has not attained the proper level.'#13#10)
  else
    begin
    area := findArea(param);

    if (area <> nil) then
      begin
      act(AT_REPORT,'Area ' + param + ' assigned to $N.',false,ch,nil,vict,TO_CHAR);

      if (vict <> ch) then
        act(AT_REPORT,ch.name^ + ' has assigned ' + param + ' to you.',false,vict,nil,ch,TO_CHAR);

      vict.player^.area := area;
      vict.player^.area_fname := param;
      vict.player^.r_lo := area.r_lo;
      vict.player^.r_hi := area.r_hi;
      vict.player^.m_lo := area.m_lo;
      vict.player^.m_hi := area.m_hi;
      vict.player^.o_lo := area.o_lo;
      vict.player^.o_hi := area.o_hi;
      end
    else
      ch.sendBuffer('That area cannot be found.'#13#10);
    end;
end;

procedure do_ranges(ch : GCharacter; param : string);
var
   vict : GCharacter;
   sub : string;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: RANGES <player> <roomlo> <roomhi> <moblo> <mobhi> <objlo> <objhi>'#13#10#13#10);
    ch.sendBuffer('Manually assigns ranges to a player, and overrides those'#13#10);
    ch.sendBuffer('automatically assigned by AASSIGN.'#13#10);
    exit;
    end;

  param := one_argument(param,sub);
  vict := findCharWorld(ch,sub);

  if (vict = nil) or (vict.IS_NPC()) then
    ch.sendBuffer('Cannot find that character.'#13#10)
  else
  if (vict.level < LEVEL_BUILD) then
    ch.sendBuffer('That character has not attained the proper level.'#13#10)
  else
    begin
    try
      with vict.player^ do
        begin
        param := one_argument(param,sub);
        r_lo := strtoint(sub);

        param := one_argument(param,sub);
        r_hi := strtoint(sub);

        param := one_argument(param,sub);
        m_lo := strtoint(sub);

        param:= one_argument(param,sub);
        m_hi := strtoint(sub);

        param:= one_argument(param,sub);
        o_lo := strtoint(sub);

        one_argument(param,sub);
        o_hi := strtoint(sub);
        end;

      act(AT_REPORT,'Assigned appropiate ranges to $N.',false,ch,nil,vict,TO_CHAR);
      act(AT_REPORT,'You have been assigned new ranges by $N.',false,vict,nil,ch,TO_CHAR);
    except
      ch.sendBuffer('Invalid numeric format.'#13#10);
    end;
    end;
end;

function createArea(fn : string) : GArea;
var
   area : GArea;
begin
  area := GArea.create;

  area.m_lo := High(integer);
  area.m_hi := -1;
  area.r_lo := High(integer);
  area.r_hi := -1;
  area.o_lo := High(integer);
  area.o_hi := -1;

  area.fname := fn;
  area.author := 'No author';
  area.reset_msg := 'No reset message';
  area.name := 'New area';

  area.max_age := 10;
  area.age := 0;
  area.flags := 0;

  with area.weather do
    begin
    mmhg := 1000;
    sky := SKY_CLOUDLESS;
    change := 0;
    temp := 20;
    temp_avg := 20;
    temp_mult := 5;
    end;

  area_list.insertLast(area);

  Result := area;
end;

procedure do_acreate(ch : GCharacter; param : string);
var
   area : GArea;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: ACREATE <filename>'#13#10#13#10);
    ch.sendBuffer('Creates a new area file using default values.'#13#10);
    exit;
    end;

  area := findArea(param);
  if (area <> nil) then
    begin
    ch.sendBuffer('Area already exists.'#13#10);
    exit;
    end;

  area := createArea(param);
  area.author := ch.name^;
  area.flags := AREA_NOPC or AREA_PROTO;           { not for mortals, proto }
  act(AT_REPORT,'Area '+param+' created.',false,ch,nil,nil,TO_CHAR);
end;

const area_flags : array[0..2] of string = ('noreset','nopc','proto');

procedure do_aset(ch : GCharacter; param : string);
var
   area : GArea;
   sub : string;
   a : integer;
begin
  if (length(param) = 0) then
    begin
    ch.sendBuffer('Usage: ASET <field> <value>'#13#10#13#10);
    ch.sendBuffer('Field can be one of the following:'#13#10#13#10);
    ch.sendBuffer('  author name resetmsg age flags'#13#10);
    exit;
    end;

  if (ch.player^.area_fname='') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (ch.player^.area=nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  area := ch.player^.area;
  param := one_argument(param,sub);

  if (sub = 'author') then
    area.author := param
  else
  if (sub = 'name') then
    area.name := param
  else
  if (sub = 'resetmsg') then
    area.reset_msg := param
  else
  if (sub = 'age') then
    area.max_age := strtointdef(param, 0)
  else
  if (sub = 'flags') then
    begin
    for a:=0 to High(area_flags) do
     if (pos(area_flags[a], param) > 0) then
      begin
      if IS_SET(area.flags,1 shl a) then
        REMOVE_BIT(area.flags, 1 shl a)
      else
        SET_BIT(area.flags,1 shl a);
      end;
    end
  else
    begin
    ch.sendBuffer('Unknown option.'#13#10);
    exit;
    end;

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

procedure do_astat(ch : GCharacter; param : string);
var
   area : GArea;
   buf : string;
   a : integer;
begin
  if (ch.player^.area_fname='') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  area:=ch.player^.area;
  if (area=nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  act(AT_REPORT, '['+area.fname+']'#13#10,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT, 'Name:             '+area.name,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT, 'Author:           '+area.author,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT, 'Reset message:    '+area.reset_msg,false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT, 'Maximum age:      '+inttostr(area.max_age),false,ch,nil,nil,TO_CHAR);

  buf := 'Ranges:          ';

  if (area.r_lo <> High(integer)) then
    buf := buf + ' ' + inttostr(area.r_lo)+'-'+inttostr(area.r_hi);

  if (area.m_lo <> High(integer)) then
    buf := buf + ' ' + inttostr(area.m_lo)+'-'+inttostr(area.m_hi);

  if (area.o_lo <> High(integer)) then
    buf := buf + ' ' + inttostr(area.o_lo)+'-'+inttostr(area.o_hi);

  act(AT_REPORT,buf,false,ch,nil,nil,TO_CHAR);

  buf := 'Flags:           ';

  if (area.flags = 0) then
    buf := buf + ' none'
  else
  for a:=0 to High(area_flags) do
   if IS_SET(area.flags,1 shl a) then
    buf := buf + ' ' + area_flags[a];

  act(AT_REPORT,buf,false,ch,nil,nil,TO_CHAR);

  act(AT_REPORT,'Nr. of resets:    '+inttostr(area.resets.getSize()),false,ch,nil,nil,TO_CHAR);
  act(AT_REPORT,'Nr. of players:   '+inttostr(area.nplayer),false,ch,nil,nil,TO_CHAR);
end;

procedure do_checkarea(ch : GCharacter; param : string);
var
   room : GRoom;
   obj : GObjectIndex;
   mob : GNPCIndex;
   area : GArea;
   node : GListNode;
   no_errors : boolean;
begin
  if (ch.player^.area_fname='') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;
  area:=ch.player^.area;
  if (area=nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  ch.sendBuffer('Checking area '+area.fname+'...'#13#10#13#10);
  no_errors := true;

  node := room_list.head;

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

    if (room.area = area) then
      begin
      if (room.name = nil) or (length(room.name^) = 0) then
        begin
        no_errors := false;
        ch.sendBuffer('('+inttostr(room.vnum)+') WARNING room name empty'#13#10);
        end;
      { else
      if (find_last(room.name) = '.') then
        begin
        no_errors:=false;
        ch.sendBuffer('('+inttostr(room.vnum)+') '+room.name+': dot not allowed in room name'#13#10));
        end; }

      if (length(room.description) = 0) then
        begin
        no_errors := false;
        ch.sendBuffer('('+inttostr(room.vnum)+') WARNING room description null'#13#10);
        end;
      { else
      if (find_last(room.description)<>'.') then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(room.vnum)+') '+room.name+': dot required in room description'#13#10));
        end; }


      if (not checkWords(room.description)) then
        begin
        no_errors:=false;
        ch.sendBuffer('('+inttostr(room.vnum)+') possibly misspelled word(s), [' + trim(misspelled_words) + ']'#13#10);
        end;
      end;

    node := node.next;
    end;

  { obj := obj_reset_first;
  while (obj <> nil) do
    begin
    if (obj.area=area) then
      begin
      if (obj.name[0] in ['A'..'Z']) then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': capitals not allowed at start of name'));
        end;
      if (obj.short[0] in ['A'..'Z']) then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': capitals not allowed at start of short description'));
        end;
      if (obj.long[0] in ['A'..'Z']) then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': capitals not allowed at start of long description'));
        end;
      if (find_last(obj.name)='.') then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': dot not allowed at end of name'));
        end;
      if (find_last(obj.short)='.') then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': dot not allowed at end of short description'));
        end;
      if (find_last(obj.long)='.') then
        begin
        no_errors:=false;
        ch.sendBuffer(pchar('('+inttostr(obj.vnum)+') '+obj.name+': dot not allowed at end of long description'));
        end;
      end;
    obj:=obj.next;
    end;
  mob:=mob_reset_first;
  while (mob<>nil) do
    begin
    if (mob.area=area) then
      begin
      if (find_last(mob.name)='.') then
        begin
        ch.sendBuffer(pchar('('+inttostr(mob.vnum)+') '+mob.name+': dot not allowed at end of name'));
        exit;
        end;
      if (find_last(mob.short)='.') then
        begin
        ch.sendBuffer(pchar('('+inttostr(mob.vnum)+') '+mob.name+': dot not allowed at end of short description'));
        exit;
        end;
      if (find_last(mob.long)='.') then
        begin
        ch.sendBuffer(pchar('('+inttostr(mob.vnum)+') '+mob.name+': dot not allowed at end of long description'));
        exit;
        end;
      end;
    mob:=mob.next;
    end; }

  if (no_errors) then
    ch.sendBuffer('Your area is perfectly fine.'#13#10);
end;

procedure do_savearea(ch : GCharacter; param : string);
var
   area : GArea;
begin
  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if ((ch.getTrust() < LEVEL_GOD) or (length(param) = 0)) and (ch.player^.area = nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  if (length(param) = 0) then
    area:=ch.player^.area
  else
    begin
    if (ch.getTrust() < LEVEL_GOD) then
      begin
      ch.sendBuffer('You can only save your own area.'#13#10);
      exit;
      end;

    area := findArea(param);

    if (area = nil) then
      begin
      ch.sendBuffer('Area not found.'#13#10);
      exit;
      end;
    end;

  ch.sendBuffer('Saving ' + area.fname + '...');

  area.save(area.fname);

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

procedure do_loadarea(ch : GCharacter; param : string);
var
   area : GArea;
   fn : string;
begin
  if (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if (length(param) = 0) then
    fn := ch.player^.area_fname
  else
    begin
    if (ch.getTrust() < LEVEL_GOD) then
      begin
      ch.sendBuffer('You can only load your own area.'#13#10);
      exit;
      end;

    fn := param;
    end;

  area := findArea(fn);
  if (area <> nil) then
    begin
    ch.sendBuffer('That area is already loaded.'#13#10);
    exit;
    end;

  area := GArea.Create;
  area.load(fn);
  ch.player^.area := area;
  act(AT_REPORT,'Area ' + fn + ' loaded.',false,ch,nil,nil,TO_CHAR);
end;

procedure do_reset(ch: GCharacter; param : string);
var
   area : GArea;
   node : GListNode;
begin
  area := nil;

  if (length(param) > 0) and (ch.getTrust() < LEVEL_GOD) then
    begin
    ch.sendBuffer('You can only reset your own area.'#13#10);
    exit;
    end;

  if (ch.getTrust() < LEVEL_GOD) and (ch.player^.area_fname = '') then
    begin
    ch.sendBuffer('You have not yet been assigned an area.'#13#10);
    exit;
    end;

  if ((ch.getTrust() < LEVEL_GOD) or (length(param) = 0)) and (ch.player^.area = nil) then
    begin
    ch.sendBuffer('Use LOADAREA first to loadup your assigned area.'#13#10);
    exit;
    end;

  if (length(param) = 0) then
    area := ch.player^.area
  else
  if (length(param) > 0) and (param = 'all') then
    begin
    act(AT_WHITE,'All areas reset.',false,ch,nil,nil,TO_CHAR);

    { reset the areas }
    node := area_list.head;

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

      node := node.next;
      end;

    exit;
    end
  else
  if (length(param) > 0) then
    area := findArea(param);

  if (area = nil) then
    begin
    ch.sendBuffer('Area not found.'#13#10);
    exit;
    end;

  act(AT_WHITE, 'Area '+area.fname+' reset.',false,ch,nil,nil,TO_CHAR);
  area.reset();
end;