
Conversion Guide for Platypus release 4+
========================================
Not for the faint-hearted.

    Send questions, comments, and bug reports to platypushome@yahoo.com.

    This document is intended to explain the process of converting an existing
    Inform game into a Platypus-compatible one. Needless to say, it does not
    cover all aspects of Platypus, only those that are relevant to converting 
    existing code.


1. Basics

    a) First, make sure your compiler will be able to find the Platypus files.
       Note that both the standard library and Platypus have files called
       "English.h", which are different. (So don't try to put them in the same
       directory.)

       Then, change your include statements:

         Include "Parser";      ----->      Include "First";
         Include "Verblib";     ----->      Include "Middle";
         Include "Grammar";     ----->      Include "Last";

    b) 

    c) Change any instances of the condition

         if (location == thedark)

       to

         if (InDark(player))

    d) Change all other references to location or real_location to 
       player.location. E.g.:

         if (location == Foyer)

       becomes

         if (player.location == Foyer)

    e) Replace all instances of the scenery attribute with a combination of 
       static and concealed. E.g.:

         has scenery

       becomes

         has static concealed

    f) Replace any uses of @output_buffer 3 xxx; with OpenBuffer(xxx);

       Replace any uses of @output_buffer -3; with CloseBuffer();

    g) If you have a LibraryMessages object, change it to be ofclass 
       MessageCogs (it does not have to be named LibraryMessages), and rename
       its "before" property to "messages".

    h) If any of those messages contain the characters # or &, you must 
       double them. So # would become ## and & would become &&. These
       characters have special uses in library messages (which are filtered
       through PrintX()).

    i) And that's all! Well, except for the 47 more things that follow.

    j) Rename properties as follows:

         Old name                 New name
         --------                 --------
         before                   respond_early
         after                    respond_late
         react_before             meddle_early
         react_after              meddle_late
         life                     respond

    k) However, indirect responses, such as for ##LetGo or ##Receive instead 
       go in an indirect property, switching on the "real" verb (e.g. ##Take
       or ##Insert):

         Old name                 New name
         --------                 --------
         before                   respond_early_indirect
         after                    respond_late_indirect
         life                     respond_indirect

    l) Change any references to direction objects to use "dir" in place of 
       "_obj". That is:

         n_obj    becomes    ndir
         ne_obj   becomes    nedir
         u_obj    becomes    udir
         etc.

    m) Change all direction properties into a single dirs property for each 
       room. For example:

         n_to Lounge, se_to Spodgeville;

       would become

         dirs ndir Lounge   sedir Spodgeville;

       or

         dirs [ d;
             if (d == ndir) return Lounge;
             if (d == sedir) return Spodgeville;
         ];

       See the entry for dirs in the Reference for more details.

    n) Declare all of your rooms to be ofclass Rooms. Change their name 
       properties to contain their actual names. (You can also use the
       adjective property.) If you want to give them names of "scenery", see
       the included "scenery.h" library.

    o) Change all "move x to y" statements into MoveTo(x,y) calls. This will 
       ensure that objects have appropriate position attributes set (inside,
       upon, under). Without them, objects in containers will not be in scope.

       Your "remove" statements do not need to be changed.

    p) Likewise, change PlayerTo(destination, flag) to 
       MoveTo(player,destination,0,flag). (The third parameter is for
       specifying a position attribute. If none is provided, the routine will
       set an appropriate one.)

    q) Add a call to SetDefaultObjectPositions() to your Initialise() routine. 
       This will ensure that objects have appropriate position attributes at
       the start of the program, and save you from editing all their "has"
       lines.

    r) Change any initial, when_on, when_off, when_open, and when_closed 
       properties into describe properties.

    s) If you are using the task-scoring system, create an object for each 
       task with a points property, and change the corresponding call to
       Achieved([task object]). E.g.:

         Object make_fry_key "making the french fry key" with points 5;

         Achieved(make_fry_key);

    t) Similarly, if you are awarding points for entering certain rooms or 
       picking up certain objects, give those rooms and objects points
       properties. (You don't have to call Achieved() for them.) Hint: use a
       class.

    u) The maximum_score global replaces constant MAX_SCORE. It will be 
       calculated automatically by adding all positive points properties, but
       you can override this by setting it manually at startup.

    v) Eliminate the door and lockable attributes. The provision of door_to 
       and with_key indicate that an object is a door and/or is lockable. The
       door_dir property is no longer used either; the library figures this
       out for itself.

    w) Replace the enterable attribute with an allow_entry property. It takes 
       an attribute parameter which indicates the position of entry: inside,
       upon, or under. [Pause while readers fantasize.] The attribute will be
       one appropriate to the object, so if it is not a hider, for instance,
       allow_entry will never be called with under. It returns true to allow
       entry, false to not allow entry. But, for the simplest cases:

         allow_entry [; rtrue; ]

    x) Similarly, allow_push (if provided) is called with a direction object, 
       and returns true to allow the object to be pushed in that direction.
       This takes the place of the old method of handling PushDir.

    y) E-mail me a ranting, all-caps diatribe about how your code still isn't
       working under Platypus on account of the 32 other things that I can't
       think of at the moment.

    z) I just figured I might as well finish off the alphabet.


    And that should take care of the most common cases. Thank you for using
    Platypus, the only alternative Inform library named after an animal that
    has feet like a duck but is furry. As of this writing.

    [Document ends.]
