{
Summary:
(N)PC classes & routines
## $Id: chars.pas,v 1.14 2004/04/10 22:24:03 druid Exp $
}
unit chars;
interface
uses
SysUtils,
Math,
{$IFDEF LINUX}
Libc,
{$ENDIF}
area,
race,
clan,
dtypes,
gvm;
{$M+}
type
GCharacter = class;
GTrophy = record
name : string;
level, times : integer;
end;
GAlias = class
public
alias : string;
expand : string;
node : GListNode;
end;
GHistoryElement = class
public
time : TDateTime;
contents : PString;
constructor Create(const txt : string);
destructor Destroy(); override;
end;
GUserChannel = class
public
channelname : string;
history : GDLinkedList;
ignored : boolean;
constructor Create(const name : string);
destructor Destroy(); override;
end;
GLearned = class
public
node : GListNode;
skill : pointer;
perc : integer;
constructor Create(perc_ : integer; skill_ : pointer);
end;
{$M+}
GCharacter = class
node_world, node_room : GListNode;
inventory : GDLinkedList;
equipment : GHashTable;
master, leader : GCharacter;
fighting, hunting : GCharacter;
snooped_by : GCharacter;
protected
_level : integer;
_str, _con, _dex, _int, _wis : integer;
_hp, _max_hp : integer;
_mv, _max_mv : integer;
_mana, _max_mana : integer;
_apb : integer;
_alignment : integer;
_gold : integer; { Gold carried }
_sex : integer;
_save_poison, _save_cold, _save_para, { saving throws }
_save_breath, _save_spell : integer;
_name, _short, _long : PString;
public
ac_mod : integer; { AC modifier (spells?) }
natural_ac : integer; { Natural AC (race based for PC's) }
hac, bac, aac, lac, ac : integer; { head, body, arm, leg and overall ac }
hitroll : integer; { the hit roll }
damnumdie, damsizedie : integer;
tracking : string;
logging : boolean;
position : integer;
state : integer;
mental_state : integer;
room : GRoom;
substate : integer;
trust : integer;
kills : integer;
wait : integer;
skills_learned : GDLinkedList;
cast_timer, bash_timer, bashing : integer;
in_command : boolean;
race : GRace;
carried_weight : integer; { weight of items carried }
weight, height : integer; { weight/height of (N)PC }
last_cmd : pointer;
affects : GDLinkedList;
aff_flags : cardinal;
clan : GClan; { joined a clan? }
procedure sendPrompt; virtual;
procedure sendBuffer(const s : string); virtual;
procedure sendPager(const txt : string); virtual;
procedure emptyBuffer; virtual;
function ansiColor(color : integer) : string; virtual;
function getTrust() : integer;
function CHAR_DIED : boolean;
function IS_IMMORT : boolean; virtual;
function IS_NPC : boolean; virtual;
function IS_LEARNER : boolean; virtual;
function IS_AWAKE : boolean; virtual;
function IS_INVIS : boolean; virtual;
function IS_HIDDEN : boolean; virtual;
function IS_WIZINVIS : boolean; virtual;
function IS_GOOD : boolean; virtual;
function IS_EVIL : boolean; virtual;
function IS_SAME_ALIGN(vict : GCharacter) : boolean; virtual;
function IS_FLYING : boolean; virtual;
function IS_BANKER : boolean; virtual;
function IS_SHOPKEEPER : boolean; virtual;
function IS_OUTSIDE : boolean; virtual;
function IS_AFFECT(affect : integer) : boolean; virtual;
function IS_DRUNK : boolean; virtual;
function IS_WEARING(item_type : integer) : boolean; virtual;
function IS_HOLYWALK : boolean; virtual;
function IS_HOLYLIGHT : boolean; virtual;
function IS_AFK : boolean; virtual;
function IS_KEYLOCKED : boolean; virtual;
function IS_EDITING : boolean; virtual;
function CAN_FLY : boolean; virtual;
function CAN_SEE(target : TObject) : boolean;
function LEARNED(skill : pointer) : integer;
procedure SET_LEARNED(perc : integer; skill : pointer);
procedure extract(pull : boolean);
procedure fromRoom();
procedure toRoom(to_room : GRoom);
function getEQ(const location : string) : GObject;
function getWield(item_type : integer) : GObject;
function getDualWield() : GObject;
procedure affectObject(obj : GObject; remove: boolean);
function equip(obj : GObject; silent : boolean = false) : boolean;
procedure die(); virtual;
procedure setWait(ticks : integer);
function calcxp2lvl : cardinal;
procedure calcAC();
procedure startFlying();
procedure stopFlying();
function findInventory(s : string) : GObject;
function findEquipment(const s : string) : GObject;
constructor Create();
destructor Destroy(); override;
procedure setName(const name : string);
procedure setShortName(const name : string);
procedure setLongName(const name : string);
function getName() : string;
function getShortName() : string;
function getLongName() : string;
function getRaceName() : string;
published
// properties
property level : integer read _level write _level;
property str : integer read _str write _str;
property con : integer read _con write _con;
property dex : integer read _dex write _dex;
property int : integer read _int write _int;
property wis : integer read _wis write _wis;
property hp : integer read _hp write _hp;
property max_hp : integer read _max_hp write _max_hp;
property mv : integer read _mv write _mv;
property max_mv : integer read _max_mv write _max_mv;
property mana : integer read _mana write _mana;
property max_mana : integer read _max_mana write _max_mana;
property apb : integer read _apb write _apb;
property alignment : integer read _alignment write _alignment;
property gold : integer read _gold write _gold;
property sex : integer read _sex write _sex;
property save_poison : integer read _save_poison write _save_poison;
property save_cold : integer read _save_cold write _save_cold;
property save_para : integer read _save_para write _save_para;
property save_breath : integer read _save_breath write _save_breath;
property save_spell : integer read _save_spell write _save_spell;
property name : string read getName write setName;
property short : string read getShortName write setShortName;
property long : string read getLongName write setLongName;
property rname : string read getRaceName;
end;
GNPC = class(GCharacter)
public
npc_index : GNPCIndex;
act_flags : cardinal;
context : GContext;
published
constructor Create();
destructor Destroy(); override;
function IS_IMMORT : boolean; override;
function IS_NPC : boolean; override;
function IS_LEARNER : boolean; override;
function IS_WIZINVIS : boolean; override;
function IS_BANKER : boolean; override;
function IS_SHOPKEEPER : boolean; override;
procedure sendBuffer(const s : string); override;
procedure die; override;
end;
{$M-}
var
char_list : GDLinkedList;
extracted_chars : GDLinkedList;
function findCharWorld(ch : GCharacter; name : string) : GCharacter;
procedure cleanExtractedChars();
procedure initChars();
procedure cleanupChars();
implementation
uses
constants,
util,
player,
conns,
skills,
console,
mudsystem;
constructor GHistoryElement.Create(const txt : string);
begin
inherited Create();
time := Now();
contents := hash_string(txt);
end;
destructor GHistoryElement.Destroy();
begin
unhash_string(contents);
inherited Destroy();
end;
constructor GUserChannel.Create(const name : string);
begin
inherited Create();
channelname := name;
history := GDLinkedList.Create();
ignored := false;
end;
destructor GUserChannel.Destroy();
begin
history.clear();
history.Free();
inherited Destroy();
end;
// GCharacter constructor
constructor GCharacter.Create();
begin
inherited Create();
inventory := GDLinkedList.Create();
equipment := GHashTable.Create(32);
equipment.setHashFunc(sortedHash);
affects := GDLinkedList.Create();
master := nil;
snooped_by := nil;
leader := Self;
tracking := '';
end;
// GCharacter destructor
destructor GCharacter.Destroy();
begin
affects.clear();
affects.Free();
inventory.clear();
inventory.Free();
equipment.clear();
equipment.Free();
hunting := nil;
unhash_string(_name);
unhash_string(_short);
unhash_string(_long);
inherited Destroy;
end;
procedure GCharacter.extract(pull : boolean);
{ set pull to false if you wish for character to stay
alive, e.g. in portal or so. don't set to false for NPCs - Grimlord }
begin
if (CHAR_DIED) then
begin
bugreport('extract_char', 'area.pas', 'ch already extracted');
exit;
end;
if (room <> nil) then
fromRoom();
if (not pull) then
begin
if (IS_EVIL) then
toRoom(findRoom(ROOM_VNUM_EVIL_PORTAL))
else
toRoom(findRoom(ROOM_VNUM_GOOD_PORTAL));
end
else
begin
{ TODO:
if (conn <> nil) then
GConnection(conn).ch := nil; }
char_list.remove(node_world);
node_world := extracted_chars.insertLast(Self);
end;
end;
procedure GCharacter.setName(const name : string);
begin
_name := hash_string(name);
end;
procedure GCharacter.setShortName(const name : string);
begin
_short := hash_string(name);
end;
procedure GCharacter.setLongName(const name : string);
begin
_long := hash_string(name);
end;
function GCharacter.getName() : string;
begin
if (_name <> nil) then
Result := _name^
else
Result := '';
end;
function GCharacter.getShortName() : string;
begin
if (_short <> nil) then
Result := _short^
else
Result := '';
end;
function GCharacter.getLongName() : string;
begin
if (_long <> nil) then
Result := _long^
else
Result := '';
end;
function GCharacter.getRaceName() : string;
begin
if (race <> nil) then
Result := race.name
else
Result := '';
end;
function GCharacter.getTrust() : integer;
var
ch : GCharacter;
begin
if (snooped_by <> nil) and (GPlayer(snooped_by).switching = Self) then
ch := snooped_by
else
ch := Self;
if (ch.trust <> 0) then
begin
getTrust := ch.trust;
exit;
end;
if (ch.IS_NPC) then
getTrust := UMax(ch.level, 500)
else
getTrust := ch.level;
end;
function GCharacter.CHAR_DIED : boolean;
var
iterator : GIterator;
ch : GCharacter;
begin
CHAR_DIED := false;
if (Self = nil) then
begin
CHAR_DIED := true;
exit;
end;
iterator := extracted_chars.iterator();
while (iterator.hasNext()) do
begin
ch := GCharacter(iterator.next());
if (ch = Self) then
begin
CHAR_DIED := true;
break;
end;
end;
iterator.Free();
end;
procedure GCharacter.sendPrompt();
begin
end;
procedure GCharacter.sendBuffer(const s : string);
begin
end;
procedure GCharacter.sendPager(const txt : string);
begin
end;
procedure GCharacter.emptyBuffer();
begin
end;
function GCharacter.IS_IMMORT : boolean;
begin
Result := false;
end;
function GCharacter.IS_NPC : boolean;
begin
Result := false;
end;
function GCharacter.IS_LEARNER : boolean;
begin
Result := false;
end;
function GCharacter.IS_AWAKE : boolean;
begin
IS_AWAKE := (state <> STATE_SLEEPING);
end;
function GCharacter.IS_INVIS : boolean;
begin
IS_INVIS := IS_SET(aff_flags, AFF_INVISIBLE);
end;
function GCharacter.IS_HIDDEN : boolean;
begin
IS_HIDDEN := IS_SET(aff_flags, AFF_HIDE);
end;
function GCharacter.IS_WIZINVIS : boolean;
begin
Result := false;
end;
function GCharacter.IS_GOOD : boolean;
begin
IS_GOOD := (alignment >= 0) and (not IS_IMMORT);
end;
function GCharacter.IS_EVIL : boolean;
begin
IS_EVIL := (alignment < 0) and (not IS_IMMORT);
end;
function GCharacter.IS_SAME_ALIGN(vict : GCharacter) : boolean;
begin
IS_SAME_ALIGN := false;
if (vict.IS_IMMORT or IS_IMMORT) or (IS_EVIL and vict.IS_EVIL) or
(IS_GOOD and vict.IS_GOOD) then
IS_SAME_ALIGN := true;
end;
function GCharacter.IS_FLYING : boolean;
begin
Result := (position = POS_FLYING);
end;
function GCharacter.IS_BANKER : boolean;
begin
Result := false;
end;
function GCharacter.IS_SHOPKEEPER : boolean;
begin
Result := false;
end;
function GCharacter.IS_OUTSIDE : boolean;
begin
IS_OUTSIDE := (room.sector <> SECT_INSIDE) and (not room.flags.isBitSet(ROOM_INDOORS));
end;
function GCharacter.IS_AFFECT(affect : integer) : boolean;
begin
IS_AFFECT := IS_SET(aff_flags, affect);
end;
function GCharacter.IS_DRUNK : boolean;
begin
IS_DRUNK := false;
end;
// Char is wearing an object of type <item_type>
function GCharacter.IS_WEARING(item_type : integer) : boolean;
var
iterator : GIterator;
obj : GObject;
begin
Result := false;
iterator := equipment.iterator();
while (iterator.hasNext()) do
begin
obj := GObject(iterator.next());
if (obj.item_type = item_type) then
begin
Result := true;
break;
end;
end;
iterator.Free();
end;
function GCharacter.IS_HOLYWALK : boolean;
begin
Result := false;
end;
function GCharacter.IS_HOLYLIGHT : boolean;
begin
Result := false;
end;
{ Utility function - Nemesis }
function GCharacter.IS_AFK : boolean;
begin
Result := false;
end;
{ utility function - Nemesis }
function GCharacter.IS_KEYLOCKED : boolean;
begin
Result := false;
end;
function GCharacter.IS_EDITING : boolean;
begin
Result := false;
end;
function GCharacter.CAN_FLY : boolean;
begin
Result := false;
if (IS_SET(aff_flags, AFF_LEVITATION)) then
Result := true;
end;
{ can ch see ? }
function GCharacter.CAN_SEE(target : TObject) : boolean;
var
vict : GCharacter;
begin
CAN_SEE := true;
if (Self = target) then
exit;
if (not IS_AWAKE) then
CAN_SEE := false;
if (target is GRoom) then
begin
if (room.IS_DARK) and (not IS_HOLYLIGHT) and (not IS_SET(aff_flags, AFF_INFRAVISION)) then
CAN_SEE := false;
end;
if (target is GCharacter) then
begin
vict := GCharacter(target);
if (vict.IS_INVIS) and (not (IS_SET(aff_flags, AFF_DETECT_INVIS)
or IS_IMMORT)) then
CAN_SEE:=false;
if (vict.IS_HIDDEN) and (not (IS_SET(aff_flags, AFF_DETECT_HIDDEN)
or IS_IMMORT)) then
CAN_SEE := false;
if (vict.IS_WIZINVIS) and (level < GPlayer(vict).wiz_level) then
CAN_SEE := false;
end;
if (IS_SET(aff_flags, AFF_BLIND)) then
CAN_SEE := false;
end;
// Check what percentage char has learned <skill>
function GCharacter.LEARNED(skill : pointer) : integer;
var
iterator : GIterator;
g : GLearned;
begin
Result := 0;
iterator := skills_learned.iterator();
while (iterator.hasNext()) do
begin
g := GLearned(iterator.next());
if (g.skill = skill) then
begin
Result := g.perc;
break;
end;
end;
iterator.Free();
end;
// Xenon 10/Apr/2001: Modified SET_LEARNED() to remove skill from linked list when perc = 0
procedure GCharacter.SET_LEARNED(perc : integer; skill : pointer);
var
iterator : GIterator;
g, x : GLearned;
begin
g := nil;
iterator := skills_learned.iterator();
while (iterator.hasNext()) do
begin
x := GLearned(iterator.next());
if (x.skill = skill) then
begin
g := x;
break;
end;
end;
iterator.Free();
if (g = nil) then
begin
g := GLearned.Create(perc, skill);
g.node := skills_learned.insertLast(g);
end
else
begin
if (perc > 0) then
g.perc := perc
else
skills_learned.remove(g.node);
end;
end;
function GCharacter.ansiColor(color : integer) : string;
begin
Result := '';
end;
// Char from room
procedure GCharacter.fromRoom();
begin
if (room = nil) then
begin
bugreport('GCharacter.fromRoom', 'chars.pas', 'room null');
exit;
end;
room.chars.remove(node_room);
if (IS_WEARING(ITEM_LIGHT)) and (room.light > 0) then
room.light := room.light - 1;
{ Only PCs register as players, so increase the number! - Grimlord }
if (not IS_NPC) then
dec(room.area.nplayer);
room := nil;
end;
// Char to room
procedure GCharacter.toRoom(to_room : GRoom);
var
tele : GTeleport;
iterator : GIterator;
begin
if (to_room = nil) then
begin
bugreport('GCharacter.toRoom', 'chars.pas', 'room null, moving to portal');
if (IS_IMMORT) then
begin
to_room := findRoom(ROOM_VNUM_IMMORTAL_PORTAL);
if (to_room = nil) then
begin
bugreport('GCharacter.toRoom', 'chars.pas', 'immortal portal not found');
end;
end;
if (to_room = nil) then
if (IS_EVIL) then
to_room := findRoom(ROOM_VNUM_EVIL_PORTAL)
else
to_room := findRoom(ROOM_VNUM_GOOD_PORTAL);
if (to_room = nil) then
begin
bugreport('GCharacter.toRoom', 'chars.pas', 'HELP! even portal is NULL room! what did you do?');
writeConsole('System is unstable - prepare for a rough ride');
exit;
end;
end;
room := to_room;
if (IS_WEARING(ITEM_LIGHT)) then
room.light := room.light + 1;
node_room := room.chars.insertLast(Self);
{ Only PCs register as players, so increase the number! - Grimlord }
if (not IS_NPC) then
inc(to_room.area.nplayer);
{ check for teleports }
if (to_room.flags.isBitSet(ROOM_TELEPORT)) and (to_room.teledelay > 0) then
begin
iterator := teleport_list.iterator();
while (iterator.hasNext()) do
begin
tele := GTeleport(iterator.next());
if (tele.t_room = to_room) then
begin
iterator.Free();
exit;
end;
end;
iterator.Free();
tele := GTeleport.Create();
tele.t_room := to_room;
tele.timer := to_room.teledelay;
tele.node := teleport_list.insertLast(tele);
end;
end;
// Char dies
procedure GCharacter.die();
begin
{ snooping/switching immortals should stop doing so when we die }
if (snooped_by <> nil) then
begin
GPlayer(snooped_by).snooping := nil;
GPlayer(snooped_by).switching := nil;
snooped_by.sendBuffer('Ok.'#13#10);
snooped_by := nil;
end;
addCorpse(Self);
end;
// GNPC
constructor GNPC.Create();
begin
inherited Create();
context := nil;
end;
destructor GNPC.Destroy();
begin
if (Assigned(context)) then
FreeAndNil(context);
inherited Destroy();
end;
function GNPC.IS_SHOPKEEPER : boolean;
begin
Result := IS_SET(act_flags, ACT_SHOPKEEP);
end;
function GNPC.IS_BANKER : boolean;
begin
Result := IS_SET(act_flags, ACT_BANKER);
end;
function GNPC.IS_WIZINVIS : boolean;
begin
Result := IS_SET(act_flags, ACT_MOBINVIS)
end;
function GNPC.IS_LEARNER : boolean;
begin
Result := IS_SET(act_flags, ACT_TEACHER);
end;
function GNPC.IS_NPC : boolean;
begin
Result := true;
end;
function GNPC.IS_IMMORT : boolean;
begin
Result := inherited IS_IMMORT;
if (IS_SET(act_flags, ACT_IMMORTAL)) then
IS_IMMORT := true;
end;
procedure GNPC.die();
begin
inherited die();
dec(npc_index.count);
extract(true);
dec(mobs_loaded);
end;
procedure GNPC.sendBuffer(const s : string);
begin
if (snooped_by <> nil) then
GPlayer(snooped_by).conn.send(s);
end;
procedure GCharacter.setWait(ticks : integer);
begin
wait := UMax(wait, ticks);
end;
// Get object wearing at bodypart <location>
function GCharacter.getEQ(const location : string) : GObject;
var
iterator : GIterator;
obj : GObject;
begin
Result := nil;
iterator := equipment.iterator();
while (iterator.hasNext()) do
begin
obj := GObject(iterator.next());
if (obj.worn = location) then
begin
Result := obj;
break;
end;
end;
iterator.Free();
end;
// Get wielded object by <item_type>
function GCharacter.getWield(item_type : integer) : GObject;
var
obj : GOBject;
begin
getWield := nil;
obj := getEQ('rightwield');
if (obj <> nil) and (obj.item_type = item_type) then
begin
getWield := obj;
exit;
end;
obj := getEQ('leftwield');
if (obj <> nil) and (obj.item_type = item_type) then
begin
getWield:=obj;
exit;
end;
end;
function GCharacter.getDualWield() : GObject;
begin
getDualWield := nil;
{ can't dual wield }
if (LEARNED(gsn_dual_wield) = 0) then
exit;
if (getEQ('rightwield') <> nil) and (getEQ('leftwield') <> nil) then
getDualWield := getEQ('leftwield');
end;
// Apply/Remove special affects on an object
procedure GCharacter.affectObject(obj : GObject; remove : boolean);
var
iterator : GIterator;
aff : GAffect;
begin
with obj do
case obj.item_type of
ITEM_ARMOR: calcAC;
ITEM_LIGHT: if (remove) then
Self.room.light := room.light - 1
else
Self.room.light := room.light + 1;
ITEM_GEM: if (remove) then
max_mana := max_mana - obj.value[3]
else
max_mana := max_mana + obj.value[3]
end;
iterator := obj.affects.iterator();
while (iterator.hasNext()) do
begin
aff := GAffect(iterator.next());
aff.modify(Self, not remove);
end;
end;
// Equip object
function GCharacter.equip(obj : GObject; silent : boolean = false) : boolean;
var
bodypart : GBodyPart;
begin
Result := true;
if IS_SET(obj.flags,OBJ_ANTI_GOOD) and IS_GOOD then
begin
act(AT_REPORT,'You are zapped by $p!',false,Self,obj,nil,TO_CHAR);
act(AT_REPORT,'$n is zapped by $p and burns $s hands.',false,Self,obj,nil,TO_ROOM);
obj.fromChar;
obj.toRoom(room);
exit;
end;
if IS_SET(obj.flags,OBJ_ANTI_EVIL) and IS_EVIL then
begin
act(AT_REPORT,'You are zapped by $p!',false,Self,obj,nil,TO_CHAR);
act(AT_REPORT,'$n is zapped by $p and burns $s hands.',false,Self,obj,nil,TO_ROOM);
obj.fromChar;
obj.toRoom(room);
exit;
end;
if (obj.wear_location1 <> '') and (getEQ(obj.wear_location1) = nil) then { Wear on spot #1}
begin
bodypart := GBodyPart(race.bodyparts[obj.wear_location1]);
if (bodypart = nil) then
begin
act(AT_REPORT, 'You do not have the right anatomy to wear $p.', false, Self, obj, nil, TO_CHAR);
Result := false;
exit;
end;
if (not silent) then
begin
act(AT_REPORT, bodypart.char_message, false, Self, obj, nil, TO_CHAR);
act(AT_REPORT, bodypart.room_message, false, Self, obj, nil, TO_ROOM);
end;
obj.fromChar();
obj.worn := obj.wear_location1;
obj.toChar(Self);
affectObject(obj, false);
end
else
if (obj.wear_location2 <> '') and (getEQ(obj.wear_location2) = nil) then { Wear on spot #2}
begin
bodypart := GBodyPart(race.bodyparts[obj.wear_location2]);
if (bodypart = nil) then
begin
act(AT_REPORT, 'You do not have the right anatomy to wear $p.', false, Self, obj, nil, TO_CHAR);
Result := false;
exit;
end;
if (not silent) then
begin
act(AT_REPORT, bodypart.char_message, false, Self, obj, nil, TO_CHAR);
act(AT_REPORT, bodypart.room_message, false, Self, obj, nil, TO_ROOM);
end;
obj.fromChar();
obj.worn := obj.wear_location2;
obj.toChar(Self);
affectObject(obj, false);
end
else { No spots left }
begin
sendBuffer('You are already wearing something there!'#13#10);
Result := false;
end;
end;
function GCharacter.calcxp2lvl : cardinal;
begin
calcxp2lvl := round((20*power(level,1.2))*(1+(random(2)/10)));
end;
// Calculate Armour Class
procedure GCharacter.calcAC();
var
dex_mod : integer;
iterator : GIterator;
obj : GObject;
begin
dex_mod := (dex-50) div 12;
hac := natural_ac - dex_mod + ac_mod;
bac := natural_ac - dex_mod + ac_mod;
aac := natural_ac - dex_mod + ac_mod;
lac := natural_ac - dex_mod + ac_mod;
iterator := equipment.iterator();
while (iterator.hasNext()) do
begin
obj := GObject(iterator.next());
if (obj.item_type = ITEM_ARMOR) then
case obj.value[2] of
ARMOR_HAC : dec(hac, obj.value[3]);
ARMOR_BAC : dec(bac, obj.value[3]);
ARMOR_AAC : dec(aac, obj.value[3]);
ARMOR_LAC : dec(lac, obj.value[3]);
end;
end;
iterator.Free();
ac := (hac + bac + aac + lac) div 4;
end;
// Start flying
procedure GCharacter.startFlying();
begin
if (not IS_OUTSIDE) then
begin
sendBuffer('You cannot fly while indoors!'#13#10);
exit;
end;
if (IS_FLYING) then
begin
sendBuffer('You are already flying!'#13#10);
exit;
end
else
if (CAN_FLY) then
begin
position := POS_FLYING;
act(AT_REPORT,'You begin to fly again!',false,Self,nil,nil,TO_CHAR);
act(AT_REPORT,'$n gently floats up in the air.',false,Self,nil,nil,TO_ROOM);
end
else
begin
act(AT_REPORT,'You flap your arms, but never leave the ground.',false,Self,nil,nil,TO_CHAR);
act(AT_REPORT,'$n flaps $s arms to fly, but can''t.',false,Self,nil,nil,TO_ROOM);
end;
end;
// Stop flying
procedure GCharacter.stopFlying();
begin
if (IS_FLYING) then
begin
position := POS_STANDING;
act(AT_REPORT,'You slowly land on the ground.',false,Self,nil,nil,TO_CHAR);
act(AT_REPORT,'$n gently lands on the ground.',false,Self,nil,nil,TO_ROOM);
end;
end;
// Find object in inventory by name
function GCharacter.findInventory(s : string) : GObject;
var
obj : GObject;
iterator : Giterator;
number, count : integer;
begin
Result := nil;
number := findNumber(s); // eg 2.object
count := 0;
iterator := inventory.iterator();
while (iterator.hasNext()) do
begin
obj := GObject(iterator.next());
if (isObjectName(obj.name, s) or isObjectName(obj.short, s)) then
begin
inc(count);
if (count = number) then
begin
Result := obj;
break;
end;
end;
end;
iterator.Free();
end;
// Find object in equipment by name
function GCharacter.findEquipment(const s : string) : GObject;
var
obj : GObject;
iterator : GIterator;
begin
Result := nil;
iterator := equipment.iterator();
while (iterator.hasNext()) do
begin
obj := GObject(iterator.next());
if (isObjectName(obj.name, s) or isObjectName(obj.short, s)) then
begin
Result := obj;
break;
end;
end;
iterator.Free();
end;
{ Added 2.<char> - Nemesis }
function findCharWorld(ch : GCharacter; name : string) : GCharacter;
var
iterator : GIterator;
vict : GCharacter;
number,count : integer;
begin
findCharWorld := nil;
number := findNumber(name); // eg 2.char
if (uppercase(name) = 'SELF') then
begin
findCharWorld := ch;
exit;
end;
count := 0;
iterator := char_list.iterator();
while (iterator.hasNext()) do
begin
vict := GCharacter(iterator.next());
if (isName(vict.name,name)) or (isName(vict.short,name)) and (ch.CAN_SEE(vict)) then
begin
inc(count);
if (count = number) then
begin
findCharWorld := vict;
break;
end;
end;
end;
iterator.Free();
end;
{ GLearned }
constructor GLearned.Create(perc_: integer; skill_: pointer);
begin
inherited Create;
perc := perc_;
skill := skill_;
end;
procedure cleanExtractedChars();
begin
extracted_chars.clear();
end;
procedure initChars();
begin
char_list := GDLinkedList.Create();
extracted_chars := GDLinkedList.Create();
extracted_chars.ownsObjects := false;
end;
procedure cleanupChars();
begin
char_list.clear();
char_list.Free();
extracted_chars.clear();
extracted_chars.Free();
end;
end.