======================== Some last lousy points ======================== .. highlight:: inform .. default-role:: samp .. only:: html .. image:: /images/picF.png :align: left .. raw:: latex \dropcap{f} inally our three example games are written; we've shown you as much of the Inform language as we've needed to, and made a lot of observations about how and why something should be done. Despite all that, there's much that we've left unsaid, or touched on only lightly. In this chapter we'll revisit key topics and review some of the more significant omissions, to give you a better feel for what's important, and what can be ignored for the time being; when you become an accomplished designer, you will decide what matters and what can be left on the shelf. We'll also talk, in :ref:`reading-other-code`, about a few ways of doing things that we've chosen not to tell you about, but which you're quite likely to encounter if you look at Inform code written by other designers. The tone here is perhaps a little dry, but trust us: in walking this dusty ground we touch on just about everything that is fundamental in your overall understanding of Inform. And as always, the |DM4| provides rounder and more comprehensive coverage. Expressions =========== In this guide we’ve used the placeholder `{expression}` a few times; here's roughly what we mean. * An `{expression}` is a single `{value}`, or several `{values}` combined using `{operators}` and sometimes parentheses ``(...)``. * Possible `{values}` include: * a literal number (-32768 to 32767) * something that's represented as a number (a character ``'a'`` , a dictionary word ``'aardvark'`` , a string ``"aardvark's adventure"`` or an action ``##Look`` ) * the internal identifier of a constant, an object, a class or a routine * (only in a run-time statement, not in a compile-time directive) the contents of a variable, or the return value from a routine. * Possible `{operators}` include: * an arithmetic operator: ``+ - * / % ++`` * a bitwise logical operator: ``& | ~`` * a numeric comparison operator: ``== ~= > < >= <=`` * an object conditional operator: ``ofclass in notin provides has hasnt`` * a boolean combinational operator: ``&& || ~~`` Internal IDs ============ Many of the items which you define in your source file -- objects, variables, routines, etc. -- need to be given a name so that other items can refer to them. We call this name an item's internal identifier (because it's used only within the source file and isn't visible to the player), and we use the placeholders `{obj_id}`, `{var_id}`, `{routine_id}`, etc. to represent where it's used. An internal ID * can be up to thirty-two characters long * must start with a letter or underscore, and then continue with letters ``A-Z`` , underscore ``_`` and digits ``0-9`` (where upper-case and lower-case letters are treated as indistinguishable) * should generally be unique across all files: your source file, the standard library files, and any library contributions which you've used (except that a routine's local variables are not visible outside that routine). .. _statements: Statements ========== .. todo:: We might need some custom syntax highlighting here. A :term:`statement` is an instruction intended for the interpreter, telling it what to do at run-time. It *must* be given in lower-case, and always ends with a semicolon. Some statements, like ``if``, control one or more other statements. We use the placeholder `{statement_block}` to represent either a single `{statement}`, or any number of `{statements}` enclosed in braces:: statement; { statement; statement; ... statement; } Statements that we've met ------------------------- Our games have used these statements, about half of the Inform possibilities:: give obj_id attribute; give obj_id attribute attribute ... attribute; if (expression) statement_block if (expression) statement_block else statement_block move obj_id to parent_obj_id; objectloop (var_id) statement_block print value; print value, value, ... value; print_ret value; print_ret value, value, ... value; remove obj_id; return false; return true; style underline; print...; style roman; switch (expression) { value: statement; statement; ... statement; ... default: statement; statement; ... statement; } "string"; "string", value, ... value; ; ; ; <>; <>; <>; Statements that we've not met ----------------------------- Although our example games haven't needed to use them, these looping statements are sometimes useful:: break; continue; do statement_block until (expression) for (set_var : loop_while_expression : update_var) statement_block while (expression) statement_block On the other hand, we suggest that you put the following statements on hold for now; they're not immediately relevant to everyday code and have mostly to do with printing and formatting:: box font jump new_line spaces string In particular, avoid using the deprecated jump statement if you possibly can. Print rules ----------- In ``print`` and ``print_ret`` statements, each `{value}` can be: * a numeric `{expression}`, displayed as a signed decimal number, * a `"{string}"`, displayed literally, or * a print rule. You can create your own, or use a standard one, including: .. tabularcolumns:: ll +-------------------------+---------------------------------------------------+ | `(a) {obj_id}` | the object's name, preceded by "a", "an" or "some"| +-------------------------+---------------------------------------------------+ | `(A) {obj_id}` | as ``(a)`` but using "A", "An" or "Some" | +-------------------------+---------------------------------------------------+ | `(the) {obj_id}` | the object's name, preceded by "the" | +-------------------------+---------------------------------------------------+ | `(The) {obj_id}` | as ``(the)`` but using "The" | +-------------------------+---------------------------------------------------+ | `(number) {expression}` | the numeric expression's value in words | +-------------------------+---------------------------------------------------+ Directives ========== A :term:`directive` is an instruction intended for the compiler, telling it what to do at compile-time, while the source file is being translated into Z-code. By convention it's given an initial capital letter (though the compiler doesn't enforce this) and always ends with a semicolon. Directives that we've met ------------------------- We've used all of these directives; note that for ``Class``, ``Extend``, ``Object`` and ``Verb`` the full supported syntax is more sophisticated than the basic form presented here:: Class class_id with property value, property value, ... property value, has attribute attribute ... attribute; Constant const_id: Constant const_id = expression; Constant const_id expression; Extend 'verb' * token token ... token -> action * token token ... token -> action ... * token token ... token -> action Include "filename"; Object obj_id "external_name" parent_obj_id with property value, property value, ... property value, has attribute attribute ... attribute; Release expression; Replace routine_id; Serial "yymmdd"; Verb 'verb' * token token ... token -> action * token token ... token -> action ... * token token ... token -> action; ! comment text which the compiler ignores [ routine_id; statement; statement; ... statement; ]; #Ifdef any_id; ... #Endif; Directives that we've not met ----------------------------- There's only a handful of useful directives which we haven't needed to use:: Attribute attribute; Global var_id; Global var_id = expression; Property property; Statusline score; Statusline time; but there's a whole load which are of fairly low importance for now:: Abbreviate Array Default End Ifndef Ifnot Iftrue Iffalse Import Link Lowstring Message Switches System_file Zcharacter .. _objects: Objects ======= An object is really just a collection of variables which together represent the capabilities and current status of some specific component of the model world. Full variables are called properties; simpler two-state variables are attributes. Properties ---------- The library defines around forty-eight standard property variables (such as ``before`` or ``name``), but you can readily create further ones just by using them within an object definition. You can create and initialise a property in an object's ``with`` segment: property, ! set to zero / false property value, ! set to a single value property value value ... value, ! set to a list of values In each case, the `{value}` is either a compile-time `{expression}`, or an embedded routine:: property expression, property [; statement; statement; ... statement; ], You can refer to the value of a property:: self.property ! only within that same object obj_id.property ! everywhere and you can test whether an object definition includes a given property:: (obj_id provides property) ! is true or false .. _routines: Routines ======== Inform provides standalone routines and embedded routines. Standalone routines ------------------- Standalone routines are defined like this:: [ routine_id; statement; statement; ... statement; ]; and called like this:: routine_id() Embedded routines ----------------- These are embedded as the value of an object's property:: property [; statement; statement; ... statement; ], and are usually called automatically by the library, or manually by:: self.property() ! only within that same object obj_id.property() ! everywhere Arguments and local variables ----------------------------- Both types of routine support up to fifteen local variables -- variables which can be used only by the statements within the routine, and which are automatically initialised to zero every time that the routine is called:: [ routine_id var_id var_id ... var_id; statement; statement; ... statement; ]; property [ var_id var_id ... var_id; statement; statement; ... statement; ], You can pass up to seven arguments to a routine, by listing those arguments within the parentheses when you call the routine. The effect is simply to initialise the matching local variables to the argument values rather than to zero:: routine_id(expression, expression, ... expression) Although it works, this technique is rarely used with embedded routines, because there is no mechanism for the library to supply argument values when calling the routine. Return values ------------- Every routine returns a single value, which is supplied either explicitly by some form of return statement:: [ routine_id; statement; statement; ... return expr; ]; ! returns expr property [; statement; statement; ... return expr; ], ! returns expr or implicitly when the routine runs out of statements. If none of these ``statements`` is one -- ``return``, ``print_ret``, ``"..."`` or ``<<...>>`` -- that causes an explicit return, then:: [ routine_id; statement; statement; ... statement; ]; returns ``true`` and :: property [; statement; statement; ... statement; ] return ``false``. This difference is *important*. Remember it by the letter pairs STEF: left to themselves, Standalone routines return True, Embedded routines return False. Here's an example standalone routine which returns the larger of its two argument values:: [ Max a b; if (a > b) return a; else return b; ]; and here are some examples of its use (note that the first example, though legal, does nothing useful whatsoever):: Max(x,y); x = Max(2,3); if (Max(x,7) == 7) ... switch (Max(3,y)) { ... Library routines versus entry points ------------------------------------ A library routine is a standard routine, included within the library files, which you can optionally call from your source file if you require the functionality which the routine provides. We've mentioned these library routines:: IndirectlyContains(parent_obj_id, obj_id) PlaceInScope(obj_id) PlayerTo(obj_id, flag) StartDaemon(obj_id) StopDaemon(obj_id) By contrast, an entry point routine is a routine which you can provide in your source file, in which case the library calls it at an appropriate time. We've mentioned these optional entry point routines:: DeathMessage() InScope(actor_obj_id) And this, the only mandatory one:: Initialise() There are full lists in :ref:`library-routines` and :ref:`entry-points`. .. _reading-other-code: Reading other people's code =========================== Right at the start of this guide, we warned you that we weren't setting out to be comprehensive; we've concentrated on presenting the most important aspects of Inform, as clearly as we can. However, when you read the *Inform Designer's* Manual, and more especially when you look at complete games or library extensions which other designers have produced, you'll come across other ways of doing things -- and it might be that you, like other authors, prefer them over our methods. Just try to find a style that suits you and, this is the important bit, be *consistent* about its use. In this section, we highlight some of the more obvious differences which you may encounter. Code layout ----------- Every designer has his or her own style for laying out their source code, and they're all worse than the one you adopt. Inform's flexibility makes it easy for designers to choose a style that suits them; unfortunately, for some designers this choice seems influenced by the Jackson Pollock school of art. We've advised you to be consistent, to use plenty of white space and indentation, to choose sensible names, to add comments at difficult sections, to actively *think*, as you write your code, about making it as readable as you can. This is doubly true if you ever contemplate sharing a library extension with the rest of the community. This example, with the name changed, is from a file in the Archive:: [xxxx i j; if (j==0) rtrue; if (i in player) rtrue; if (i has static || (i has scenery)) rtrue; action=##linktake; if (runroutines(j,before) ~= 0 || (j has static || (j has scenery))) { print "You'll have to disconnect ",(the) i," from ",(the) j," first.^"; rtrue; } else { if (runroutines(i,before)~=0 || (i has static || (i has scenery))) { print "You'll have to disconnect ",(the) i," from ",(the) j," first.^"; rtrue; } else if (j hasnt concealed && j hasnt static) move j to player; if (i hasnt static && i hasnt concealed) move i to player; action=##linktake; if (runroutines(j,after) ~= 0) rtrue; print "You take ",(the) i," and ",(the) j," connected to it.^"; rtrue; } ]; Here's the same routine after a few minutes spent purely on making it more comprehensible; we haven't actually tested that it (still) works, though that second ``else`` looks suspicious:: [ xxxx i j; if (i in player || i has static or scenery || j == nothing) return true; action = ##LinkTake; if (RunRoutines(j,before) || j has static or scenery) "You'll have to disconnect ", (the) i, " from ", (the) j, " first."; else { if (RunRoutines(i,before) || i has static or scenery) "You'll have to disconnect ", (the) i, " from ", (the) j, " first."; else if (j hasnt static or concealed) move j to player; if (i hasnt static or concealed) move i to player; if (RunRoutines(j,after)) return true; "You take ", (the) i, " and ", (the) j, " connected to it."; } ]; We hope you'll agree that the result was worth the tiny extra effort. Code gets written once; it gets read dozens and dozens of times. Shortcuts --------- There are a few statement shortcuts, some more useful than others, which you'll come across. * These five lines all do the same thing:: return true; return 1; return; rtrue; ]; ! at the end of a standalone routine * These four lines all do the same thing:: return false; return 0; rfalse; ]; ! at the end of an embedded routine * These four lines all do the same thing:: print "string"; new_line; return true; print "string^"; return true; print_ret "string"; "string"; * These lines are the same:: print value1; print value2; print value3; print value1, value2, value3; * These lines are the same:: ; return true; <>; * These lines are also the same:: print "^"; new_line; * These ``if`` statements are equivalent:: if (MyVar == 1 || MyVar == 3 || MyVar == 7) ... if (MyVar == 1 or 3 or 7) ... * These ``if`` statements are equivalent as well:: if (MyVar ~= 1 && MyVar ~= 3 && MyVar ~= 7) ... if (MyVar ~= 1 or 3 or 7) ... * In an ``if`` statement, the thing in parentheses can be *any* expression; all that matters is its value: zero (false) or anything else (true). For example, these statements are equivalent:: if (MyVar ~= false) ... if (~~(MyVar == false)) ... if (MyVar ~= 0) ... if (~~(MyVar == 0)) ... if (MyVar) ... Note that the following statement specifically tests whether ``MyVar`` contains ``true`` (1), *not* whether its value is anything other than zero. :: if (MyVar == true) ... * If ``MyVar`` is a variable, the statements ``MyVar++;`` and ``++MyVar;`` work the same as ``MyVar = MyVar + 1;`` For example, these lines are equivalent:: MyVar = MyVar + 1; if (MyVar == 3) ... if (++MyVar == 3) ... if (MyVar++ == 2) ... What's the same about ``MyVar++`` and ``++MyVar`` is that they both add one to ``MyVar``. What's different about them is the value to which the construct itself evaluates: ``MyVar++`` returns the current value of ``MyVar`` and then performs the increment, whereas ``++MyVar`` does the "+1" first and then returns the incremented value. In the example, if ``MyVar`` currently contains 2 then ``++MyVar`` returns 3 and ``MyVar++`` returns 2, even though in both cases the value of ``MyVar`` afterwards is 3. As another example, this code (from Helga in "William Tell"):: Talk: self.times_spoken_to = self.times_spoken_to + 1; switch (self.times_spoken_to) { 1: score = score + 1; print_ret "You warmly thank Helga for the apple."; 2: print_ret "~See you again soon.~"; default: return false; } ], could have been written more succinctly like this:: Talk: switch (++self.times_spoken_to) { 1: score++; print_ret "You warmly thank Helga for the apple."; 2: print_ret "~See you again soon.~"; default: return false; } ], * Similarly, the statements ``MyVar--;`` and ``--MyVar;`` work the same as ``MyVar = MyVar - 1;`` Again, these lines are equivalent:: MyVar = MyVar - 1; if (MyVar == 7) ... if (--MyVar == 7) ... if (MyVar-- == 8) ... "number" property and "general" attribute ----------------------------------------- The library defines a standard ``number`` property and a standard ``general`` attribute, whose roles are undefined: they are general-purpose variables available within every object to designers as and when they desire. We recommend that you avoid using these two variables, primarily because their names are, by their very nature, so bland as to be largely meaningless. Your game will be clearer and easier to debug if you instead create new property variables -- with appropriate names -- as part of your ``Object`` and ``Class`` definitions. .. _common-props: Common properties and attributes -------------------------------- As an alternative to creating new individual properties which apply only to a single object (or class of objects), it's possible to devise properties and new attributes which, like those defined by the library, are available on *all* objects. The need to do this is actually quite rare, and is mostly confined to library extensions (for example, the ``pname.h`` extension which we encountered in :doc:`12` gives every object a ``pname`` property and a ``phrase_matched`` attribute). To create them, you would use these directives near the start of your source file:: Attribute attribute; Property property; We recommend that you avoid using these two directives unless you really do need to affect every object -- or at least the majority of them -- in your game. There is a limit of forty-eight attributes (of which the library currently defines around thirty) and sixty-two of these common properties (of which the library currently defines around forty-eight). On the other hand, the number of individual properties which you can add is virtually unlimited. .. _setting-up-tree: Setting up the object tree -------------------------- Throughout this guide, we've defined the initial position of each object within the overall object tree either by explicitly mentioning its parent's ``obj_id`` (if any) in the first line of the object definition -- what we've been calling the header information -- or, for a few objects which crop up in more than one place, by using their ``found_in`` properties. For example, in "William Tell" we defined twenty-seven objects; omitting those which used ``found_in`` to define their placement at the start of the game, we're left with object definitions starting like this:: Room street "A street in Altdorf" Room below_square "Further along the street" Furniture stall "fruit and vegetable stall" below_square Prop "potatoes" below_square Prop "fruit and vegetables" below_square NPC stallholder "Helga" below_square Room south_square "South side of the square" Room mid_square "Middle of the square" Furniture pole "hat on a pole" mid_square Room north_square "North side of the square" Room marketplace "Marketplace near the square" Object tree "lime tree" marketplace NPC governor "governor" marketplace Object bow "bow" Object quiver "quiver" Arrow "arrow" quiver Arrow "arrow" quiver Arrow "arrow" quiver Object apple "apple" You'll see that several of the objects begin the game as parents: ``below_square``, ``mid_square``, ``marketplace`` and ``quiver`` all have child objects beneath them; those children mention their parent as the last item of header information. There's an alternative object syntax which is available to achieve the same object tree, using "arrows". That is, we could have defined those parent-and-child objects as:: Room below_square "Further along the street" Furniture -> stall "fruit and vegetable stall" Prop -> "potatoes" Prop -> "fruit and vegetables" NPC -> stallholder "Helga" Room mid_square "Middle of the square" Furniture -> pole "hat on a pole" Room marketplace "Marketplace near the square" Object -> tree "lime tree" NPC -> governor "governor" Object quiver "quiver" Arrow -> "arrow" Arrow -> "arrow" Arrow -> "arrow" The idea is that an object's header information *either* starts with an arrow, or ends with an ``obj_id``, or has neither (having both isn’t permitted). An object with neither has no parent: in this example, that's all the ``Rooms``, and also the ``bow`` and the ``quiver`` (which are moved to the player ``object`` in the ``Initialise`` routine) and the apple (which remains without a parent until Helga gives it to William). An object which starts with a single arrow ``->`` is defined to be a child of the nearest previous object without a parent. Thus, for example, the ``tree`` and ``governor`` objects are both children of the ``marketplace``. To define a child of a child, you'd use two arrows ``-> ->``, and so on. In "William Tell", that situation doesn't occur; to illustrate how it works, imagine that at the start of the game the potatoes and the other fruit and vegetables where actually *on* the stall. Then we might have used:: Room below_square "Further along the street" Furniture -> stall "fruit and vegetable stall" Prop -> -> "potatoes" Prop -> -> "fruit and vegetables" NPC -> stallholder "Helga" ... That is, the objects with one arrow (the ``stall`` and ``stallholder``) are children of the nearest object without a parent (the ``Room``), and the objects with two arrows (the produce) are children of the nearest object defined with a single arrow (the ``stall``). The advantages of using arrows include: * You're forced to define your objects in a "sensible" order. * Fewer ``obj_ids`` may need to be used (though in this game it would make no difference). The disadvantages include: * The fact that objects are related by the physical juxtaposition of their definitions is not necessarily intuitive to all designers. * Especially in a crowded room, it’s harder to be certain exactly how the various parent–child relationships are initialised, other than by carefully counting lots of arrows. * If you relocate the parent within the initial object hierarchy to a higher or lower level, you'll need also to change its children by adding or removing arrows; this isn't necessary when the parent is named in the child headers. We prefer to explicitly name the parent, but you'll encounter both forms very regularly. Quotes in "name" properties --------------------------- We went to some lengths, way back in :ref:`things-in-quotes`, to explain the difference between double quotes ``"..."`` (strings to be output) and single quotes ``'...'`` (input tokens -- dictionary words). Perhaps somewhat unfortunately, Inform allows you to blur this clean distinction: you can use double quotes in name properties and Verb directives:: NPC stallholder "Helga" below_square with name "stallholder" "greengrocer" "monger" "shopkeeper" "merchant" "owner" "Helga" "dress" "scarf" "headscarf", ... Verb "talk" "t//" "converse" "chat" "gossip" * "to"/"with" creature -> Talk * creature -> Talk; *Please* don't do this. You'll just confuse yourself: those are dictionary words, not strings; it's just as easy -- and far clearer -- to stick rigidly to the preferred punctuation. Obsolete usages --------------- Finally, remember that Inform has been evolving since 1993. Over that time, Graham has taken considerable care to maintain as much compatibility as possible, so that games written years ago, for earlier versions of the compiler and the library, will still compile today. While generally a good thing, this brings the disadvantage that a certain amount of obsolete baggage is still lying around. You may, for example, see games using ``Nearby`` directives (denotes parentage, roughly the same as ``->``) and ``near`` conditions (roughly, having the same parent), or with ``" \ "`` controlling line breaks in long ``print`` statements. Try to understand them; try *not* to use them.