DESTROY(BIRD);
spk = BIRD_DEAD;
} else if (obj == VEND) {
- pspeak(VEND, game.prop[VEND] + 2);
- game.prop[VEND] = 3 - game.prop[VEND];
+ bool blocking = (game.prop[VEND] == VEND_BLOCKS);
+ game.prop[VEND] = blocking ? VEND_UNBLOCKS : VEND_BLOCKS;
+ rspeak(blocking ? MACHINE_SWINGOUT : MACHINE_SWINGBACK);
return GO_CLEAROBJ;
}
GETIN(input, &command->wd1, &command->wd1x, &command->wd2, &command->wd2x);
if (command->wd1 != MAKEWD(WORD_YINIT) && command->wd1 != MAKEWD(WORD_YES))
return GO_CHECKFOO;
- pspeak(DRAGON, 3);
+ pspeak(DRAGON, look, 3);
game.prop[DRAGON] = 1;
game.prop[RUG] = 0;
int k = (PLAC[DRAGON] + FIXD[DRAGON]) / 2;
if (HERE(EGGS))k = 1;
if (game.loc == PLAC[EGGS])k = 0;
MOVE(EGGS, PLAC[EGGS]);
- pspeak(EGGS, k);
+ pspeak(EGGS, look, k);
return GO_CLEAROBJ;
}
}
} else if (obj == COINS && HERE(VEND)) {
DESTROY(COINS);
DROP(BATTERY, game.loc);
- pspeak(BATTERY, FRESH_BATTERIES);
+ pspeak(BATTERY, look, FRESH_BATTERIES);
return GO_CLEAROBJ;
} else if (obj == BIRD && AT(DRAGON) && game.prop[DRAGON] == 0) {
rspeak(BIRD_BURNT);
} else {
game.prop[VASE] = 2;
if (AT(PILLOW))game.prop[VASE] = 0;
- pspeak(VASE, game.prop[VASE] + 1);
+ pspeak(VASE, look, game.prop[VASE] + 1);
if (game.prop[VASE] != 0)game.fixed[VASE] = -1;
}
}
if (spk == NO_CARRY)
rspeak(NOW_HOLDING);
game.blklin = false;
- pspeak(i, -1);
+ pspeak(i, touch, -1);
game.blklin = true;
spk = NO_MESSAGE;
}
spk = NO_MESSAGE;
}
for (int i = 1; i <= NOBJECTS; i++) {
- if (!HERE(i) || OBJSND[i] == 0 || game.prop[i] < 0)
+ if (!HERE(i) || object_descriptions[i].sounds[0] == NULL || game.prop[i] < 0)
continue;
- int mi = OBJSND[i] + game.prop[i];
+ int mi = game.prop[i];
if (i == BIRD)
mi += 3 * game.blooded;
- pspeak(i, mi, game.zzword);
+ pspeak(i, hear, mi, game.zzword);
spk = NO_MESSAGE;
- if (i == BIRD && OBJSND[i] + game.prop[i] == 8)
+ /* FIXME: Magic number, sensitive to bird state logic */
+ if (i == BIRD && game.prop[i] == 5)
DESTROY(BIRD);
}
rspeak(spk);
rspeak(spk);
return GO_CLEAROBJ;
}
- pspeak(PLANT, game.prop[PLANT] + 3);
+ pspeak(PLANT, look, game.prop[PLANT] + 3);
game.prop[PLANT] = MOD(game.prop[PLANT] + 1, 3);
game.prop[PLANT2] = game.prop[PLANT];
return GO_MOVE;
} else if (OBJTXT[command.obj] == 0 || game.prop[command.obj] < 0) {
rspeak(ACTSPK[command.verb]);
} else
- pspeak(command.obj, OBJTXT[command.obj] + game.prop[command.obj]);
+ pspeak(command.obj, study, game.prop[command.obj]);
return GO_CLEAROBJ;
}
rspeak(NOTHING_HAPPENS);
return GO_CLEAROBJ;
} else {
- pspeak(RESER, game.prop[RESER] + 1);
+ pspeak(RESER, look, game.prop[RESER] + 1);
game.prop[RESER] = 1 - game.prop[RESER];
if (AT(RESER))
return GO_CLEAROBJ;
}
if (HERE(BIRD))rspeak(spk);
game.prop[FISSURE] = 1 - game.prop[FISSURE];
- pspeak(FISSURE, 2 - game.prop[FISSURE]);
+ pspeak(FISSURE, look, 2 - game.prop[FISSURE]);
return GO_CLEAROBJ;
}
}
extern FILE *logfp;
extern bool oldstyle, editline, prompt;
+enum speaktype {touch, look, hear, study};
+
/* b is not needed for POSIX but harmless */
#define READ_MODE "rb"
#define WRITE_MODE "wb"
extern bool wordempty(token_t);
extern void wordclear(token_t *);
extern void speak(const char*, ...);
-extern void pspeak(vocab_t, int, ...);
+extern void pspeak(vocab_t, enum speaktype, int, ...);
extern void rspeak(vocab_t, ...);
extern bool GETIN(FILE *, token_t*, token_t*, token_t*, token_t*);
extern void echo_input(FILE*, char*, char*);
- BREAK_VASE: 'You have taken the vase and hurled it delicately to the ground.'
- PROD_DWARF: 'You prod the nearest dwarf, who wakes up grumpily, takes one look at\nyou, curses, and grabs for his axe.'
- THIS_ACCEPTABLE: 'Is this acceptable?'
+# This message is not currently used
- ALREADY_OVER: 'This adventure is already over. To start a new adventure, or to\nresume an earlier adventure, please run a fresh copy of the program.'
- OGRE_FULL: 'The ogre doesn''t appear to be hungry.'
- OGRE_DODGE: 'The ogre, who despite his bulk is quite agile, easily dodges your\nattack. He seems almost amused by your puny effort.'
- TABLE_SPACE: 'Table space used:\n%d of %d words of messages %d of %d travel options\n%d of %d vocabulary words %d of %d locations\n%d of %d objects %d of %d action verbs\n%d of %d "random" messages %d of %d "class" messages\n%d of %d hints %d of %d turn threshholds'
- RESUME_ABANDON: 'To resume an earlier Adventure, you must abandon the current one.'
- VERSION_SKEW: 'I''m sorry, but that Adventure was begun using Version%d.%d of the\nprogram, and this is Version%d.%d. You must find the other version\nin order to resume that Adventure.'
-- DAVE_TAMPERING: 'A dark fog creeps in to surround you. From somewhere in the fog you\nhear a stern voice. "This Adventure has been tampered with! You have\nbeen dabbling in magic, knowing not the havoc you might cause thereby.\nLeave at once, before you do irrevocable harm!" The fog thickens,\nuntil at last you can see nothing at all. Your vision then clears,\nand you find yourself back in The Real World.'
+# This message is not currently used
+- SAVE_TAMPERING: 'A dark fog creeps in to surround you. From somewhere in the fog you\nhear a stern voice. "This Adventure has been tampered with! You have\nbeen dabbling in magic, knowing not the havoc you might cause thereby.\nLeave at once, before you do irrevocable harm!" The fog thickens,\nuntil at last you can see nothing at all. Your vision then clears,\nand you find yourself back in The Real World.'
- GUESS_AGAIN: 'Guess again.'
- MISSING_ONE: 'You''re missing only one other treasure. Do you need help finding it?'
- NO_LOCATE: 'Once you''ve found all the other treasures, it is no longer possible to\nlocate the one you''re now missing.'
- ADVENTURE_NEWS: 'Open Adventure is an author-approved open-source release of\nVersion 2.5 with, as yet, no gameplay changes.\nVersion 2.5 was essentially the same as Version II; the cave and the\nhazards therein are unchanged, and top score is still 430 points.\nThere are a few more hints, especially for some of the more obscure\npuzzles. There are a few minor bugfixes and cosmetic changes. You\ncan now save a game and resume it at once (formerly you had to wait a\nwhile first), but it now costs you a few points each time you save the\ngame. Saved games are now stored in much smaller files than before.'
- GO_UNNEEDED: 'You don''t have to say "go" every time; just specify a direction or, if\nit''s nearby, name the place to which you wish to move.'
- CANNOT_CARRY7: !!null
+- MACHINE_SWINGOUT: 'As you strike the vending machine, it pivots backward along with a\nsection of wall, revealing a dark passage leading south.'
+- MACHINE_SWINGBACK: 'The vending machine swings back to block the passage.'
classes:
- threshold: 0
- [BIRD_UNCAGED, 'A cheerful little bird is sitting here singing.']
- [BIRD_CAGED, 'There is a little bird in the cage.']
- [BIRD_FOREST_UNCAGED, 'A cheerful little bird is sitting here singing.']
+ sounds:
- 'The bird''s singing is quite melodious.'
- 'The bird does not seem inclined to sing while in the cage.'
- 'It almost seems as though the bird is trying to tell you something.'
longs:
- 'A huge green fierce snake bars the way!'
- '' # chased away
+ sounds:
- 'The snake is hissing venomously.'
- OBJ_12:
inventory: '*fissure'
inventory: '*stone tablet'
longs:
- 'A massive stone tablet imbedded in the wall reads:\n"Congratulations on bringing light into the dark-room!"'
+ texts:
- '"Congratulations on bringing light into the dark-room!"'
- OBJ_14:
inventory: 'Giant clam >GRUNT!<'
longs:
- 'There is an enormous clam here with its shell tightly closed.'
+ sounds:
- 'The clam is as tight-mouthed as a, er, clam.'
- OBJ_15:
inventory: 'Giant oyster >GROAN!<'
longs:
- 'There is an enormous oyster here with its shell tightly closed.'
- 'Interesting. There seems to be something written on the underside of\nthe oyster.'
+ sounds:
- 'Even though it''s an oyster, the critter''s as tight-mouthed as a clam.'
- 'It says the same thing it did before. Hm, maybe it''s a pun?'
- OBJ_16:
inventory: '"Spelunker Today"'
longs:
- 'There are a few recent issues of "Spelunker Today" magazine here.'
+ texts:
- 'I''m afraid the magazine is written in dwarvish. But pencilled on one\ncover you see, "Please leave the magazines at the construction site."'
- OBJ_17:
inventory: !!null
- 'The plant spurts into furious growth for a few seconds.'
- 'The plant grows explosively, almost filling the bottom of the pit.'
- 'You''ve over-watered the plant! It''s shriveling up! And now . . .'
+ sounds:
- 'The plant continues to ask plaintively for water.'
- 'The plant continues to demand water.'
- 'The plant now maintains a contented silence.'
- 'The blood-specked body of a huge green dead dragon lies to one side.'
- 'The body of a huge green dead dragon is lying off to one side.'
- 'Congratulations! You have just vanquished a dragon with your bare\nhands! (Unbelievable, isn''t it?)'
+ sounds:
- 'The dragon''s ominous hissing does not bode well for you.'
- 'The dragon is, not surprisingly, silent.'
- 'The dragon is, not surprisingly, silent.'
- 'A burly troll stands by the bridge and insists you throw him a\ntreasure before you may cross.'
- 'The troll steps out from beneath the bridge and blocks your way.'
- '' # chased away
+ sounds:
- 'The troll sounds quite adamant in his demand for a treasure.'
- OBJ_34:
inventory: '*phony troll'
inventory: '*message in second maze'
longs:
- 'There is a message scrawled in the dust in a flowery script, reading:\n"This is not the maze where the pirate leaves his treasure chest."'
+ texts:
- '"This is not the maze where the pirate leaves his treasure chest."'
- OBJ_37:
inventory: '*volcano and/or geyser'
- OBJ_38:
inventory: '*vending machine'
longs:
- - 'There is a massive and somewhat battered vending machine here. The\ninstructions on it read: "Drop coins here to receive fresh batteries."'
+ - [VEND_BLOCKS, 'There is a massive and somewhat battered vending machine here. The\ninstructions on it read: "Drop coins here to receive fresh batteries."']
+ - [VEND_UNBLOCKS, 'There is a massive vending machine here, swung back to reveal a\nsouthward passage.']
+ texts:
- '"Drop coins here to receive fresh batteries."'
- - 'As you strike the vending machine, it pivots backward along with a\nsection of wall, revealing a dark passage leading south.'
- - 'There is a massive vending machine here, swung back to reveal a\nsouthward passage.'
- '"Drop coins here to receive fresh batteries."'
- - 'The vending machine swings back to block the passage.'
- OBJ_39:
inventory: 'Batteries'
longs:
inventory: '*ogre'
longs:
- 'A formidable ogre bars the northern exit.'
+ sounds:
- 'The ogre is apparently the strong, silent type.'
- OBJ_42:
inventory: '*urn'
inventory: '*mud'
longs:
- ''
+ texts:
- '"MAGIC WORD XYZZY"'
- OBJ_48:
inventory: '*note'
longs:
- ''
+ texts:
- '"You won''t get it up the steps"'
- OBJ_49:
inventory: '*sign'
longs:
- ''
+ texts:
- 'Cave under construction beyond this point.\n Proceed at own risk.\n [Witt Construction Company]'
- '"Treasure Vault. Keys in main office."'
- OBJ_50:
long TRVS;
long TRNVLS;
long TABNDX;
-long OBJSND[NOBJECTS + 1];
long OBJTXT[NOBJECTS + 1];
long KEY[LOCSIZ + 1];
long LINES[LINSIZ + 1];
long KK = GETNUM(NULL);
long I = GETNUM(NULL);
if (I != 0) {
- OBJSND[K] = (KK > 0 ? KK : 0);
OBJTXT[K] = (I > 0 ? I : 0);
continue;
}
* message for game.prop(N)=0. Successive prop messages are
* found by chasing pointers. */
for (int I = 1; I <= NOBJECTS; I++) {
- OBJSND[I] = 0;
OBJTXT[I] = 0;
}
for (int I = 1; I <= LOCSIZ; I++) {
fprintf(header_file, "\n");
// content variables
- write_1d(header_file, OBJSND, NOBJECTS + 1, "OBJSND");
write_1d(header_file, OBJTXT, NOBJECTS + 1, "OBJTXT");
write_1d(header_file, KEY, LOCSIZ + 1, "KEY");
write_1d(header_file, TRAVEL, TRVSIZ + 1, "TRAVEL");
* 330 vocabulary words (KTAB, ATAB, TABSIZ).
* 185 locations (KEY, COND, game.abbrev, game.atloc, LOCSIZ).
* 100 objects (PLAC, game.place, FIXD, game.fixed, game.link (twice),
- * ogame.prop, OBJSND, OBJTXT).
+ * ogame.prop).
* 35 "action" verbs (ACTSPK, VRBSIZ).
* 12 different player classifications (CTEXT, CVAL, CLSMAX).
* 20 hints (game.hintlc, game.hinted, HINTS, HNTSIZ).
* and block him. (standard travel entries check for
* game.prop(TROLL)=0.) Special stuff for bear. */
if (game.prop[TROLL] == 1) {
- pspeak(TROLL, 1);
+ pspeak(TROLL,look, 1);
game.prop[TROLL] = 0;
MOVE(TROLL2, 0);
MOVE(TROLL2 + NOBJECTS, 0);
int kk = game.prop[obj];
if (obj == STEPS && game.loc == game.fixed[STEPS])
kk = 1;
- pspeak(obj, kk);
+ pspeak(obj, look, kk);
}
}
}
* tick game.clock1 unless well into cave (and not at Y2). */
if (game.closed) {
if (game.prop[OYSTER] < 0 && TOTING(OYSTER))
- pspeak(OYSTER, 1);
+ pspeak(OYSTER, look, 1);
for (size_t i = 1; i <= NOBJECTS; i++) {
if (TOTING(i) && game.prop[i] < 0)
game.prop[i] = -1 - game.prop[i];
va_end(ap);
}
-void pspeak(vocab_t msg, int skip, ...)
-/* Find the skip+1st message from msg and print it. msg should be
- * the index of the inventory message for object. (INVEN+N+1 message
- * is game.prop=N message). */
+void pspeak(vocab_t msg, enum speaktype mode, int skip, ...)
+/* Find the skip+1st message from msg and print it. Modes are:
+ * feel = for inventory, what you can touch
+ * look = the long description for the state the object is in
+ * listen = the sound for the state the object is in
+ * study = text on the object. */
{
va_list ap;
va_start(ap, skip);
- if (skip >= 0)
- vspeak(object_descriptions[msg].longs[skip], ap);
- else
+ switch (mode) {
+ case touch:
vspeak(object_descriptions[msg].inventory, ap);
+ break;
+ case look:
+ vspeak(object_descriptions[msg].longs[skip], ap);
+ break;
+ case hear:
+ vspeak(object_descriptions[msg].sounds[skip], ap);
+ break;
+ case study:
+ vspeak(object_descriptions[msg].texts[skip], ap);
+ break;
+ }
va_end(ap);
}
typedef struct {{
const char* inventory;
const char** longs;
+ const char** sounds;
+ const char** texts;
}} object_description_t;
typedef struct {{
template = """ {{
.inventory = {},
.longs = (const char* []) {{
+{}
+ }},
+ .sounds = (const char* []) {{
+{}
+ }},
+ .texts = (const char* []) {{
{}
}},
}},
message = message[:45] + "..."
statedefines += "#define %s\t%d /* %s */\n" % (label, i, message)
statedefines += "\n"
- obj_str += template.format(i_msg, longs_str)
+ sounds_str = ""
+ if item[1].get("sounds") == None:
+ sounds_str = " " * 12 + "NULL,"
+ else:
+ for l_msg in item[1]["sounds"]:
+ sounds_str += " " * 12 + make_c_string(l_msg) + ",\n"
+ sounds_str = sounds_str[:-1] # trim trailing newline
+ texts_str = ""
+ if item[1].get("texts") == None:
+ texts_str = " " * 12 + "NULL,"
+ else:
+ for l_msg in item[1]["texts"]:
+ texts_str += " " * 12 + make_c_string(l_msg) + ",\n"
+ texts_str = texts_str[:-1] # trim trailing newline
+ obj_str += template.format(i_msg, longs_str, sounds_str, texts_str)
obj_str = obj_str[:-1] # trim trailing newline
return obj_str