Roger Firth's IF pages | ![]() |
InFancy -- using Inform objects | ![]() |
![]() |
This is the final form of the code, represented here for ease of reference. As ever, we start with a standard preamble:
Constant Story "INFANCY"; Constant Headline "^A juvenile INFORM program.^"; Constant MANUAL_PRONOUNS; Include "Parser"; Include "VerbLib"; ! ---------------------------------------------------------------------------- ! |
These are the standalone routines:
[ Initialise; location = kitchen; ];
! Locate the (first) child object of a given Class.
[ ChildOfClass obj class
k;
objectloop (k in obj) if (k ofclass class) return k;
return 0;
];
! Ensure compatibility with glulx, which uses four-byte words.
#ifndef WORDSIZE;
Constant TARGET_ZCODE 0;
Constant WORDSIZE 2+TARGET_ZCODE; ! avoid compiler warning
#endif;
! Test if a given value occurs in a given property array of an object.
[ IsAWordIn wd obj prop
k l m;
k = obj.∝ l = (obj.#prop)/WORDSIZE;
for (m=0 : m<l : m++) if (wd == k-->m) rtrue;
rfalse;
];
! ---------------------------------------------------------------------------- !
|
The classes:
Class Room
with description "A bare room."
has light;
Class Furniture
with before [; Take,Pull,Push,PushDir:
print_ret (The) self, " is too heavy for that.";
]
has static supporter;
Class Vessel
with parse_name [ liq qty wd container_count contents_count;
if (parser_action == ##TheSame) return -2;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
for (wd=NextWord() : wd~=0 : wd=NextWord()) switch (wd) {
'of':
if (container_count > 0) container_count++;
'empty','nothing':
if (qty == 0) contents_count++;
default:
if (IsAWordIn(wd,self,name)) container_count++;
else
if (qty > 0 && IsAWordIn(wd,liq,name)) contents_count++;
else jump exitVessel;
}
.exitVessel;
if (container_count > 0) return container_count + contents_count;
return 0;
],
invent [ liq qty;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
if (inventory_stage == 2) {
if (qty == self.capacity) print " (full)";
else
if (qty > 0) print " (partly full)";
}
],
description [ liq qty;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
print "It's currently ";
if (qty == self.capacity) print_ret "full of ", (name) liq, ".";
else
if (qty > 0) print_ret "partly full of ", (name) liq, ".";
else "empty.";
],
before [ liq qty;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
Drink, Empty:
if (self notin player)
print_ret "You need to be holding ", (the) self, ".";
if (qty > 1)
print "You take a mouthful of ", (name) liq, ".^";
else
if (qty == 1)
print "You finish the rest of ", (the) liq, ".^";
else print_ret "There's nothing in ", (the) self, ".";
liq.add_liquid(-1);
rtrue;
Receive: print_ret (The) self, " is meant for holding liquids.";
],
capacity 0 ! Liquid the vessel can contain
has transparent;
Class Liquid(1)
with name 'liquid' '.spare' '.spare' '.spare' '.spare' '.spare',
short_name "liquid",
rename [ sn n0 n1 n2 n3 n4 n5;
if (sn) self.short_name = sn;
if (n0) self.&name-->0 = n0;
if (n1) self.&name-->1 = n1;
if (n2) self.&name-->2 = n2;
if (n3) self.&name-->3 = n3;
if (n4) self.&name-->4 = n4;
if (n5) self.&name-->5 = n5;
],
add_liquid [ qty;
self.capacity = self.capacity + qty;
if (self.capacity > 0)
return self.capacity;
else
{ Liquid.destroy(self); return 0; }
],
description [; print_ret "It looks rather like ", (name) self, "."; ],
article "some",
before [ container; container = parent(self);
Take:
if (container ofclass Vessel) <<Take container>>;
print_ret "You can't take a puddle of ", (name) self, ".";
Drink:
if (container ofclass Vessel) <<Drink container>>;
print_ret "You can't drink a puddle of ", (name) self, ".";
Empty:
if (container ofclass Vessel) <<Empty container>>;
print_ret "You can't do that.";
EmptyT:
if (container ofclass Vessel) <<EmptyT container second>>;
print_ret "You can't do that.";
],
capacity 0; ! Liquid currently in the vessel
! ---------------------------------------------------------------------------- !
|
The instances of those classes -- the actual game objects:
Room kitchen "Kitchen"
with description "Oddly, there are no exits.";
Furniture kitchen_table "table" kitchen
with name 'battered' 'pine' 'table',
initial
"In the centre of the room stands a battered pine table.",
description
"The table is scuffed and stained with indeterminate substances.";
Object bottle "bottle" kitchen_table
with parse_name [ wd adj_count noun_count;
if (parser_action == ##TheSame) return -2;
wd = NextWord();
while (wd == 'green' or 'glass' or 'wine' or 'corked')
{ wd = NextWord(); adj_count++; }
while (wd == 'bottle' or 'flask' or 'flagon')
{ wd = NextWord(); noun_count++; }
if (noun_count > 0) return noun_count + adj_count;
return 0;
],
short_name [;
if (cork in self) print "corked ";
],
description [ liq;
liq = ChildOfClass(self,Liquid);
print "You see an ordinary wine bottle, of green glass,
with a faded label and a ";
if (cork in self) print "cork protruding from the ";
print "slender neck";
if (liq ~= 0) print ". There is a quantity of liquid inside";
".";
],
before [ liq qty liq2;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
Uncork: <<Remove cork self>>;
Cork: <<Insert cork self>>;
Drink: "Please don't drink from the bottle!";
Empty: if (cork in self)
"Fortunately, the cork prevents you making a mess.";
if (qty == 0) print_ret (The) self, " is empty.";
liq.rename("red wine",'red','wine','plonk');
print "You pour ", (the) liq, " onto the floor.^";
move liq to location;
rtrue;
EmptyT: if (cork in self)
print_ret "You tip ", (the) self,
", but nothing happens.";
if (qty == 0) print_ret (The) self, " is empty.";
if (~~(second ofclass Vessel))
"That would just make a mess.";
liq2 = ChildOfClass(second,Liquid);
if (liq2 == 0) { ! no liquid in Vessel
if (qty > second.capacity) qty = second.capacity;
liq2 = Liquid.create();
if (liq2 == 0) "*** Can't create Liquid object! ***";
liq2.rename("red wine",'red','wine','plonk');
print "You pour ", (a) liq, " into ", (the) second, ".^";
move liq2 to second;
}
else { ! already some liquid in Vessel
qty = second.capacity - liq2.add_liquid(0);
if (qty == 0)
print_ret (The) second, " is already full.";
print "You add some more ", (name) liq,
" to ", (the) second, ".^";
}
liq2.add_liquid(qty); liq.add_liquid(-qty);
rtrue;
],
capacity 10 ! Liquid the bottle can contain
has transparent;
Liquid "liquid" bottle
with capacity 4; ! Liquid currently in the bottle
Object label "label" bottle
with name 'faded' 'label' 'lable',
description
"Though somewhat faded and difficult to make out,
the label seems to read ~Chat Eau~.";
Object cork "cork" bottle
with name 'cork' 'stopper',
before [;
Remove, Take, Pull:
if ((self notin bottle) || (second ~= nothing or bottle))
rfalse;
move self to player;
"You pull the cork from the bottle.";
Insert:
if ((self notin player) || (second ~= bottle)) rfalse;
move self to bottle;
"You put the cork in the bottle.";
],
description
"It's a small cork, of the type associated with wine bottles.";
Vessel glass kitchen_table
with name 'chipped' 'glass' 'tumbler',
short_name [ liq qty;
liq = ChildOfClass(self,Liquid);
if (liq ~= 0) qty = liq.add_liquid(0);
if (qty > 0)
print "glass of ", (name) liq;
else
print "empty glass tumbler";
rtrue;
],
description [;
print "The glass tumbler is slightly chipped,
but still usable with care. ";
Self.Vessel::description();
],
capacity 2; ! Liquid the glass can contain
! ---------------------------------------------------------------------------- !
|
Finishing up with the standard Grammar and our small extensions to it:
Include "Grammar"; [ UncorkSub; "You can't uncork that."; ]; [ CorkSub; "You can't cork that."; ]; Verb 'uncork' * noun -> Uncork; Verb 'cork' * noun -> Cork; Verb 'pour' = 'empty'; ! ---------------------------------------------------------------------------- ! |
The techniques that we've talked about here are certainly not the only ways of producing the required behaviour; they're not even necessarily the best ones. As ever, comments are welcome; corrections even more so. I'd hate to be misleading those in most need, so if any of you gurus spot an error, please let me know.