Become thoroughly conversant with grammar.h. |
Verb 'climb' 'scale' * noun -> Climb * 'up'/'over' noun -> Climb;Verb defines a verb. Climb is the verb and scale is its synonym. Alternate prepositions can be listed together when separated by a forward slash. Noun is the verb's object. Climb (after the ->) is the verb routine that will be executed when the climb command is entered by the player. That's pretty straight forward.
Verb routines are always followed by "Sub" in code, but when part of a grammar declaration, such as in grammar.h, the Sub suffix is left off. Bit strange, but that is how it is. |
Verb 'clamber' = 'climb';Creating Verb Routines
[BurnSub; L__M(##Burn,1,noun); ]; <- The original BurnSub in verblibm.h. Burn: "This dangerous act would achieve little." <- The burn message in english.h.Well, first BurnSub needs to be replaced. It can be replaced by including in your code (before parser.h):
Replace BurnSub;Now that it has been replaced, a new Burnsub routine needs to be provided.
[ BurnSub; if ((match notin player) || (match in player && match hasnt light)) "You have no source of flame."; if (noun has animate) print_ret "I don't suppose ", (the) noun, " would care for that."; if (noun has light) print_ret (The) noun, " is already burning."; if (noun has is_paper) { remove noun; print_ret (The) noun, " catches fire and burns down to nothing."; } "That dangerous act would achieve little."; ];A Doe Crib Note:
Actually including burn in a game is not recommended, because it requires a lot of coding. |
Object bonfire "bonfire" with name "bonfire" "fire", description [; if (self has light) "The bonfire burns merrily away."; "Someone has stacked a bonfire here, ready to be burned."; ], before [; Burn : If (self hasnt light) { if ((match in player) && (match has light)) { give self light; "You touch the match to the bonfire and flames leap up."; } } ];Of course, it would probably also use a timer to burn the bonfire down to ashes.
Object man "man" has animate male with name "man", life [; etc.; ];
Object chair "chair" has supporter enterable with name "chair" "plastic" "ordinary", description "It's an ordinary, plastic chair.", before [; Enter : if (man in chair) "It seems to be occupied."; ];
Object chair "chair" has supporter enterable with name "chair" "plastic" "ordinary", description "It's an ordinary, plastic chair.", before [; Enter : if (man in chair) "It seems to be occupied."; Burn : print "Plastic really smells when it burns. "; ];
[ BurnSub; if ((match notin player) || (match in player && match hasnt light)) "You have no source of flame."; if (noun has animate) print_ret "I don't suppose ", (the) noun, " would care for that."; if (noun has light) print_ret (The) noun, " is already burning."; if (noun has is_paper) { remove noun; print_ret (The) noun, " catches fire and burns down to nothing."; } "That dangerous act would achieve little."; ]; Object bonfire "bonfire" with name "bonfire" "fire", description [; if (self has light) "The bonfire burns merrily away."; "Someone has stacked a bonfire here, ready to be burned."; ], before [; Burn : If (self hasnt light) { if ((match in player) && (match has light)) { give self light; "You touch the match to the bonfire and flames leap up."; } } ];The bonfire is only lit, returning true (1) and skipping BurnSub, if it isn't already burning and the player has a lit match. If it is already burning, its before routine returns 0, which calls BurnSub to print "The bonfire is already burning." If the player doesn't have a match or has a match that isn't lit, its before routine also returns 0, which calls BurnSub to print "You have no source of flame."
Conditions you want specific to an object (in this case, the bonfire already lit and a lit match in player's possession) have to be tested in that object's before routine itself, because the corresponding verbsub will only be executed afterward (if at all). |
Command | Example |
---|---|
Verb
(creates a new verb) |
Verb 'xyzzy' * -> XYZZY; |
=
(creates a synonym) |
Verb 'clamber' = 'climb'; |
Extend
(adds to the definition of an existing verb in grammar.h, new addition is placed last in the list) |
Extend 'climb' * 'up'/'down' noun -> Climb; |
Extend verb last
(adds to the definition of an existing verb, new addition is placed at the end of the list, same as above) |
Extend 'climb' last * 'up'/'down' noun -> Climb; |
Extend verb first
(adds to the definition of an existing verb, new addition is placed at the front of the list) |
Extend 'climb' first * 'up'/'down' noun -> Climb; |
Extend verb replace
(completely replaces the default definition in grammar.h) |
Extend 'climb' replace * 'up'/'down' noun -> Climb; |
Inform does not support multi-dimensional arrays, which is one of its biggest drawbacks and why creating a database in Inform is almost impossible. |
Object hidden_door "hidden door" has door openable static with name "hidden" "door", found_in secret_passage library;Hidden door's found_in property is a two element array: secret_passage is element 0, and library is element 1. The word, array, is not included in a property array, so the only way you can tell that it is an array is by the multiple number of elements. (Yes, name is also a property array, but a special one.)
Trying to access non-existent array elements, going outside array bounds, is
probably the second biggest cause of vile zero errors from hell (see
Attributes, #4.)
Array test_array ->10; (declaration) test_array->10 = 1; (out of bounds, remember it would be 0-9) |
Object nowhere; found_in secret_passage nowhere;Now the door will only appear in the secret_passage and not in the library until the right conditions are met.
Object hidden_door "hidden door" has door openable static with name "hidden" "door", when_open [; if (location==secret_passage) "The hidden door opens west."; "The bookcase is open, revealing a secret passage east."; ], when_closed "The hidden door is closed.", door_dir [; if (location==secret_passage) return w_to; return e_to; ], door_to [; if (location==secret_passage) return library; return secret_passage; ], before [; Close : if (location == library) "It doesn't move, you'll have to close it some other way."; ], found_in secret_passage nowhere; Object nowhere; Object secret_passage "Passage" has light with description "It is hard to see in here.", w_to hidden_door, cant_go "You can't see where the passage leads to."; Object library "Library" has light with description "You are in a big library with a bookcase crammed full of books.", e_to [; if (self hasnt general) "You can't go that way."; return hidden_door; ]; Object -> shelves "bookcase" has scenery with name "shelves" "bookcase" "bookshelves" "case", article "some", description "There are a lot of books, but one big red book is especially noticeable."; Object -> big_book "big book" has scenery with name "book" "big" "red", description "The red book is unusually big. It appears as if the title was painted on.", before [; Take : "It moves a little, but otherwise seems attached to the bookcase."; Push, Turn : "It doesn't budge."; Pull : print "You pull the book. "; if (library has general) { (hidden_door.&found_in)-->1 = nowhere; give hidden_door ~open; give library ~general; MoveFloatingObjects(); "^^~Whoosh!~ The bookcase swings closed."; } (hidden_door.&found_in)-->1 = library; give hidden_door open; give library general; MoveFloatingObjects(); "^^~Whoosh!~ The bookcase swings open revealing a secret passage to the east."; ];MoveFloatingObjects is a built-in Inform library routine that is automatically called at the beginning of each turn to adjust objects that can be found_in more than one location. But if you change found_in directly, MoveFloatingObjects needs to be called immediately to make the necessary adjustments. It is the routine that will actually move a found_in to the right locations, in this case, the hidden door to/from the library.
Option Hint1 "How do I get the kitten out of the tree?" class Hintobj with the_hints "Try chopping down the tree." "Too destructive? Try a garden hose." "No hose? Read raif for other ways to get the kitten down.";the_hints is a string array. Notice, as with found_in, there is no comma between the elements.
class Hintobj with hints_seen 0, hint_done 0, the_hints "Put list of hints here (in the object of this class).", description [; self.showhints(); rtrue; ], showhints [ max i k; max = (self.#the_hints / 2); for (i = 1: (i <= max): i++) { if ((i==1) && ((max > 1) && (self.hints_seen < max))) print "There are ", (LanguageNumber) max, " increasingly clear \ hints. Press H for another hint, any other key to quit.^^^"; print "(", i, "/", max, ") "; print (string) (self.&the_hints-->(i-1)); new_line; new_line; ! How many times through this loop? That is the number of the current ! hint. Starting with 1 = 0 hints_seen. if (self.hints_seen == (i-1)) self.hints_seen = self.hints_seen + 1; ! Only call read_char if currently on the last hint seen and ! skip on the very last hint. if ((i < max) && (i == self.hints_seen)) { @read_char 1 0 0 k; if (k ~= 'H' or 'h') return; } } ];max uses the # operator (divided by two, that confusing byte/word thing again) to find the number of elements in each hint object's the_hints array. self.&the_hints--> uses (i-1) because the for loop starts at 1 instead of 0 (since I find it easier to think of 1-10 than 0-9, as many do). Each time a new hint is read, the hints_seen property is incremented by 1, so that the next time previously seen hints will automatically show on the screen. (Note that regular Inform uses two-byte words, and Glulx Inform uses four-byte words, so in regular Inform you divide by two and in Glulx Inform you divide by four.)
Command | Examples |
---|---|
Array
(declares an array) |
Array test_array-->5; Array test_array-->1 2 3 4 5; Array test_array string 5; Array test_array->"Name"; Array test_array->'N' 'a' 'm' 'e'; Array test_array table 5; Array test_array table 'name1' 'name2' 'name3' 'name4' 'name5'; Array test_array table [; "Name One"; "Name Two"; "Name Three"; "Name Four"; "Name Five"; ]; |
array types:
-> (byte) --> (word) string (array of characters, bytes) table (array of strings, words) |
see above |
Command | Example |
---|---|
#
(returns the length of an array stored in an object's property) |
len = (obj.#property_array) / 2; |
&
(accesses an array element stored in an object's property) |
if (obj.&property_array-->0 == 1); |