forked from EricEve/adv3lite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
modid.t
643 lines (582 loc) · 26.5 KB
/
modid.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
#charset "us-ascii"
/*
* Copyright (c) 2000, 2006 Michael J. Roberts. All Rights Reserved.
*
* adv3Lite Library - module ID's
*
* This module defines a framework for "module ID's." The module ID
* mechanism allows library modules to identify themselves. The module
* ID framework is modular, in that several libraries can be linked
* together without any prior knowledge of one another, and the module ID
* framework will be able to find all of their ID's.
*/
/* include the library header */
#include "advlite.h"
/* we also require file access */
#include <file.h>
/* ------------------------------------------------------------------------ */
/*
* Module ID. Each library add-in can define one of these, so that the
* "credits" command and the like can automatically show the version of
* each library module included in the finished game, without the game's
* author having to compile a list of the module versions manually.
*
* An easy way to implement a CREDITS command is to define a ModuleID
* object for the game itself, and override the showCredit() method to
* display the text of the game's credits. The module object for the
* game itself should usually have a listingOrder of 1, because the
* author usually will want the game's information to be displayed first
* in any listing that shows each included library module (such as the
* VERSION command's output).
*/
class ModuleID: object
/* my name */
name = ''
/* the "byline" for the module, in plain text and HTML versions */
byline = ''
htmlByline = ''
/* my version number string */
version = ''
/*
* Show my library credit. By default won't show anything.
* Libraries should generally not override this, because we want to
* leave it up to the author to determine how the credits are
* displayed. If a library overrides this, then the author won't be
* able to control the formatting of the library credit, which is
* undesirable.
*/
showCredit() { }
/*
* Show version information. By default, we show our name and
* version number, then start a new line. The main game's module ID
* should generally override this to show an appropriate version
* message for the game, and any library add-ins that want to
* display their version information can override this to do so.
*/
showVersion()
{
showVersionMsg(name, version);
"\n";
}
showVersionMsg(nam, ver)
{
DMsg(show version, '{1} version {2}', nam, ver);
}
/*
* Show the "about this game" information. By default, we show
* nothing here. Typically, only the game's module ID object will
* override this; in the game's module ID object, this method should
* display any desired background information about the game that
* the author wants the player to see on typing the ABOUT command.
*
* The ABOUT command conventionally displays information about the
* game and its author - the kind of thing you'd find in an author's
* notes section in a book - along with any special instructions to
* the player, such as notes on unusual command syntax. Information
* that players will find especially helpful include:
*
* - A list of any unusual command phrasings that the game uses.
* Ideally, you will disclose here every verb that's required to
* complete the game, beyond the basic set common to most games
* (LOOK, INVENTORY, NORTH, SOUTH, TAKE, DROP, PUT IN, etc). By
* disclosing every necessary verb and phrasing, you can be certain
* to avoid "guess the verb" puzzles. (Note that it's possible to
* disclose every *required* verb without disclosing every
* *accepted* verb - some verbs might be so suggestive of a
* particular puzzle solution that you wouldn't want to disclose
* them, but as long as you disclose less suggestive alternatives
* that can be used to solve the same puzzles, you have a valid
* defense against accusations of using "guess the verb" puzzles.)
*
* - A quick overview of the NPC conversation system, if any.
* Conversation systems have been slowly evolving as authors
* experiment with different styles, and at least three or four
* different conventions have emerged. The default that experienced
* players will expect is the traditional ASK/TELL system, so it's
* especially important to mention your system if you're using
* something else.
*
* - An indication of the "cruelty" level of the game. In
* particular, many experienced players find it helpful to know from
* the outset how careful they have to be about saving positions
* throughout play, so it's helpful to point out whether or not it's
* possible for the player character to be killed; whether it's
* possible to get into situations where the game becomes
* "unwinnable"; and if the game can become unwinnable, whether or
* not this will become immediately clear. The kindest games never
* kill the PC and are always winnable, no matter what actions the
* player takes; it's never necessary to save these games except to
* suspend a session for later resumption. The cruelest games kill
* the PC without warning (although if they offer an UNDO command
* from a "death" prompt, then even this doesn't constitute true
* cruelty), and can become unwinnable in ways that aren't readily
* and immediately apparent to the player, which means that the
* player could proceed for quite some time (and thus invest
* substantial effort) after the game is already lost.
*
* - A description of any special status line displays or other
* on-screen information whose meaning might not be immediately
* apparent.
*/
showAbout() { }
/*
* My listing order. When we compile a list of modules, we'll sort
* the modules first by ascending listing order; any modules with
* the same listing order will be sorted alphabetically by name with
* respect to the other modules with the same listing order.
*
* The value 1 is reserved for the game's own ID object. Note that
* the TADS 3 library defines a module ID with listing order 50,
* which is chosen so that the main library credit will appear after
* the game credits but before any extension credits using the
* default order value 100 that we define here. Extensions are
* free, however, to use a number lower than 5 if they wish to
* appear before the main library credit.
*/
listingOrder = 100
/*
* get a list of all of the modules that are part of the game,
* sorted in listing order
*/
getModuleList()
{
local lst;
/* compile a list of all of the modules */
lst = new Vector(10);
forEachInstance(ModuleID, { obj: lst.append(obj) });
lst = lst.toList();
/*
* sort the list by listing order (and alphabetically by name
* where listing orders are the same)
*/
lst = lst.sort(SortAsc, function(a, b) {
/* if the listings order differ, sort by listing order */
if (a.listingOrder != b.listingOrder)
return a.listingOrder - b.listingOrder;
/* the listing orders are the same; sort by name */
if (a.name < b.name)
return -1;
else if (a.name > b.name)
return 1;
else
return 0;
});
/* return the sorted list */
return lst;
}
;
/* ------------------------------------------------------------------------ */
/*
* A module ID with metadata. During pre-initialization, we'll
* automatically write out a file with the metadata for each of these
* objects. This is an abstract base class; a subclass must be created
* for each specific metadata format.
*/
class MetadataModuleID: ModuleID, PreinitObject
/* execute pre-initialization */
execute()
{
/* write out our metadata */
writeMetadataFile();
}
/*
* write our metadata file - this must be overridden by each
* subclass to carry out the specific steps needed to create and
* write the metadata file in the appropriate format for the
* subclass
*/
writeMetadataFile() { }
;
/*
* A module ID with GameInfo metadata. The GameInfo metadata format is
* the standard TADS format for descriptive data about the game. The
* usual way to use GameInfo metadata is to create a file called
* "gameinfo.txt" for a game, then embed this file directly in the
* game's .t3 file using the TADS 3 resource bundler (t3res). Once the
* gameinfo.txt is embedded in the .t3 file, tools will be able to read
* the game's descriptive data directly from the .t3 file. For example,
* HTML TADS on Windows can read the information into its Game Chest,
* which allows the interpreter to show the full name of the game, the
* author, and a blurb describing the game, among other things.
*/
class GameInfoModuleID: MetadataModuleID
/*
* The IFID - this is a UUID uniquely identifying the game, using the
* standard UUID format (xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, where
* each 'x' is a hexadecimal digit). You should pick an IFID when
* you start each game project, and then keep the same IFID
* throughout the game's entire existence, *including* version
* updates. Each new version release of the same game - even major
* new versions - should use the same IFID, so that the versions can
* all be related to one another as the same game.
*
* If the game has multiple IFIDs, list them here, separated by
* commas. You should NOT *intentionally* create multiple IFIDs for
* your game; once you've created an IFID, it should be the unique
* and permanent identifier for the game. In particular, do NOT
* create a new IFID for a new version: the whole series of releases
* throughout a game's lifetime should be identified by a single
* IFID, so that archivists will know that the versions are all
* incarnations of the same work.
*
* The reason that multiple IFIDs are allowed at all is that many
* older games were not assigned explicit UUID-style IFIDs when
* released. In such cases, the game has an "implied" IFID based on
* an MD5 hash of the compiled game file's contents. Every release
* that doesn't contain an explicit IFID will therefore have a
* different implied IFID. So, for example, if you've already
* released versions 1, 2, and 3 of your game, and you didn't assign
* explicit IFID values to those releases, each version will have a
* different implied IFID. When you release version 4, you should
* NOT assign a new UUID-style IFID. Instead, in the IFID string
* here, list ALL THREE of the implied IFIDs from the past releases.
* Each of the three IFIDs counts from now on as an IFID for the
* work, for all versions collectively. (By placing the list of
* IFIDs in version 4, you prevent version 4 from adding yet another
* implied IFID of its own: the explicit IFID list supersedes the
* implied IFID.) See the Babel spec for more information, and for
* instructions on how to calculate the implied IFID for a TADS game
* that was released without a UUID-style IFID.
*/
IFID = ''
/*
* The game's headline. It's become an IF tradition to use a
* quasi-subtitle of the sort that Infocom used, of the form "An
* Interactive Mystery." This can be used to define that subtitle.
*/
headline = ''
/*
* If this game is part of a series, such as a trilogy, these can be
* used to identify the name of the series and the position in the
* series. The series name should be something like "The Enchanter
* Trilogy"; the series number, if provided, should be a simple
* integer string ('1', '2', etc) giving the position in the series.
* Note that the series number isn't required even if a series name
* is specified, since some series are just groups of works without
* any particular ordering.
*/
seriesName = ''
seriesNumber = ''
/*
* The genre of the game. Some games don't fit any particular genre,
* and some authors just don't like the idea of having to pigeonhole
* their games, so feel free to leave it out. If there's a good fit
* to a well-established genre, though, you can specify it here. We
* recommend you keep this short - one word, maybe two - and use a
* genre name that's generally recognized as such. You might want to
* use Baf's Guide as a reference (http://www.wurb.com/if/genre).
*/
genreName = ''
/*
* The forgiveness level, according to the Zarfian scale propounded
* by Andrew Plotkin on rec.arts.int-fiction. This must be one of
* these terms, using the exact capitalization shown: Merciful,
* Polite, Tough, Nasty, Cruel.
*/
forgivenessLevel = ''
/*
* The names and email addresses of the authors, in GameInfo format.
* This list must use the following format:
*
* author one <email>; author two <email> <email>; ...
*
* In other words, list the first author's name, followed by one or
* more email addresses, in angle brackets, for the first author.
* If more than one author is to be listed, add a semicolon,
* followed by the name of the second author, followed by the second
* author's email address or addresses, enclosing each in angle
* brackets. Repeat as needed for additional authors. The list
* does not need to end with a semicolon; semicolons are merely used
* to separate entries.
*/
authorEmail = ''
/*
* The game's web site, if any. If specified, this must be an
* absolute URL with http protocol - that is, it must be of the form
* "http://mydomain.com/...".
*/
gameUrl = ''
/*
* Descriptive text for the game, in plain text format. This is a
* short description that can be used, for example, in a catalog of
* games. This should be a couple of sentences or so.
*/
desc = ''
/*
* Descriptive text for the game, as an HTML fragment. This should
* have the same information as the 'desc', but this version can use
* HTML markups (including tags and character entities) to embellish
* the display of the text. Any HTML markups should be "in-line"
* body elements only, not "block" or head elements, so that this
* text can be inserted into a larger HTML document. For example,
* markups like <i> and <b> are fine, but <p> and <table> should not
* be used.
*/
htmlDesc = ''
/*
* The release date. By default, we compute this statically to be
* today's date. This means this will be set to the date of
* compilation. If the game wishes to override this, note that the
* GameInfo format requires this to be of the form YYYY-MM-DD. For
* example, December 9, 2001 would be '2001-12-09'.
*/
releaseDate = static getGameInfoToday()
/*
* The date of first publication. This can be just a year in YYYY
* format, or a full YYYY-MM-DD date. This is the original release
* date of the original version of the game, which is often of
* interest to archivists. This should *not* be updated when a new
* release is made - it's always the date of *original* publication.
*/
firstPublished = ''
/*
* The language in which this game's text is written. This is the
* RFC3066 language code for the main language of the work. For
* example, games written in US English would use 'en-US', while
* games written in British English would use 'en-GB'. Note that
* each language-specific library module should use 'modify' to set
* this to the default for the library.
*/
languageCode = ''
/*
* The license type for this game. Most text IF games these days
* are released as freeware, so we use this as the default. The
* GameInfo metadata format defines several other standard license
* types, including Public Domain, Shareware, Commercial Demo,
* Commercial, and Other. Authors should change this if they plan
* to release under a licensing model other than freeware.
*
* Note that the GameInfo metadata format documentation explicitly
* states that the license type indicated here is advisory only and
* cannot be considered definitive. This means that this setting
* does not take away any of the author's rights to set specific
* license terms. Even so, we recommend that you pick an
* appropriate value here to avoid any confusion.
*/
licenseType = 'Freeware'
/*
* The copying rules for this game. Most text games these days are
* released as freeware with minimal restrictions on copying, so we
* use a default of "nominal cost only." Other values defined in the
* GameInfo format include Prohibited, No Restrictions, No-Cost Only,
* At-Cost Only, and Other. A modifier indicates whether or not the
* game may be included in compilations (such as those "10,001 great
* games" CD-R's that people like to sell on auction sites); we
* indicate that inclusion in compilations is allowed by default.
* You can change this to "Compilations Prohibited" if you prefer not
* to allow your game to be distributed in that fashion.
*
* Note that the restrictions specified here aren't enforced by any
* sort of copy-protection or DRM (digital rights management)
* technology. This information is entirely for the benefit of
* conscientious users who want to abide by your wishes and thus need
* to know what your wishes are.
*
* The GameInfo bundle is mostly for the benefit of software that can
* extract the information from the compiled game. So, we recommend
* that you also put a full notice and explanation of your license
* restrictions somewhere that users can easily find it, such as in a
* separate LICENSE.TXT file that you distribute with your game, or
* in the text of the game itself (displayed by a LICENSE or
* COPYRIGHT command, for example).
*/
copyingRules = 'Nominal cost only; compilations allowed'
/*
* The recommended "presentation profile" for the game. 'Default'
* means that the interpreter's default profile should be used.
* (Some interpreters let the user select which profile to use as the
* default, in which case 'Default' means we'll use that profile.)
*/
presentationProfile = 'Default'
/* write our metadata file */
writeMetadataFile()
{
local f;
/*
* open the file - note that the GameInfo.txt resource is
* required to be encoded in UTF-8, so open the file with the
* UTF-8 character set
*/
f = File.openTextFile(gameInfoFilename, FileAccessWrite, 'utf-8');
/* scan our list of metadata keys and write each one */
for (local i = 1, local len = metadataKeys.length() ;
i + 1 <= len ; i += 2)
{
local key;
local prop;
local val;
/* get the key name and value property for this entry */
key = metadataKeys[i];
prop = metadataKeys[i+1];
val = self.(prop);
/* turn any '\ ' characters into ' ' characters */
val = val.findReplace('\ ', ' ', ReplaceAll);
/* write out this key if there's a value defined for it */
if (val != nil && val != '')
f.writeFile(key + ': ' + val + '\n');
}
/* done with the file - close it */
f.closeFile();
/* remember the primary IFID in the globals */
libGlobal.IFID = rexReplace([',.*$', '<space>+'], IFID, '');
}
/*
* the GameInfo filename - by default, we write the standard
* gameinfo.txt file
*/
gameInfoFilename = 'GameInfo.txt'
/*
* The metadata key mappings. This is a list of key/property pairs.
* The key in each pair is a string giving a standard GameInfo key
* name, and the property gives the property (of self) that we
* evaluate to get the string value for that key.
*/
metadataKeys =
[
'IFID', &IFID,
'Name', &name,
'Headline', &headline,
'Byline', &byline,
'HtmlByline', &htmlByline,
'AuthorEmail', &authorEmail,
'Url', &gameUrl,
'Desc', &desc,
'HtmlDesc', &htmlDesc,
'Version', &version,
'ReleaseDate', &releaseDate,
'FirstPublished', &firstPublished,
'Series', &seriesName,
'SeriesNumber', &seriesNumber,
'Genre', &genreName,
'Forgiveness', &forgivenessLevel,
'Language', &languageCode,
'LicenseType', &licenseType,
'CopyingRules', ©ingRules,
'PresentationProfile', &presentationProfile
]
/*
* get today's date, using the GameInfo standard date format
* (YYYY-MM-DD)
*/
getGameInfoToday()
{
local dt;
local mm, dd;
/* get the current date */
dt = getTime(GetTimeDateAndTime);
/* get the month, and add a leading zero if it's only one digit */
mm = (dt[2] < 10 ? '0' : '') + dt[2];
/* get the day, and add a leading zero if it's only one digit */
dd = (dt[3] < 10 ? '0' : '') + dt[3];
/* build and return the full YYYY-MM-DD date string */
return toString(dt[1]) + '-' + mm + '-' + dd;
}
;
/* ------------------------------------------------------------------------ */
/*
* Base class for the game's module ID. This merely sets the listing
* order to 1 so that the game's credit is listed first. Normally,
* exactly one GameID object, called 'versionInfo', is defined in a game,
* to provide the game's identifying information.
*
* Note that this class is based on GameInfoModuleID, so the library will
* automatically write out a gameinfo.txt file based on this object's
* settings. For full GameInfo data, the game should minimally define the
* following properties (see GameInfoModuleID and ModuleID for details on
* these properties):
*
*. IFID - a random 32-digit hex number to uniquely identify the game;
*. you can generate one at http://www.tads.org/ifidgen/ifidgen
*. name - the name of the game
*. byline - the main author credit: "by so and so"
*. htmlByline - the main author credit as an HTML fragment
*. authorEmail - the authors' names and email addresses (in GameInfo format)
*. desc - a short blurb describing the game, in plain text format
*. htmlDesc - the descriptive blurb as an HTML ragment
*. version - the game's version string
*
* In addition, you can override the following settings if you don't like
* the defaults inherited from GameInfoModuleID:
*
*. releaseDate - the release date string (YYYY-MM-DD)
*. licenseType - freeware, shareware, etc.
*. copyingRules - summary rules on copying
*. presentationProfile - Multimedia, Plain Text
*/
class GameID: GameInfoModuleID
/* always list the game's credits before any library credits */
listingOrder = 1
/*
* Show the game's credits. By default, we'll just show our name and
* by-line.
*
* Typically, authors will want to override this to display the full
* credits for the game. Most authors like to show the author or
* authors, along with notes of thanks to important contributors.
*
* Note that libraries generally will not show anything automatically
* in the credits, to allow the author full control over the
* formatting of the credits. Authors are encouraged to give credit
* where it's due for any libraries they use.
*/
showCredit()
{
/* by default, just show the game's name and by-line */
gLibMessages.showCredit(name, htmlByline);
}
/*
* show a blank line after the game's version information, to make
* it stand apart from the list of library and VM version numbers
*/
showVersion()
{
inherited();
"\b";
}
;
/* ------------------------------------------------------------------------ */
/*
* The main adv3Lite library ID.
*/
moduleAdv3Lite: ModuleID
name = 'adv3Lite Library'
byline = 'by Eric Eve'
htmlByline = 'by <a href="mailto:[email protected]">'
+ 'Eric Eve</a>'
version = '1.4'
/*
* We use a listing order of 50 so that, if all of the other credits
* use the defaults, we appear after the game's own credits
* (conventionally at listing order 1) and before any extension
* credits (which inherit the default order 100), but so that
* there's room for extensions that want to appear before us, or
* after us but before any default-ordered extensions.
*/
listingOrder = 50
;
/* ------------------------------------------------------------------------ */
/*
* An ID module not for the library but for the T3 VM itself. This
* doesn't display any credit information, but displays version number
* information for the VM so that the "version" command shows what
* version of the interpreter is in use.
*/
ModuleID
showVersion()
{
local vsn = t3GetVMVsn();
/*
* show the version information - note that we must decompose
* the version number into the standard 3-part dotted string
*/
showVersionMsg('T3 VM (' + t3GetVMID() + ')',
'' + (vsn >> 16) + '.'
+ ((vsn >> 8) & 0xFF) + '.'
+ (vsn & 0xFF));
"\n";
}
/*
* Use a very high listing order so that we're the last thing shown.
*/
listingOrder = 10000
;