Building a plug-in
Once you have a working interpreter running in GlkTerm, you can very quickly turn it into a working plugin. You will want to use Zoom version 1.1.2 or later to do this, as this version introduced the plug-in manager that makes it very easy to install new plug-ins.
Add a new target to your XCode project which is a Loadable bundle. Make sure that ZeroLink is turned off and set the wrapper extension to be ‘zoomplugin’. Remove the files that XCode generates for the project, and link to the ZoomPlugIns, GlkView, ZoomView and Cocoa frameworks (Cocoa is in /System/Frameworks, the rest are available from inside the Zoom application).
Next, add a copy files build phase with a destination of ‘Executables’ and add your glk interpreter product to it. This is why you need to pick a different name for your interpreter to your plugin: if they have the same name you’ll end up copying the interpreter over the plug-in bundle executable file.
Now, add a new class that derives from the ZoomGlkPlugIn class (defined in
+ (NSString*) pluginVersion
Returns a string indicating the version number of your plugin. You could just read the version number from your bundle’s Info.plist file here.
+ (NSString*) pluginDescription
Returns a string indicating a description of your plugin.
+ (BOOL) canRunPath: (NSString*) path
Returns YES if the file at the specified path looks like one that your plugin can run. Note that the file might not exist if Zoom is trying to work out if it has a plug-in that can handle a file available at the IFDB, so in general this should just look to see if the path extension is one that your interpreter can handle.
+ (BOOL) canLoadSavegames
Returns YES if your plug-in can load both a story file and a save game simultaneously. If this is YES, then Zoom will allow the user to double-click on saved games and have them immediately start up with the appropriate story file. If NO, then Zoom will open the story file but not restore the save game.
- (id) initWithFilename: (NSString*) gameFile
The designated initialiser for a plug-in. This should call the same function in the superclass, and [self setClientPath: ] with the path name of the interpreter to run.
- (ZoomStoryID*) idForStory
Returns a ZoomStoryID object with the IFID for the file represented by this object. In general, you’ll want to construct the ZoomStoryID object with initWithIdString: or initWithData:type:. The former lets you specify any string as your IFID, the latter will produce a MD5 ID.
You can incorporate some of the public-domain portions of babel to generate an IFID. The sample below shows how parts of the adrift.c file can be included to generate a valid ID. Unfortunately, it’s not possible to use the main babel functions as babel is licensed under the Creative Commons license, which is not compatible with Zoom’s licensing.
- (ZoomStory*) defaultMetadata
Returns a ZoomStory object containing the default metadata for the game represented by this object. You can ask Zoom to run the babel executable to get this information, via the ZoomBabel object. See the sample below for how to achieve this.
- (NSImage*) coverImage
Should return an NSImage object representing the image to use as the cover image in the iFiction window. If the game does not provide a cover image, then you should return an image containing the icon for your interpreter.
- (NSImage*) logo
Like coverImage, but this is the image displayed as the story starts up. You should return nil if you don’t want any startup image displayed.
Plist entries
Once you’ve written the class for your plugin, you will want to update the property list for your bundle to specify to Zoom the name of your class, which icon to use, further information about the interpreter, file associations, etc. You should set the following keys:
NSPrincipalClass
A string representing the name of the class you have declared to represent your plugin.
ZoomPlugin
A dictionary representing information about your plugin. The keys for this will be detailed later on.
CFBundleDocumentTypes
A standard document types dictionary (as for applications) describing the associations for the files that your plugin can handle.
UTExportedTypeDeclarations
A standard universal type declarations object describing the associations for the files your plugin can handle.
ZoomPlugin keys
These keys provide a description of your plug in that Zoom uses while installing it and to display information about it in the Plug-ins window. You should provide all of these keys to have Zoom recognise your plug in as being valid:
Author
That’s your name (ie, the person who wrote the plugin)
DisplayName
The ‘display name’ of the plug-in. This should be the name of the IF system that the plug-in implements: for example for SCARE, this is ‘Adrift’ as SCARE runs Adrift games.
InterpreterAuthor
Optional: the name of the person that wrote the interpreter that your plugin uses. If this isn’t present, Zoom will assume that the person who wrote the plug-in is also the person that wrote the interpreter.
InterpreterVersion
The version number of the interpreter that this plug-in implements.
Version
The version number of the plug-in: this is separate from the interpreter version number as it needs to be possible to fix bugs in a plug-in without there being a whole new version of the interpreter to go along with it.
Image
An icon for the plug-in. Typically you’ll put this in the Resources directory of your bundle: in this case, the value will be something like ‘../../Resources/SCARE.icns’.
ZoomVersion
This should contain the integer value ‘112′ at the moment.
Installing your plug-in
Once you’ve got everything put together and your plug-in compiles, you can try it out in Zoom by double-clicking the .zoomplugin file: Zoom will install your plug-in and restart. You should then be able to run files implemented for your interpreter using the Zoom front-end.
Sample plug-in bundle code
This code is the plug-in bundle code for the SCARE plug-in. It demonstrates how to declare a plug-in, and how to properly generate an IFID by using some of the public-domain code from babel.
{[.mainsample /enzymes/chili-cplusplus.php]}