#!/usr/bin/perl print "Content-type: text/html\n\n"; ################################################################ ## ARGUMENTS ## ## rm=N Room number, 0 .. $MAXROOM. Sets $RoomNumber. ## ## in=XXX Packed inventory, as a number base $MAXITEM. ## Must be unpacked into @ihas_by_item first. ## ## ## rh=XXX Room Has X; packed inventory times $MAXROOM ## plus the room whose contents are listed. ## There may be a lot of these. Basically diffs ## from the values listed in @item_home. ## Must be unpacked into @room_contents first. ## er=XXX After unpacking mod $MAXROOMS, all these rooms have ## nothing at all in them. Set @room_contents accordingly. ## ## f=NXXX Flags set N; XXX = three chars base 64 via table: ## "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+" ## Convert number to binary, then set flags 18*N+(XXX). ## XXX is stored in order flag 0... flag 18, bitwise. ## There MUST be a multiple of 18 flags! ## ## x=N Examining object N. Sets $CurrentlyExamining. ## ## msg=TXT Message "TXT". Sets $CurrentlyMessaging, and prints ## the appropriate message from %message_desc. Messages ## don't get hypertexted, except for a "Back" button. ## ## dw=N Sets $NounDollar to N. ## ################################################################ ## VARIABLES ## ## @item_by_num Maps between item names ('keys') and ## %n item numbers (2). ## ## @item_home Default room contents, as packed 'in' strings. ## @room_contents Current room contents, as packed 'in' strings. ## ## @ihas_by_num Booleans; is item number N in inventory? ## $NumberOfItemsCarried Number of items in inventory, as calculated ## from in=XXX by unpack_args. ## ## @room_by_num Maps between room names ('inside building') and ## %r room numbers (1). ## @room_desc HTML room descriptions; links in [brackets]. ## @room_links Href code for [brackets] in @room_desc. ## ## @item_desc HTML object descriptions; links in [brackets]. ## @item_links Href code for [brackets] in @item_desc. ## ## %message_desc HTML message text. No [bracket-links] allowed. ## ## %f Maps flag names ('gotwater') to numbers (1). ## @flag Booleans; is flag N currently on? ## ## $RoomNumber Current room number (rm=N). ## ## $CurrentlyExamining Item number of object we're looking at, in ## range (1..$MAXITEM-1). ## ## $CurrentlyMessaging Text label of current message, e.g., 'EATF' ## ## $NounDollar Item number of object we're "puzzling over." ## Same role as $NOUN$ in AGT, for href_say() ## messages. ## ## $argsPickingUpThisItem Hint to pack_args() that this item should ## not be included in the current room's contents. ## THIS VARIABLE SHOULD *NOT* AFFECT THE PLAYER'S ## INVENTORY LIST! It makes the object actually ## "disappear" from the room. ## $argsDroppingThisItem Hint to pack_args() that this item should ## be included in the current room's contents. ## THIS VARIABLE SHOULD *NOT* AFFECT THE PLAYER'S ## INVENTORY LIST! It makes the object actually ## "appear" in the room. ## ################################################################ use integer; ############################################################# ## use strict; ## ## #ifdef CGI ## use CGI::Carp qw(fatalsToBrowser); ## #endif ## ## ############################################################# my $MAXITEM = 27; my $MAXABSTRACTITEM = 115; my $MAXFLAG = 54; my $MAXROOM = 70; my $RoomNumber = 0; my $CurrentlyExamining = 0; my $CurrentlyMessaging = ""; my $NounDollar = 0; my $argsPickingUpThisItem = 0; my $argsDroppingThisItem = 0; my $DarknessCounter = 0; sub pack_args(); sub reunpack_args($); sub start_desc(); sub done_desc(); sub can_see_room(); sub item_in_room($); sub item_short_name($); sub is_treas($); sub ihas_treas($); sub print_possessions(); sub print_room_description($); sub print_item_description($); sub stop_game(); ## INVENTORY ITEMS my @ihas_by_num = (0) x $MAXITEM; ## boolean - have I got such-and-such? my $NumberOfItemsCarried = 0; my @item_by_num; my %n = ( ## Items: 'off lamp' => 1, 'on lamp' => 2, 'keys' => 3, 'food' => 4, 'empty bottle' => 5, 'bottle of water' => 6, 'bottle of oil' => 7, 'rusty wand' => 8, 'cheerful bird' => 9, 'caged bird' => 10, 'wicker cage' => 11, 'green snake' => 12, 'gold nugget' => 13, 'diamonds' => 14, 'silver bars' => 15, 'jewelry' => 16, 'rare coins' => 17, 'giant clam' => 18, 'giant oyster' => 19, 'pearl' => 20, 'magazine' => 21, 'treasure chest' => 22, 'pool of oil' => 23, 'little plant' => 24, '12-foot beanstalk' => 25, 'huge beanstalk' => 26, 'stream' => 101, 'building' => 102, 'grate down' => 103, 'grate up' => 104, 'mist' => 105, 'fissure' => 106, 'nugget note' => 107, 'stone steps down' => 108, 'stone steps up' => 109, 'crystal bridge' => 110, 'forest' => 111, 'shadowy figure' => 112, 'sea air' => 113, 'bedrock block' => 114, ); foreach my $i (keys %n) { $item_by_num[$n{$i}] = $i; } ## IN-GAME FLAGS my @flag = (0) x $MAXFLAG; ## boolean - is flag X turned on, or off? my %f = ( ## Flags: 'VIEWING_SELF' => 0, 'MSG_GOT_WATER' => 1, 'MSG_GOT_OIL' => 2, 'MSG_SPILL_WATER' => 3, 'MSG_SPILL_OIL' => 4, 'MSG_LIT_LAMP' => 5, 'MSG_EXT_LAMP' => 6, 'GRATE_OPEN' => 7, 'MSG_GRATE_OPEN' => 8, 'MSG_GRATE_CLOSE' => 9, 'MSG_TRANSPORT' => 10, 'TRIED_JUMP' => 11, 'MSG_JUMP_TO_DEATH' => 12, 'CRYSTAL_BRIDGE' => 13, ## Does the crystal bridge exist? 'VIEW_ROOM' => 14, 'SLIT_SHOWN' => 15, 'BIRD_FLAG' => 16, 'MSG_GOT_BIRD' => 17, 'MSG_NO_SNAKE' => 18, 'MSG_DROP_CAGE' => 19, 'MSG_FREE_BIRD' => 20, 'SNAKE_HNT1' => 21, 'SNAKE_HNT2' => 22, 'FIENDISH_1' => 23, ## For use in the two mazes. 'FIENDISH_2' => 24, ## Five of these modify the room number, 'FIENDISH_3' => 25, ## and the sixth is a simple random 'FIENDISH_4' => 26, ## flag whose value doesn't do anything. 'FIENDISH_5' => 27, ## This keeps browsers from changing the 'FIENDISH_6' => 28, ## link colors of rooms we've already 'FIENDISH_7' => 29, ## visited. >;) 'MAZE_DEADEND' => 30, 'BEHIND_BLOCK' => 31, 'MED_PLANT' => 32, ## Does the medium plant exist? 'HUGE_PLANT' => 33, ## Does the huge plant exist? 'MSG_CLIMB_MED' => 34, 'MSG_CLIMB_HUGE' => 35, 'MSG_WATER_LITTLE' => 36, 'MSG_WATER_MED' => 37, 'MSG_WATER_HUGE' => 38, 'MSG_OIL_PLANT' => 39, 'USELESS1' => 40, 'USELESS3' => 41, 'USELESS4' => 42, 'USELESS5' => 43, 'USELESS6' => 44, 'USELESS7' => 45, 'USELESS8' => 46, 'USELESS9' => 47, 'USELESSA' => 48, 'USELESSB' => 49, 'USELESSC' => 50, 'USELESSD' => 51, 'USELESSE' => 52, 'USELESSF' => 53, ); ## IN-GAME MESSAGES my %message_desc = ( 'EATF' => q(My, that food was tasty!), 'LBTT' => q(Maybe there are batteries inside the lamp.), 'PPES' => q(There's nothing special about the sewer pipes.), 'H2O' => q(You have taken a drink from the stream. The water). q( tastes strongly of minerals, but is not unpleasant.). q( It is extremely cold.), 'SLIT' => q(You can't fit through a 2-inch slit!), 'ANCH' => q(You don't seem to be able to budge the steel grate.), 'GLOK' => q(You can't reach the lock, no matter how hard you try.), 'SURF' => q(Sunlight filters through the bars of the grate.). q( If only you were on the other side of it.), 'MAGI' => q(A brief note on the nature of magic. Some scholars). q( would have it that the command of magical powers). q( comes naturally to those with a special aptitude,). q( and to others only after long years of training.). q( These scholars are full of it. Those who dwell). q( in caves have always known that magic spells are). q( child's play as long as you know the right words.), 'MGNO' => q(Nothing happens.), 'CRCK' => q(The crack is far too small for you to follow.), 'JBRI' => q(I respectfully suggest you go across the bridge). q( instead of jumping.), 'JFIS' => q(On second thought, the fissure is still much). q( too wide to jump.), 'DARK' => q(It is pitch black. You can't see your hand in front). q( of your face.), 'PITS' => q(One of the many dangers of cave exploring is the). q( danger of falling into a pit. Colossal Cave in). q( particular is known to be riddled with these deep). q( crevasses, often filled with water or sharp rocks). q( and debris from the cave above. Suffice it to say,). q( you wouldn't want to be caught in the cave without a). q( light source of some kind.), 'BRD1' => q(The bird was unafraid when you entered, but as you). q( approach it becomes disturbed and you cannot catch it.), 'BRD2' => q(The bird is frightened right now and you cannot catch). q( it no matter what you try. Perhaps you might try later.), 'BRD3' => q(You can catch the bird, but you cannot carry it.), 'RIDI' => q(Don't be ridiculous!), 'BULK' => q(You cannot lift any more.), 'DWHA' => q(What do you want to do with the $NOUN$?), 'VTRE' => q(As you drop the $NOUN$, it vanishes in a clash of). q( cymbals and a puff of orange smoke! A distant). q( voice booms:
EOF
,
);
## ROOMS
my @room_by_num;
my %r = (
## Room names:
'end of road' => 0,
'inside building' => 1,
'valley' => 2,
'slit in streambed' => 3,
'outside grate' => 4,
'hill by road' => 5,
'forest' => 6,
'open forest' => 7,
'below the grate' => 8,
'cobble crawl' => 9,
'debris room' => 10,
'awkward canyon' => 11,
'bird chamber' => 12,
'top of small pit' => 13,
'hall of mists' => 14,
'east of fissure' => 15,
'nugget of gold room' => 16,
'hall of mt. king' => 17,
'low n-s passage' => 18,
'south side chamber' => 19,
'west side chamber' => 20,
'west of fissure' => 21,
'w end - hall of mists'=> 22,
'crossover of passages'=> 23,
'blocked passageway' => 24,
'"Y2"' => 25,
'window on pit' => 26,
'jumble of rock' => 27,
'low wide passage' => 28, ## Note the extra space in the
'low wide passage ' => 29, ## second room's name!
'dirty passage' => 30,
'brink of small pit' => 31,
'bottom of small pit' => 32,
'east end of long hall'=> 33,
'west end of long hall'=> 34,
'dusty rock room' => 35,
'complex junction' => 36,
'shell room' => 37,
'arched hall' => 38,
'sloping corridor' => 39,
'sloping corridor ' => 40,
'cul-de-sac' => 41,
## lots of rooms for the little twisty maze, all alike: 42-55
'brink of pit' => 56,
'pirate\'s den' => 57,
'bedquilt' => 58,
'anteroom' => 59,
'witt\'s end' => 60,
'slab room' => 61,
'swiss cheese room' => 62,
'tall e-w canyon' => 63,
'wide place' => 64,
'e end of twopit room'=> 65,
'w end of twopit room'=> 66,
'east pit' => 67,
'west pit' => 68,
'long narrow corridor'=> 69,
);
foreach my $i (keys %r) {
$room_by_num[$r{$i}] = $i;
}
foreach (42..55) {
$room_by_num[$_] = 'twisty little maze';
}
my @item_home = (0) x $MAXROOM;
$item_home[$r{'inside building'}] =
$n{'off lamp'}*($MAXITEM**3) + $n{'food'}*($MAXITEM**2)
+ $n{'keys'}*($MAXITEM) + $n{'bottle of water'};
$item_home[$r{'debris room'}] =
$n{'rusty wand'};
$item_home[$r{'cobble crawl'}] =
$n{'wicker cage'};
$item_home[$r{'bird chamber'}] =
$n{'cheerful bird'};
$item_home[$r{'east of fissure'}] =
$n{'diamonds'};
$item_home[$r{'nugget of gold room'}] =
$n{'gold nugget'};
$item_home[$r{'hall of mt. king'}] =
$n{'green snake'};
$item_home[$r{'low n-s passage'}] =
$n{'silver bars'};
$item_home[$r{'south side chamber'}] =
$n{'jewelry'};
$item_home[$r{'west side chamber'}] =
$n{'rare coins'};
$item_home[$r{'shell room'}] =
$n{'giant clam'};
$item_home[$r{'anteroom'}] =
$n{'magazine'};
$item_home[$r{'pirate\'s den'}] =
$n{'treasure chest'};
$item_home[$r{'east pit'}] =
$n{'pool of oil'};
$item_home[$r{'west pit'}] =
$n{'little plant'};
my @room_contents = @item_home;
##
## ROOM AND ITEM DESCRIPTIONS!
##
my @room_desc = < [Rough stone steps] lead [down] to the pit.
ROOM 14 NEXT
[You] are at one end of a vast hall stretching forward out of sight to the
[west]. There are openings to [either] [side]. Nearby, a wide stone staircase
leads [downward]. The hall is filled with [wisps of white mist] swaying to
and fro almost as if alive. A cold wind blows up the staircase. There is
a passage at the top of a dome behind you.
[Rough stone steps] lead [up] to the dome.
ROOM 15 NEXT
[You] are on the east bank of a [fissure] slicing clear across the hall. The
[mist] is quite thick here, and the fissure is too wide to [jump]. The hall
continues to the [east].
ROOM 16 NEXT
This is a low room with only the one [exit] and a crude note on the wall.
The note says: [You won't get it up the steps.]
ROOM 17 NEXT
[You] are in the hall of the mountain king, with [passages] [off] [in] [all]
[direction][s] - [north], [east], [west], and [south]. A wide stone
staircase leads [up] the way you came.
ROOM 18 NEXT
[You] are in a low [north]-[south] passage at a hole in the floor. The hole
goes [down] to an east-west passage.
ROOM 19 NEXT
[You] are in the south side chamber. The exit is to the [north].
ROOM 20 NEXT
[You] are in the west side chamber of the [hall of the mountain king].
A passage continues to the [west].
ROOM 21 NEXT
[You] are on the west side of the [fissure] in the hall of mists.
The hall continues to the [west], and a low passage exits to
the [north].
ROOM 22 NEXT
[You] are at the west end of the [hall of mists]. A low wide crawl continues
[west] and another goes [north]. To the [south] is a little passage 6 feet
off the floor.
ROOM 23 NEXT
[You] are at a crossover of a high [north]-[south] passage and a low
[east]-[west] one.
ROOM 24 NEXT
[You] are in a passageway leading [north]. There is a sign on the wall
of the passage saying This way to the Cave's Main Office. Just
beyond the sign, there has been a cave-in and the passageway is blocked.
The only exit is to the [south].
ROOM 25 NEXT
[You] are in a large room, with a passage to the [south], a passage to the
[west], and a wall of broken rock to the [east].
There is a large "Y2" on a rock in the room's center.
ROOM 26 NEXT
[You]'re at a low window overlooking a huge pit, which extends up out of
sight. A floor is indistinctly visible over 50 feet below. Traces of
[white mist] cover the floor of the pit, becoming thicker to the right.
Marks in the dust around the window would seem to suggest that someone
has been here recently.
Directly across the pit from you and 25 feet away there is a similar
window looking into a lighted room. A [shadowy figure] can be seen there
peering back at you. [Back]
ROOM 27 NEXT
[You] are in a [jumble] of rock, with [cracks] [everywhere].
ROOM 28 NEXT
[You] have crawled through a very low wide passage [parallel to] and
[north of] the hall of mists.
ROOM 29 NEXT
[You] have crawled through a very low wide passage [parallel to] and
[north of] the hall of mists.
ROOM 30 NEXT
[You] are in a dirty broken passage. To the east is a [crawl]. To
the west is a [large passage]. [Above you] is another passage.
ROOM 31 NEXT
[You] are on the brink of a small clean climbable [pit].
A crawl leads [west].
ROOM 32 NEXT
[You] are in the bottom of a small pit with a little [stream], which
enters and exits through tiny slits. [Back]
ROOM 33 NEXT
[You] are at the east end of a [very long hall] apparently without side
chambers. To the [east] a low wide crawl slants [up]. To the [north] a
round two foot hole slants [down].
ROOM 34 NEXT
[You] are at the west end of a very long featureless hall. The [hall]
joins up with a narrow [north]/[south] passage.
ROOM 35 NEXT
[You] are in a large room full of dusty rocks. There is a [big hole]
in the floor. There are cracks everywhere, and a passage leading [east].
ROOM 36 NEXT
[You] are at a complex junction. A low hands and knees passage from the
[north] joins a higher crawl from the [east] to make a [walking passage]
going west. There is also a large room [above], but there are no hand or
toe holds to climb up. The air is damp here.
ROOM 37 NEXT
[You]'re in a large room carved out of sedimentary rock. The floor and
walls are littered with bits of shells imbedded in the stone. A shallow
passage proceeds [downward], and a somewhat steeper one leads [up]. A low
hands and knees passage enters from the [south].
ROOM 38 NEXT
[You] are in an arched hall. A [coral passage] once continued up and east
from here, but is now blocked by debris. The [air] smells of sea water.
[Back]
ROOM 39 NEXT
[You] are in a long [sloping] corridor with ragged sharp walls.
[Back]
ROOM 40 NEXT
[You] are in a long [sloping] corridor with ragged sharp walls.
[Back]
ROOM 41 NEXT
[You] are in a cul-de-sac about eight feet across.
[Back]
ROOM 42 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike]. []
ROOM 43 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 44 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 45 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 46 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 47 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 48 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 49 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 50 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 51 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 52 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 53 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 54 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 55 NEXT
[You] are in a [maze] of [twisty] [little] [passages], [all] [alike].
ROOM 56 NEXT
[You] are on the brink of a thirty foot pit with a massive orange column down
one wall. You could [climb down] here but you could not get back up. The
[maze] [continues] [at] [this] [level].
ROOM 57 NEXT
[You] are in the Pirate's den. It is very messy and smells awful. There is a
black Jolly Rodger flag hanging from the ceiling -- too high to reach. There
are exits leading [east], [west], [south], [north], [up] and [down].
ROOM 58 NEXT
[You] are in bedquilt, a long [east]/[west] passage with [holes] [everywhere].
To explore at random select [north], [south], [up] or [down].
ROOM 59 NEXT
[You] are in an anteroom leading to a [large passage] to the east. Small
passages go [west] and [up]. The remnants of recent digging are evident.
A sign in midair here says: A [path] leads around
the pits to the east.
ROOM 67 NEXT
[You] are at the bottom of the eastern pit in the [twopit room].
ROOM 68 NEXT
[You] are at the bottom of the western pit in the [twopit room]. There
is a large [hole] in the wall about 25 feet above you.
ROOM 69 NEXT
[You] are in a long, narrow corridor stretching out of sight to the
[west]. At the [eastern end] is a hole through which you can see a
[profusion of leaves].
ROOM 70 NEXT
EOF
my @room_links = < This particular plover seems quite happy and is singing cheerfully.
ITEM 'caged bird' NEXT
There is a [little bird] inside the wicker cage. #
The bird is a black-bellied plover (rhymes with "lover" not "clover"). Its
Latin name is pluvialis sauatarola. Its belly is quite black -- hence,
the name: black-bellied plover. It also has white plumage with a white stripe
extending across its forehead, around its crown and nape and down the sides of
its breast. Its undertail is white. Its call is a drawn-out, mournful, three
note whistle with the second note lower pitched, like plee - o - ee.
The bird doesn't appear to like the cage because it has stopped singing.
ITEM 'wicker cage' NEXT
There is a small [wicker cage] discarded nearby. #
The wicker cage is a fairly simple design with an opening on the top.
ITEM 'green snake' NEXT
A [huge green fierce snake] bars the way! #
The snake is about 8 feet long and about 10 inches in diameter. It has raised
its head up and is following you with its eyes. It is hissing at you and its
forked tongue is darting in and out of its mouth with every hiss.
ITEM 'gold nugget' NEXT
There is a large sparkling [nugget of gold] here! #
The nugget weighs about two pounds and is worth a [lot of money].
ITEM 'diamonds' NEXT
There are several [diamonds] here! #
The diamonds are about 100 carats each and are perfectly clear.
ITEM 'silver bars' NEXT
There are [bars of silver] here! #
There are four silver bars -- each weighing about 5 pounds.
ITEM 'jewelry' NEXT
There is [precious jewelry] here! #
There are several necklaces and bracelets made of gold and silver. Each of
the pieces also has jewels set into the metal. This stuff didn't come out of
a Cracker Jack box -- by any means!
ITEM 'rare coins' NEXT
There are many [rare coins] here! #
The coins are all quite old and made of gold and silver.
ITEM 'giant clam' NEXT
There is an enormous [clam] here with its shell tightly closed. #
The clam is about 4 feet across and is quite heavy.
ITEM 'giant oyster' NEXT
There is an enormous [oyster] here with its shell tightly closed. #
Interesting. There seems to be something [written] on the underside
of the oyster.
ITEM 'pearl' NEXT
Off to one side lies a [glistening pearl]! #
The pearl is perfectly round and about six inches in diameter. It is quite
shiny and you can see your [reflection] in it.
ITEM 'magazine' NEXT
There is a recent issue of ["Spelunker Today" magazine] here. #
The magazine is a slick high-gloss production with numerous cave [pictures]
and a variety of [articles].
ITEM 'treasure chest' NEXT
The pirate's [treasure chest] is here! #
The pirate's chest is made of gold with jewels set into its top.
ITEM 'pool of oil' NEXT
There is a small [pool of oil] in one corner of the pit. #
Lord only knows where this oil came from. But here it is, in a little
pool in a depression at one side of this pit.
ITEM 'little plant' NEXT
There is a [tiny little plant] in the pit, murmuring "Water, water..." #
The plant cries out, Water... water, please... water.
ITEM '12-foot beanstalk' NEXT
A [12-foot-tall beanstalk] stretches out of the pit, bellowing "Water!!!" #
The plant bellows, Water!... water, please!... water!
[Climb it]
ITEM 'huge beanstalk' NEXT
There is a [gigantic beanstalk] stretching all the way up to the hole. #
The plant has almost filled the bottom of the pit. It stretches all
the way up to the hole in the wall of the twopit room. [Climb it]
ITEM 29 NEXT
EOF
@item_desc[101..200] = < ' . $text . 'Back';
}
sub href_go_bq($) {
if ($_[0] == 0) {
if (rand(100) < 33) {
return href_go(-1); ## $r{'north-south canyon'});
} elsif (rand(100) < 50) {
return href_go(-1); ## $r{'junction of canyons'});
} else {
return href_go(-1); ## $r{'large low room'});
}
}
else {
return href_say('BQCR');
}
}
sub href_go_witt() {
my $f1tmp = $flag[$f{'FIENDISH_1'}];
my $f2tmp = $flag[$f{'FIENDISH_2'}];
my $f3tmp = $flag[$f{'FIENDISH_3'}];
my $f4tmp = $flag[$f{'FIENDISH_4'}];
my $f5tmp = $flag[$f{'FIENDISH_5'}];
my $f6tmp = $flag[$f{'FIENDISH_6'}];
my $randn = int rand(32);
$flag[$f{'FIENDISH_1'}] = ($randn & (1<<0))? 1: 0;
$flag[$f{'FIENDISH_2'}] = ($randn & (1<<1))? 1: 0;
$flag[$f{'FIENDISH_3'}] = ($randn & (1<<2))? 1: 0;
$flag[$f{'FIENDISH_4'}] = ($randn & (1<<3))? 1: 0;
$flag[$f{'FIENDISH_5'}] = ($randn & (1<<4))? 1: 0;
$flag[$f{'FIENDISH_6'}] = (rand(100) < 50)? 1: 0;
$RoomNumber ^= $randn;
my $text = href_say('BQCR');
$RoomNumber ^= $randn;
$flag[$f{'FIENDISH_1'}] = $f1tmp;
$flag[$f{'FIENDISH_2'}] = $f2tmp;
$flag[$f{'FIENDISH_3'}] = $f3tmp;
$flag[$f{'FIENDISH_4'}] = $f4tmp;
$flag[$f{'FIENDISH_5'}] = $f5tmp;
$flag[$f{'FIENDISH_6'}] = $f6tmp;
return $text;
}
sub href_go_witt_exit($) {
if (rand(100) < 20) { return href_go($_[0]); }
else { return href_go_witt(); }
}
sub href_behind_block() {
if ($flag[$f{'BEHIND_BLOCK'}]) {
my $text = href_go($r{'tall e-w canyon'});
return " There is a small ${text}passage You find a small ${text}passage behind the block!";
}
else { return href_dummy() }
}
sub href_ex_twopit_hole() {
if ($flag[$f{'HUGE_PLANT'}]) { return href_say('2PHH') }
else { return href_say('2PNH') }
}
sub href_climb_bs() {
if ($flag[$f{'HUGE_PLANT'}]) {
$flag[$f{'MSG_CLIMB_HUGE'}] = 1;
my $text = href_go_view($r{'long narrow corridor'});
$flag[$f{'MSG_CLIMB_HUGE'}] = 0;
return $text;
}
else {
$flag[$f{'MSG_CLIMB_MED'}] = 1;
my $text = href_go_view($r{'w end of twopit room'});
$flag[$f{'MSG_CLIMB_MED'}] = 0;
return $text;
}
}
#####################################################
## PROCESSING THE ARGUMENTS (in both directions) ##
#####################################################
sub deal_with_fiendish()
{
my $randn = 0;
$randn = ($randn << 1) | $flag[$f{'FIENDISH_5'}];
$randn = ($randn << 1) | $flag[$f{'FIENDISH_4'}];
$randn = ($randn << 1) | $flag[$f{'FIENDISH_3'}];
$randn = ($randn << 1) | $flag[$f{'FIENDISH_2'}];
$randn = ($randn << 1) | $flag[$f{'FIENDISH_1'}];
$RoomNumber ^= $randn;
$flag[$f{'FIENDISH_1'}] = 0;
$flag[$f{'FIENDISH_2'}] = 0;
$flag[$f{'FIENDISH_3'}] = 0;
$flag[$f{'FIENDISH_4'}] = 0;
$flag[$f{'FIENDISH_5'}] = 0;
$flag[$f{'FIENDISH_6'}] = 0;
}
sub pack_flags
{
my $table =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+';
my $text = substr($table, ($_[0] & 0x3F), 1);
$text .= substr($table, (($_[1]>>12) & 0x3F), 1);
$text .= substr($table, (($_[1]>>6) & 0x3F), 1);
$text .= substr($table, (($_[1]) & 0x3F), 1);
return $text;
}
sub unpack_flags($)
{
stop_game if (length($_[0]) != 4);
my $table =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+';
my $text = $_[0];
my $byte = substr($text, 0, 1);
my $fl_no = index($table, $byte);
stop_game if ($fl_no < 0);
my $flag;
$byte = index($table, substr($text, 3, 1));
stop_game if ($byte < 0);
$flag = $byte;
$byte = index($table, substr($text, 2, 1));
stop_game if ($byte < 0);
$flag |= $byte << 6;
$byte = index($table, substr($text, 1, 1));
stop_game if ($byte < 0);
$flag |= $byte << 12;
for my $j (0 .. 17) {
$flag[18*$fl_no + $j] = (0 != ($flag & (1 << 17-$j)));
}
}
sub pack_args()
{
my $text = "rm=${RoomNumber}";
my $pack_inv = 0;
foreach my $i (1..$MAXITEM-1) {
if ($ihas_by_num[$i]) {
$pack_inv = $pack_inv * $MAXITEM + $i;
if ($pack_inv >= 1_000_000 / $MAXITEM) {
$text .= "&in=${pack_inv}";
$pack_inv = 0;
}
}
}
$text .= "&in=${pack_inv}" if ($pack_inv != 0);
## A little bit of extra compression; otherwise, we get a lot
## of argument strings with ...rh=6&rh=9&rh=10&rh=14...!
my $empty_rooms = 0;
foreach my $i (0 .. $MAXROOM-1) {
my $orig_rmcnt = $room_contents[$i];
if ($argsPickingUpThisItem || $argsDroppingThisItem) {
my $tmp1 = $room_contents[$i];
my $tmp2 = ($i == $RoomNumber)? $argsDroppingThisItem: 0;
while ($tmp1) {
if ($tmp1 % $MAXITEM != $argsPickingUpThisItem) {
$tmp2 *= $MAXITEM;
$tmp2 += $tmp1 % $MAXITEM;
}
$tmp1 /= $MAXITEM;
}
## Unfortunately, to make the "item_in_room" code work,
## we have to re-reverse the contents of the room so that
## other rooms' contents don't magically change. If that
## happens, items start disappearing from inventories.
$room_contents[$i] = 0;
while ($tmp2) {
$room_contents[$i] *= $MAXITEM;
$room_contents[$i] += $tmp2 % $MAXITEM;
$tmp2 /= $MAXITEM;
}
}
if ($room_contents[$i] != $item_home[$i]) {
if ($room_contents[$i] != 0) {
my $rh = $room_contents[$i] * $MAXROOM + $i;
$text .= "&rh=${rh}";
}
else {
$empty_rooms = $empty_rooms * $MAXROOM + $i;
if ($empty_rooms >= 1_000_000 / $MAXROOM) {
$text .= "&er=${empty_rooms}";
$empty_rooms = 0;
}
}
}
$room_contents[$i] = $orig_rmcnt;
}
if ($empty_rooms != 0) {
$text .= "&er=${empty_rooms}";
}
foreach my $fl_no (0 .. ($MAXFLAG/18)-1) {
my $fl = 0;
foreach $j (0 .. 17) {
$fl = ($fl << 1) + ($flag[18*$fl_no + $j] != 0);
}
if ($fl != 0) {
$text .= "&f=";
$text .= pack_flags($fl_no, $fl);
}
}
if ($CurrentlyExamining) {
$text .= "&x=${CurrentlyExamining}";
}
if ($CurrentlyMessaging) {
$text .= "&msg=${CurrentlyMessaging}";
}
if ($NounDollar) {
$text .= "&dw=${NounDollar}";
}
if ($DarknessCounter) {
$text .= "&dc=${DarknessCounter}";
}
return "advent.cgi?" . $text;
}
sub unpack_args
{
my $cgi_args = join('&', @_);
@_ = split(/&/, $cgi_args);
foreach my $i (@_) {
my $varname;
my $vardata;
($varname, $vardata) = split(/=/, $i);
if ($varname eq "rm") {
$RoomNumber = $vardata;
} elsif ($varname eq "in") {
my $invent_compact = $vardata;
while ($invent_compact != 0) {
stop_game if ($ihas_by_num[$invent_compact % $MAXITEM]);
$ihas_by_num[$invent_compact % $MAXITEM] = 1;
++$NumberOfItemsCarried;
$invent_compact /= $MAXITEM;
}
} elsif ($varname eq "rh") {
my $rm_no = $vardata % $MAXROOM;
my $invent_compact = $vardata / $MAXROOM;
if ($room_contents[$rm_no] == $item_home[$rm_no]) {
$room_contents[$rm_no] = 0;
}
while ($invent_compact != 0) {
$room_contents[$rm_no] *= $MAXITEM;
$room_contents[$rm_no] += $invent_compact % $MAXITEM;
$invent_compact /= $MAXITEM;
}
} elsif ($varname eq "er") {
## All these rooms are completely empty.
while ($vardata != 0) {
$room_contents[$vardata % $MAXROOM] = 0;
$vardata /= $MAXROOM;
}
} elsif ($varname eq "f") {
unpack_flags($vardata);
} elsif ($varname eq "x") {
stop_game if ($CurrentlyExamining != 0);
$CurrentlyExamining = $vardata;
stop_game if ($CurrentlyExamining <= 0);
stop_game if ($MAXITEM <= $CurrentlyExamining
&& $CurrentlyExamining < 101);
stop_game if ($CurrentlyExamining >= $MAXABSTRACTITEM);
} elsif ($varname eq "msg") {
stop_game if ($CurrentlyMessaging ne "");
$CurrentlyMessaging = $vardata;
} elsif ($varname eq "dw") {
stop_game if ($NounDollar != 0);
$NounDollar = $vardata;
stop_game if ($NounDollar <= 0);
stop_game if ($MAXITEM <= $NounDollar
&& $NounDollar < 101);
stop_game if ($NounDollar >= $MAXABSTRACTITEM);
} elsif ($varname eq "dc") {
stop_game if ($DarknessCounter != 0);
$DarknessCounter = $vardata;
stop_game if ($DarknessCounter <= 0);
} else {
stop_game;
}
}
deal_with_fiendish();
stop_game if ($RoomNumber < 0 || $RoomNumber >= $MAXROOM);
}
sub reunpack_args($)
{
## This function is dangerous! It completely overwrites
## the current game state!
$RoomNumber = 0;
@ihas_by_num = (0) x $MAXITEM;
$NumberOfItemsCarried = 0;
@room_contents = @item_home;
@flag = (0) x $MAXFLAG;
$CurrentlyExamining = 0;
$CurrentlyMessaging = "";
$DarknessCounter = 0;
$NounDollar = 0;
my $arg = $_[0];
$arg =~ s/advent\.cgi\?//i;
unpack_args($arg);
}
#############################################################
## Process cmd-line arguments... ##
#############################################################
#ifdef CGI
my @args = split(/&/, $ENV{'QUERY_STRING'});
#else
my @args = @ARGV;
#endif
unpack_args(@args);
#############################################################
## PLAY THE GAME... show the room description ##
#############################################################
start_desc();
if ($flag[$f{'VIEW_ROOM'}]) {
$CurrentlyMessaging = "";
$CurrentlyExamining = 0;
$flag[$f{'VIEWING_SELF'}] = 0;
$flag[$f{'VIEW_ROOM'}] = 0;
}
if ($flag[$f{'MSG_SPILL_WATER'}]) {
print " Your bottle is empty and your feet are wet.\n";
$flag[$f{'MSG_SPILL_WATER'}] = 0;
}
elsif ($flag[$f{'MSG_SPILL_OIL'}]) {
if ($RoomNumber == $r{'valley'}) {
print " You pour out the bottle into the stream. Your bottle is empty and your feet are wet.\n";
}
$flag[$f{'MSG_SPILL_OIL'}] = 0;
}
elsif ($flag[$f{'MSG_GOT_WATER'}]) {
print " You have filled your bottle with water.\n";
$flag[$f{'MSG_GOT_WATER'}] = 0;
}
elsif ($flag[$f{'MSG_GOT_OIL'}]) {
print " You have filled your bottle with oil.\n";
$flag[$f{'MSG_GOT_OIL'}] = 0;
}
elsif ($flag[$f{'MSG_GOT_BIRD'}]) {
print " You catch the bird and put it inside the wicker cage.\n";
$flag[$f{'MSG_GOT_BIRD'}] = 0;
}
elsif ($flag[$f{'MSG_LIT_LAMP'}]) {
my $the = ($ihas_by_num[$n{'on lamp'}])? 'Your': 'The';
print " ${the} lamp is now shining brightly!\n";
$flag[$f{'MSG_LIT_LAMP'}] = 0;
}
elsif ($flag[$f{'MSG_EXT_LAMP'}]) {
my $the = ($ihas_by_num[$n{'off lamp'}])? 'Your': 'The';
print " ${the} lamp is now off.\n";
$flag[$f{'MSG_EXT_LAMP'}] = 0;
}
elsif ($flag[$f{'MSG_GRATE_OPEN'}]) {
print " The grate is now open.\n";
$flag[$f{'MSG_GRATE_OPEN'}] = 0;
}
elsif ($flag[$f{'MSG_GRATE_CLOSE'}]) {
print " The grate is now shut and locked.\n";
$flag[$f{'MSG_GRATE_CLOSE'}] = 0;
}
elsif ($flag[$f{'MSG_TRANSPORT'}]) {
print < ";
print href_start_over() . "Play again You put the cage (with the bird in it) on the ground.".
" The bird has stopped singing.\n";
$flag[$f{'MSG_DROP_CAGE'}] = 0;
}
elsif ($flag[$f{'MSG_FREE_BIRD'}]) {
print " You release the bird from the wicker cage.\n";
$flag[$f{'MSG_FREE_BIRD'}] = 0;
}
elsif ($flag[$f{'MSG_OIL_PLANT'}]) {
print " The plant indignantly shakes the oil off its\n";
print "leaves and asks: \"Water?\"\n";
$flag[$f{'MSG_OIL_PLANT'}] = 0;
}
elsif ($flag[$f{'MSG_WATER_LITTLE'}]) {
print " You pour the water onto the little plant.\n";
print " The plant spurts into furious growth for a few seconds.\n";
$flag[$f{'MSG_WATER_LITTLE'}] = 0;
}
elsif ($flag[$f{'MSG_WATER_MED'}]) {
print " The plant grows explosively, almost filling the bottom\n";
print "of the pit.\n";
$flag[$f{'MSG_WATER_MED'}] = 0;
}
elsif ($flag[$f{'MSG_WATER_HUGE'}]) {
print " You've over-watered the plant! It's shriveling up!\n";
print "It's... it's... dying! It's disappeared!\n";
print "You murderer!\n";
$flag[$f{'MSG_WATER_HUGE'}] = 0;
}
elsif ($flag[$f{'MSG_CLIMB_MED'}]) {
print " You climb up the plant and out of the pit.\n";
$flag[$f{'MSG_CLIMB_MED'}] = 0;
}
elsif ($flag[$f{'MSG_CLIMB_HUGE'}]) {
print " You climb up the beanstalk and scurry through the\n";
print "hole in the ceiling of the cavern.\n";
$flag[$f{'MSG_CLIMB_HUGE'}] = 0;
}
if ($flag[$f{'MSG_NO_SNAKE'}]) {
print " The little bird attacks the green snake,\n";
print "and in an astounding flurry drives the snake away.\n";
$flag[$f{'MSG_NO_SNAKE'}] = 0;
}
if ($CurrentlyMessaging ne "") {
my $text = $message_desc{$CurrentlyMessaging};
my $name = ($NounDollar)? item_short_name($NounDollar): 'zebra';
$text =~ s/\$NOUN\$/${name}/i;
$CurrentlyMessaging = '';
my $back = href_it(pack_args());
print $text;
print "\n ${back}Back ${back}Back You look as ugly as ever.\n";
print_possessions();
$flag[$f{'VIEWING_SELF'}] = 0;
my $text = href_it(pack_args());
print "\n ${text}Back Dead end. ${text}Back A ${bridge}crystal bridge now spans the fissure. The top of a 12-foot-tall beanstalk is poking up out of\n";
print "the ${west}pit.\n";
}
elsif (($RoomNumber == $r{'e end of twopit room'}
or $RoomNumber == $r{'w end of twopit room'})
and ($flag[$f{'HUGE_PLANT'}]))
{
my $west = ($RoomNumber==$r{'e end of twopit room'})? 'west ': '';
print " There is a huge beanstalk growing out of the ${west}pit";
print " up to the hole.\n";
}
done_desc();
}
else {
++$DarknessCounter;
if ($DarknessCounter > 2 && rand(100) < 10) {
print "You fell into a pit and broke every bone in your body!\n";
print " ";
print href_start_over() . "Play again ";
my $rm_no = shift @_;
my $text = $room_desc[$rm_no];
my $linkn = 0;
@atoms = split(/(\[.*?\])/s, $text);
for my $i (0 .. $#atoms) {
if (substr($atoms[$i],0,1) eq '[') {
my @links = eval $room_links[$rm_no];
print $links[$linkn++];
print substr($atoms[$i], 1, -1);
print "";
}
else {
print $atoms[$i];
}
}
my $items = $room_contents[$RoomNumber];
if ($items != 0) {
print " \n";
}
while ($items != 0) {
my $current_item = $items % $MAXITEM;
my $text = $item_desc[$current_item];
$text = substr($text, 0, index($text,'#'));
@atoms = split(/(\[.*?\])/s, $text);
for my $i (0 .. $#atoms) {
if (substr($atoms[$i],0,1) eq '[') {
my $examine_link = href_ex($current_item);
print $examine_link;
print substr($atoms[$i], 1, -1);
print "";
}
else {
print $atoms[$i];
}
}
print " You are carrying: You are not carrying anything.\n";
}
if ($ihas_by_num[$n{'on lamp'}]) {
my $lamp = href_ex($n{'on lamp'});
my $turn_off = href_lamp_toggle();
print "Your ${lamp}lamp is ${turn_off}shining brightly. \n";
my $item = shift @_;
my $text = $item_desc[$item];
$text = substr($text, 1+index($text,'#'));
my $linkn = 0;
@atoms = split(/(\[.*?\])/s, $text);
for my $i (0 .. $#atoms) {
if (substr($atoms[$i],0,1) eq '[') {
my @links = eval $item_links[$item];
print $links[$linkn++];
print substr($atoms[$i], 1, -1);
print "";
}
else {
print $atoms[$i];
}
}
print "\n";
if (item_in_room($item) and ($item < 100)) {
my $tmp = $CurrentlyExamining;
$CurrentlyExamining = 0;
my $pickup_link = href_pickup($item);
$CurrentlyExamining = $tmp;
$_ = item_short_name($CurrentlyExamining);
my $it = (/.*s$/)? 'them': 'it';
print " ${pickup_link}\[Pick ${it} up]\n";
}
}
sub item_short_name($)
{
my $text = $item_desc[$_[0]];
my $idx = index($text, '[');
$text = substr($text, $idx+1, index($text,']')-$idx-1);
return $text;
}
sub is_treas($)
{
return 1 if ($_[0] == $n{'gold nugget'});
return 1 if ($_[0] == $n{'diamonds'});
return 1 if ($_[0] == $n{'jewelry'});
return 1 if ($_[0] == $n{'rare coins'});
return 1 if ($_[0] == $n{'silver bars'});
return 1 if ($_[0] == $n{'pearl'});
return 1 if ($_[0] == $n{'treasure chest'});
return 0;
}
sub ihas_treas($)
{
for my $i (1 .. $MAXITEM) {
if (is_treas($i) && $ihas_by_num[$i]) {
@list_treasures = (@list_treasures, $i);
}
}
if (@list_treasures > 0)
{ return $list_treasures[rand @list_treasures]; }
return 0;
}
sub item_in_room($) {
## If "picking it up" changes the room - it's here!
my $texto = pack_args();
my $tmp = $argsPickingUpThisItem;
$argsPickingUpThisItem = $_[0];
my $text = pack_args();
$argsPickingUpThisItem = $tmp;
return ($texto ne $text);
}
sub start_desc()
{
my $room_name = $room_by_num[$RoomNumber];
print "\nCave under construction beyond this point.
Witt construction company
Proceed at your own risk.
\n";
print "The oil streams away with the current.\n";
}
else {
print "
EOL
$flag[$f{'MSG_TRANSPORT'}] = 0;
}
elsif ($flag[$f{'MSG_JUMP_TO_DEATH'}]) {
print <
";
done_desc();
}
elsif ($flag[$f{'MSG_DROP_CAGE'}]) {
print "
\n";
}
elsif (($RoomNumber == $r{'e end of twopit room'}
or $RoomNumber == $r{'w end of twopit room'})
and ($flag[$f{'MED_PLANT'}]))
{
my $west = ($RoomNumber==$r{'e end of twopit room'})? 'west ': '';
print "
";
done_desc();
}
my $dark = href_say('DARK');
my $you = href_myself();
my $pits = href_say('PITS');
print "It is now ${dark}pitch dark. If you proceed".
" ${you}you will likely ${pits}fall into a pit.\n";
done_desc();
}
###############################################################
sub can_see_room()
{
return 1 if ($RoomNumber <= $r{'cobble crawl'});
return 1 if ($ihas_by_num[$n{'on lamp'}]);
return 1 if (item_in_room($n{'on lamp'}));
return 0;
}
sub print_room_description($)
{
print "
\n";
$items /= $MAXITEM;
}
}
sub print_possessions()
{
my $actually_carrying_anything = 0;
foreach my $current_item (1 .. $MAXITEM-1) {
next if ($ihas_by_num[$current_item] == 0);
if (! $actually_carrying_anything) {
print "
\n\n";
$actually_carrying_anything = 1;
}
my $item_name;
my $text = $item_desc[$current_item];
$text = substr($text, 0, index($text,'#'));
@atoms = split(/(\[.*?\])/s, $text);
for my $i (0 .. $#atoms) {
if (substr($atoms[$i],0,1) eq '[') {
$item_name = substr($atoms[$i], 1, -1);
last;
}
}
my $item_xlink = href_ex($current_item);
my $drop = href_drop($current_item);
print "
\n";
}
else {
print "
\n";
}
}
sub print_item_description($)
{
print "Error 404: bad CGI arguments.
\n";
die;
}