Send questions, comments, and bug reports to Anson Turner.
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.
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) At the start of your code, insert:
Constant MAX_COMPATIBILITY;
This constant triggers many changes in the library which make it far easier to get standard-library based code working under Platypus. Or at least it used to. As of release 4, it does absolutely nothing. But insert it anyway. Come on, it's fun. You know you want to.
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.]
-- Anson Turner
(formatted by John G. Wood)
This page originally found at http://www.elvwood.org/InteractiveFiction/Platypus/Convert.html
Last updated: 14 March 2002