Class Customer(MaxCustomers)
with parse_name [i j k isnum;
isnum=0; i=0;
if (self has male) j='man'; else j='woman';
for(::) {
k=NextWord(); wn--;
if (k=='customer' or 'client' or 'person' or j)
i++;
else if (TryNumber(wn)==self.number)
{ i++; isnum=1;}
else
{wn++; return (i*isnum);}
wn++;
} ],
before [; Make:<<MakeHelp>>;
Attack:
remove self;
Customer.destroy(self);
"The customer falls dead by your hand. Several GUE \
custodial staff wander in and remove the body.";],
short_name [; print "Customer ", self.number; rtrue;],
desc_head,
description [;
if (self in Queue)
print_ret (string) self.desc_head, "is standing in line.";
else
print_ret (string) self.desc_head,"is at ",(the) parent(self),"."; ],
time 0,
create [;
self.number=CID; CID++; self.time=turns;
if (random(2)==1) {
give self ~female male ~neuter;
self.desc_head="He "; }
else {
give self female ~male ~neuter;
self.desc_head="She "; }
move self to Queue;
print_ret "Customer ",self.number," enters the Bank.";
],
destroy [;
PronounFlush(self);
],
life [;
Ask, Tell, Answer: "The customer pretends not to hear you."; ],
orders [; "The customer pretends not to hear you."; ],
number,
has proper animate scenery concealed;
Class Teller(MaxTellers)
with parse_name [i j isnum; isnum=0; i=0;
for(::) {
j=NextWord(); wn--;
if (j=='teller' or 'server' or 'clerk' or 'man' or 'woman' or 'epicene' or
'gnome' or 'zurich' or 'window' or 'of')
i++;
else if (TryNumber(wn)==self.number)
{i++; isnum=1;}
else
{wn++; return (i*isnum);}
wn++;
} ],
short_name [; print "Teller ", self.number; rtrue;],
before [i; Make:<<MakeHelp>>;
Attack: remove self;
print "The teller falls backwards and lands ungracefully \
behind the window. Seconds later, a screen is \
pulled across the window by an unseen hand.";
if (child(self)~=nothing) {
i=child(self);
print " ",(The) i," leaves the bank disgusted.^";
remove i;
Customer.destroy(i);}
else print "^";
StopDaemon(self);
Teller.destroy(self);
return true;
],
create [;
StartDaemon(self);
self.number=SID; SID++;
move self to Bank;
],
destroy [;
PronounFlush(self);
],
description [; print "The teller is a completely average epicene gnome of \
Zurich (FrobozzCo supply catalog #423126709)";
if (child(self)~=nothing)
print ", currently serving ",(the) child(self);
"."; ],
daemon [i j;
(ServerLive-->(self.number))++;
if (child(self)~=nothing) (ServerUse-->(self.number))++;
if ((child(self)~=nothing) && (random(Job_Timer.number)==1)) {
print "Customer ",child(self).number," finishes his business and leaves the \
Bank. Teller ",self.number," is now available.^";
i=child(self);
remove i;
Customer.destroy(i);
}
if ((child(self)==nothing) && (child(Queue)~=nothing)) {
i=child(Queue);
while (sibling(i)~=nothing) i=sibling(i);
j=turns-i.time;
CustsServed++;
WaitTimes=WaitTimes+j;
print "Customer ",i.number," walks up to Teller
",self.number,", after waiting ",j," turns.^";
move i to self; }
],
life [;
Ask, Tell, Answer: "The teller pretends not to hear you.";
],
number,
orders [; "The teller pretends not to hear you."; ],
has proper male neuter female animate container open scenery concealed;
Object Bank "Bank of Zork"
with name "door" "doors""carpet" "rug" "carpeting",
description "Huge glass doors flank the southern exit of the awe-inspiring \
Bank of Zork. Plush red carpeting runs the full length of this tremendous hall \
up to the narrow, glass windows lining the northern end of the hall. From all \
around, although not emanating from a clear source, you hear the muted ringing \
of telephones and taps of typing.",
before [; Go: if (noun==s_obj) {rhetoricflag=2; "Leaving so soon?";}
if (noun==n_obj) "The windows are locked and reinforced against burglars like \
you.";
Exit: rhetoricflag=2; "Leaving so soon?";
Yes: if (rhetoricflag>0) "No, you're not. I'm the game and you're just the player. \
So if I don't want you to leave, you don't leave. If you \
don't like it, then just quit. But you're not leaving.";
No: if (rhetoricflag>0) "Good.";
],
daemon [i;
rhetoricflag--;
if (random(Arrival_Timer.number)==1) {
if (Customer.remaining()==0) "A customer almost enters the bank, but thinks better of \
it after seeing the length of the line.";
i=Customer.create();}
],
has light;
Object -> Queue "queue"
with name "queue" "line" "posts" "post" "rope",
initial [; if (children(self)==0) "An empty grid of posts and rope \
indicates a queue.";
if (children(self)<5) "A queue contains a few people here.";
if (children(self)<10) "A queue contains several people here.";
"A queue contains many people here.";
],
before [; Enter: "You aren't a customer.";
Search: <<Examine self>>;
],
description [j x;
if (children(self)==0) "There are no customers in the queue.";
if (children(self)==1) {
print "The customer currently in the queue is numbered ",
child(self).number;
".";
}
print "The customers currently in the queue are numbered ";
if (children(self)==2) {
j=0;
objectloop (x in self) {
j++;
if (j==1) print x.number," and ";
else print x.number;
}
".";
}
j=0;
objectloop (x in self) {
j++;
if (j<children(self)-1) print x.number,", ";
else if (j==children(self)-1) print x.number,", and ";
else print x.number;
}
".";
],
has static open container;
Object -> Gen_Customer "customers"
with name "customer" "client" "person" "man" "woman" "customers" "clients"
"people" "men" "women",
description [; <<Push self>>;],
before [i j x; Make: print "With a crackle of eldritch energy...^";
if (Customer.remaining()==0) "A customer almost enters the bank, but thinks better of \
it after seeing the length of the line.";
i=Customer.create();
rtrue;
default:
j=0;
objectloop (x ofclass Customer) if (x.number~=0) j++;
if (j==0) "There are no customers in the bank.";
print "Please refer to customers by number. ";
if (j==1) {
print "The customer currently in the Bank is numbered ";
objectloop (x ofclass Customer) {
if (x.number~=0) print x.number;
}
".";
}
if (j==2) {
print "The customers currently in the Bank are numbered ";
i=0;
objectloop (x ofclass Customer) {
if (x.number~=0) { i++;
if (i==1) print x.number," and ";
else print x.number; }
}
".";
}
print "The customers currently in the Bank are numbered ";
i=0;
objectloop (x ofclass Customer) {
if (x.number~=0) { i++;
if (i<j-1) print x.number,", ";
else if (i==j-1) print x.number,", and ";
else print x.number;
}}
".";
],
has static scenery concealed pluralname;
Object -> Non_Customer "nonexistent customer"
with parse_name [i k isnum;
isnum=0; i=0;
for(::) {
k=NextWordStopped(); wn--;
if (k=='customer' or 'client' or 'person' or 'man' or 'woman')
i++;
else if ((k~=-1) && (TryNumber(wn)~=-1000))
{ i++; isnum=1;}
else
{wn++; return (i*isnum);}
print k," ",i,"^";
wn++;
} ],
before [; Make:<<MakeHelp>>;
default: "That customer is not in the Bank.";
],
has static scenery concealed;
Object -> Gen_Teller "tellers"
with name "teller" "server" "clerk" "person" "man" "woman" "tellers" "servers"
"window" "windows" "people" "men" "women" "gnomes" "gnome"
"epicene" "of" "zurich",
description [; <<Push self>>;],
before [i j x; Make: print "With a crackle of eldritch energy...^";
if (Teller.remaining()==0) "A teller window tries to form out of a \
vortex in time and space, but doesn't quite materialize.";
x=Teller.create();
"A new teller window slides open.";
default:
j=0;
objectloop (x ofclass Teller) if (x.number~=0) j++;
if (j==0) "There are no tellers in the bank.";
print "Please refer to tellers by number. ";
if (j==1) {
print "The teller currently in the Bank is numbered ";
objectloop (x ofclass Teller) {
if (x.number~=0) print x.number;
}
".";
}
if (j==2) {
print "The tellers currently in the Bank are numbered ";
i=0;
objectloop (x ofclass Teller) {
if (x.number~=0) { i++;
if (i==1) print x.number," and ";
else print x.number; }
}
".";
}
print "The tellers currently in the Bank are numbered ";
i=0;
objectloop (x ofclass Teller) {
if (x.number~=0) { i++;
if (i<j-1) print x.number,", ";
else if (i==j-1) print x.number,", and ";
else print x.number;
}}
".";
],
has static scenery concealed pluralname;
Object -> Non_Teller "nonexistent teller"
with parse_name [i j isnum; isnum=0; i=0;
for(::) {
j=NextWordStopped(); wn--;
if (j=='teller' or 'server' or 'clerk' or 'man' or 'woman' or 'epicene' or
'gnome' or 'zurich' or 'window' or 'of')
i++;
else if ((j~=-1) && (TryNumber(wn)~=-1000))
{i++; isnum=1;}
else
{wn++; return (i*isnum);}
wn++;
} ],
before [; Make:<<MakeHelp>>;
default: "That teller is not in the Bank.";
],
has static scenery concealed;
Object -> Arrival_Timer "Arrival Timer"
with name "arrival" "timer" "frequency" "control",
number 2,
before [;
AdjustSetting: self.number=second;
if (second~=0)
print_ret "Arrivals are now every ",second," time steps.";
"Arrivals are disabled.";
default: "The arrival timer can only be ~set~.";
],
has static scenery concealed;
Object -> Job_Timer "Job Timer"
with name "job" "timer" "frequency" "control" "length" "end",
number 5,
before [;
AdjustSetting: self.number=second;
if (second~=0)
print_ret "Jobs now take, on average, ",second," time steps.";
"Jobs now take infinitely long.";
default: "The job timer can only be ~set~.";
],
has static scenery concealed;
Object notepad "notepad"
with name "notepad" "pad" "note" "notes" "paper" "papers" "usage",
description [i; print "The daily statistics are as follows:^";
font off;
print "Customers served: ",CustsServed,"^";
if (CustsServed~=0) print "Average customer wait time: ",WaitTimes/CustsServed,".",
((WaitTimes*10)/CustsServed)%10,"^^";
for(i=1:i<=SID:i++) if ((ServerLive-->i)~=0) {
print "Teller ";
if ((SID>=10) && (i<10)) print " ";
print i, " utilization rate: ";
if (SID<10) print " ";
print ((ServerUse-->i)*100)/(ServerLive-->i),"%^";
}
font on;
"^This is another fine product of the Frobozz Magic Paper Company.";
];
[ChooseObjects obj code;
if (code<2) { if (obj~=Queue) return 0; rfalse;}
if (obj ofclass Customer or Teller) return 1;
if ((obj==Gen_Teller) && (Teller.remaining()==MaxTellers)) return 1;
if ((obj==Gen_Customer) && (Customer.remaining()==MaxCustomers)) return 1;
if (obj==Non_Teller or Non_Customer) return 0;
return 5;
];
[PronounFlush obj x;
for (x = 1 : x <= LanguagePronouns-->0: x = x+3)
if ((LanguagePronouns-->(x+2))==obj)
LanguagePronouns-->(x+2)=NULL;
#ifdef EnglishNaturalLanguage;
itobj = PronounValue('it'); old_itobj = itobj;
himobj = PronounValue('him'); old_himobj = himobj;
herobj = PronounValue('her'); old_herobj = herobj;
#endif;
];
#IFDEF DEBUG;
[XPurloinSub;
"[The purloin command has been specifically disabled in this program.]";
];
[XAbstractSub;
"[The abstract command has been specifically disabled in this program.]";
];
#ENDIF;
Include "Grammar";
[AboutSub;
"The Bank of Zork was born as a project for a high school modeling and simulation class. \
This particular project was eventually completed in Pascal, due mostly to limitations on \
floating-point representations in Inform. Since then, I have turned the queueing model core \
(which was by far one of the simplest parts of the project) into a full-fledged parser-hacking \
exercise. Some particularly interesting hacks are hermaphroditic tellers, numbered people \
(a code snippet stolen shamelessly from Graham Nelson's ~Balances~), pronoun management for \
disappearing objects, and a few other interesting exercises. This is my first full program in \
Inform, so I'm glad it was such a learning experience. Below is a little more information on \
specifics of this project.^^\
VERBS OF NOTE:^\
If you ~make~, ~summon~, or a few other synonyms, you can create tellers or customers. The same \
is true, in reverse, of ~kill~, ~destroy~, and its ilk. You can also ~set~ the simulation \
parameters, the job timer and arrival timer.^^\
FEATURES (PATCHED BUGS):^\
No more than 31 tellers or 150 customers can be active at once. If there is an arrival and/or \
summoning to exceed this number, the program will reply in form.^^\
BUGS:^\
After about 367 active turns, the teller statistics on the notepad will become unreliable as \
integers overflow . The same is true of the tenths digit of the customer wait time after \
3678 turns. I don't really see any way to fix this bug without recreating integer arithmetic.^^\
FEEDBACK:^\
If you've found a particularly interesting bug or typo or strangeness of this program, or just \
feel like telling me something, you can write me at dwildstr@@64mbhs.edu or dwildstr@@64mit.edu. I'm \
not sure how long either of these accounts will be active: wait for release 2 for deatails.";
];
[MakeSub;
"That isn't something you can create.";];
[MakeHelpSub;
"You cannot make a numbered object. Please refer to objects in general \
(i.e. ~make teller~ instead of ~make teller 4~).";];
[AdjustSettingSub;
"That isn't an adjustable simulation parameter.";];
[AdjustHelpSub;
"You can only set simulation parameters to numbers.";];
Verb meta "about" "help" "author" "info" "information"
* special -> About;
Verb "create" "make" "summon" "construct" "build"
* noun -> Make
* noun number -> MakeHelp;
Extend "set" first
* noun "to" number -> AdjustSetting
* noun "to" special -> AdjustHelp;