the-infocom-files / cutthroats

Cutthroats
3 stars 3 forks source link

The Weasel doesn't kill you if you catch him in your room in superbrief mode #4

Open eriktorbjorn opened 4 years ago

eriktorbjorn commented 4 years ago

Usually, if you catch The Weasel rummaging through your stuff he'll kill you:

>SOUTH
Your Room
You're in your room in the Red Boar Inn. It's sparsely furnished, but
comfortable enough. To the north is the door, and there's a closet without a
door to the west.
The Weasel is rummaging through your stuff. He notices you, and before you have
a chance to react, he smiles then cuts your throat.

   ****  You have died  ****

Too bad.

Same thing in brief mode:

>SOUTH
Your Room
The Weasel is rummaging through your stuff. He notices you, and before you have
a chance to react, he smiles then cuts your throat.

   ****  You have died  ****

Too bad.

But in superbrief mode:

>SOUTH
Your Room
>LOOK
Your Room
You're in your room in the Red Boar Inn. It's sparsely furnished, but
comfortable enough. To the north is the door, and there's a closet without a
door to the west.
You can't help notice that your dresser has been opened and the contents messed
up.
On the floor is a note that must have been slipped under the door while you
slept.
In a corner of the room is a lopsided wooden dresser.
The dresser contains:
  A book of shipwrecks
  A room key
The Weasel is picking his teeth with a nasty knife, looking around furtively.
A comfortable bed sits along the wall.

This is how BEDROOM-F handles it:

<ROUTINE BEDROOM-F (RARG)
     <COND (<EQUAL? .RARG ,M-FLASH>
        <COND (<AND <IN? ,WEASEL ,BEDROOM>
                <NOT <VERB? LOOK>>>
               <JIGS-UP 
"The Weasel is rummaging through your stuff. He notices you, and
before you have a chance to react, he smiles then cuts your throat.">)

It seems like M-FLASH isn't invoked in superbrief mode. See DESCRIBE-ROOM:

     <COND (<OR .LOOK? <NOT ,SUPER-BRIEF>>
        <COND (<AND .V? <APPLY <GETP ,HERE ,P?ACTION> ,M-LOOK>>
               <RTRUE>)
              (<AND .V? <SET STR <GETP ,HERE ,P?LDESC>>>
               <TELL .STR CR>)>
        <APPLY <GETP ,HERE ,P?ACTION> ,M-FLASH>
        <COND (<AND .AV <NOT <==? ,HERE .AV>> <FSET? .AV ,VEHBIT>>
               <APPLY <GETP .AV ,P?ACTION> ,M-LOOK>)>)>
eriktorbjorn commented 4 years ago

This is how M-FLASH is documened in Marc Blank's ZIL manual:

M-FLASH is a context code that can be used in a ROOM’s ACTION ROUTINE to describe something in the room regardless of the level of verbosity or what’s already been printed. It was used twice in ZORK II and has lived in almost total obscurity since.

So according to that, it should work. But does it? From a quick look, it seems that most games that implement M-FLASH at all (many of them don't) have an exception for superbrief mode like that. Though Seastalker and Moonmist may be exceptions to that rule. Seastalker also invokes M-FLASH from GOTO, and Moonmist from ENTER-ROOM.

I could be wrong about that, though.

eriktorbjorn commented 4 years ago

Perhaps it's worth taking a look at what games actually use M-FLASH to see what may break?

To summarize, Cutthroats and Moonmist seem to be the only games to use (abuse?) it for game logic, rather than simple descriptions.

I seem to recall seeing some game using M-ENTER and a timer to print messages after the room description. (Simply using M-ENTER would print it before, I think.) So if the code has to be rewritten, that's a possibility.

eriktorbjorn commented 4 years ago

If I understand GOTO and DESCRIBE-ROOM correctly, the only safe way to detect if the player enters a room (other than game-specific hacks) is to use M-ENTER since both M-LOOK and M-FLASHmay be skipped, sometimes for perfectly understandable reasons (e.g. the room is dark).

But M-ENTER is invoked before the room description is printed. The game I saw which used timers to still print messages directly after the room description was probably Sorcerer, e.g.:

<ROUTINE TREE-BRANCH-F (RARG)
     <COND (<EQUAL? .RARG ,M-LOOK>
        <TELL "You are ">
        <COND (,FLYING
               <TELL "flying near">)
              (T
               <TELL "on">)>
        <TELL
" a large gnarled branch of an old and twisted tree." CR>)
           (<EQUAL? .RARG ,M-ENTER>
        <ENABLE <QUEUE I-BOA -1>>
        <RFALSE>)>>

<ROUTINE I-BOA ()
     <COND (<EQUAL? ,HERE ,TREE-BRANCH>
        <COND (,FLYING
               <RFALSE>)
              (,BOA-WARNING
               <JIGS-UP
"|
The snake begins wrapping itself around your torso, squeezing
the life out of you...">)
              (T
               <SETG BOA-WARNING T>
               <TELL CR
"A giant boa constrictor is slithering along the branch toward you!" CR>)>)
           (T
        <SETG BOA-WARNING <>>
        <DISABLE <INT I-BOA>>
        <RFALSE>)>>

Which produces:

>UP
Tree Branch
You are on a large gnarled branch of an old and twisted tree.

A giant boa constrictor is slithering along the branch toward you!
The hellhound leaps madly about the base of the tree, gnashing its jaws.
eriktorbjorn commented 4 years ago

Though using the timer trick, the game would probably also list the objects in the room, rather than ending right after the room description. So maybe the solution for this game is to change the semantics of M-FLASH to match the documentation?

It seems like Moonmist may have done just that. I'll try to remember checking that when I get to that game.

eriktorbjorn commented 4 years ago

I just checked: You can enter McGinty Salvage through the back window while he's there without getting killed, if you do it in superbrief mode. (He will kill you as soon as you look, through.)

eriktorbjorn commented 4 years ago

And The Weasel doesn't toss the line over the side if you enter the Aft Deck in superbrief mode. (He will once you look.)

eriktorbjorn commented 4 years ago

Similarly, there are events that are triggered in an actor's M-OBJDESC handler. These do not appear to be triggered in superbrief mode, because the actor isn't shown when you enter the room.

This might include, but not be limited to: