Adding initial work on Grue Hunter 2.0
authorJason Self <j@jxself.org>
Fri, 30 Sep 2016 21:09:42 +0000 (14:09 -0700)
committerJason Self <j@jxself.org>
Fri, 30 Sep 2016 21:09:42 +0000 (14:09 -0700)
13 files changed:
.gitignore [new file with mode: 0644]
.gitmodules [new file with mode: 0644]
README
build.sh [new file with mode: 0755]
gh.pl [deleted file]
grue-hunter.inf [new file with mode: 0644]
lib [new submodule]
objects/backpack.inf [new file with mode: 0644]
objects/coppercoin.inf [new file with mode: 0644]
objects/lantern.inf [new file with mode: 0644]
objects/lengthofrope.inf [new file with mode: 0644]
rooms/bottomofpit.inf [new file with mode: 0644]
rooms/northend.inf [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..6ea9c8b
--- /dev/null
@@ -0,0 +1 @@
+*.z5
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..dc70f3a
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "lib"]
+       path = lib
+       url = https://jxself.org/git/informlib.git
diff --git a/README b/README
index 512855a27bcd94548edef2698d1b7e9dca04876f..d78645105cd2588fcddf9925a44555a5f55b469d 100644 (file)
--- a/README
+++ b/README
@@ -1,34 +1,47 @@
-This directory contains version 1.0 of Grue Hunter.
+This directory contains version 2.0 of Grue Hunter.
 
-Homepage: http://jxself.org/grue-hunter.shtml
+Homepage: https://jxself.org/grue-hunter.shtml
 
 This file is part of Grue Hunter. See the end of the file for license 
 conditions.
 
        "It is pitch black. You are likely to be eaten by a grue."
 
-The Grue has eaten many adventurers. This game gives you a chance to get even.
+The Grue has eaten many adventurers. This game gives you a chance to 
+get even.
 
-Grue Hunter is a text adventure game written in Perl. You must make your way 
-through an underground cave system in search of the Grue. Can you capture it 
-and get out alive?
+To compile the game first pull in my modified version of the Inform 
+standard library:
 
-To run the program, type './gh.pl' from within the Grue Hunter directory.
+       git submodule init
+       git submodule update
 
-Copyright (C) 2013 Jason Self <j@jxself.org>
+You will also need my modified version of the Inform compiler from 
+https://jxself.org/git/?p=inform.git
 
-Grue Hunter gives you software freedom; you can copy, modify, convey,
-and/or redistribute it under the terms of the GNU Affero General Public
-License as published by the Free Software Foundation; either version 3 of 
-the License, or (at your option) any later version.
+Once the compiler has been compiled and is ready for use return to 
+this directory and run:
 
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
-for more details.
+       inform ++include_path=lib grue-hunter
 
-You should have received a copy of the GNU Affero General Public License 
-along with this program in a file called 'AGPLv3.txt'. If not, see
-http://www.gnu.org/licenses/agpl-3.0-standalone.html or write to the: Free
-Software Foundation, Inc., 51 Franklin St, Fifth Floor Boston, MA 
-02110-1301, USA.
+Or you can run the included build.sh script which does the same thing, 
+assuming that the inform compiler is included in your PATH.
+
+You will then get the Grue Hunter story file that can be run using 
+any appropriate Z-Machine interpreter, such as Frotz. Your GNU/Linux 
+distro probably has that packaged already for easy installation.
+
+Copyright (C) 2013, 2016 Jason Self <j@jxself.org>
+
+Grue Hunter gives you software freedom; you can copy, modify, convey, 
+and/or redistribute it under the terms of the GNU Affero General 
+Public License as published by the Free Software Foundation; either 
+version 3 of the License, or (at your option) any later version.
+
+Grue Hunter is distributed in the hope that it will be useful, but 
+WITHOUT ANY WARRANTY; without even the implied warranty of 
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
+Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public 
+License along with Grue Hunter. If not, see https://gnu.org/licenses/
diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..6a0aa2c
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env sh
+# This file is part of Grue Hunter.
+#
+# Grue Hunter is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Grue Hunter is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Grue Hunter. If not, see
+# <https://gnu.org/licenses/>.
+
+inform ++include_path=lib grue-hunter
diff --git a/gh.pl b/gh.pl
deleted file mode 100755 (executable)
index 6415800..0000000
--- a/gh.pl
+++ /dev/null
@@ -1,704 +0,0 @@
-#!/usr/bin/perl
-#
-# This file is part of Grue Hunter.
-#
-# Copyright (C) 2013 Jason Self <j@jxself.org>
-#
-# Grue Hunter gives you software freedom; you can copy, modify, convey,
-# and/or redistribute it under the terms of the GNU Affero General Public
-# License as published by the Free Software Foundation; either version 3 of 
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
-# for more details.
-#
-# You should have received a copy of the GNU Affero General Public License 
-# along with this program in a file called 'AGPLv3.txt'. If not, see
-# http://www.gnu.org/licenses/agpl-3.0-standalone.html or write to the: Free
-# Software Foundation, Inc., 51 Franklin St, Fifth Floor Boston, MA 
-# 02110-1301, USA.
-
-use strict;
-use warnings;
-
-my $instructions =  <<INSTRUCTIONS;
-\033[2J
-\033[0;0H
-Grue Hunter version 1.0
-Homepage: http://jxself.org/grue-hunter.shtml
-Copyright (C) 2013 Jason Self <j\@jxself.org>
-
-Grue Hunter gives you software freedom; you can copy, modify, convey,
-and/or redistribute it under the terms of the GNU Affero General Public
-License as published by the Free Software Foundation; either version 3 of
-the License, or (at your option) any later version.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program in a file called 'AGPLv3.txt'. If not, see
-http://www.gnu.org/licenses/
-%
-\033[2J
-\033[0;0H
-In this game you are a brave hunter. You are going to enter an underground 
-cave system in search of the Grue. If you can capture the Grue and get out 
-alive you will win the game.
-%
-Once in the cave system you can move around or shoot an arrow using the 
-commands 'move' and 'shoot' and any of the four compass directions. You can 
-also shorten the commands to 'm' and 's' and the directions to 'n', 's', 'e', 
-and 'w' for brevity. You may enter 'quit' or 'q' to end the game at any time.
-%
-But... There are other things in this cave system. Giant bats can pick you up 
-and drop you elsewhere. There are also bottomless pits. If you fall into one 
-of these you will never get out. There is also the Grue itself. Though not an 
-aggressive creature, it will eat you if you come too close. There are also 
-earthquakes that move things around (the bats, the bottomless pits, the Grue, 
-and the exit.)
-INSTRUCTIONS
-
-my $space = <<SPACE;
-The room here slopes downward. Old candles are scattered across the floor.
-An old fountain sits in the middle of the room. It is covered in rubble and dirt. A toppled statue lies to the right.
-The walls here are smooth. There is an old anvil here.
-The walls contain claw marks and some sort of graffiti in a language you cannot read. A crack in the ceiling above the middle of the north wall allows a trickle of water to flow down to the floor. The water pools near the base of the wall, and a rivulet runs along the wall and out into the hall. The water smells fresh.
-You push a heavy stone door open, revealing a room with pillars lining the wall. Several square holes have been cut into the walls.
-Stalactites drip down from the ceiling in sharp points while flowstone makes strange shapes on the floor. Rusting spikes line the walls.
-This room smells of rotting vegetation. Burning torches in iron sconces line the walls.
-The scent of smoke fills the room. A small hole to your left attracts your attention; but it is too small to be of any concern.
-A stream of oil flows from one side of the room to the other, in a small rut in the floor. There is a mysterious stain on the wall.
-This is the center of a narrow passage that connects other rooms. This room is about average size; but is filled with a pungent aroma that is very nauseating.
-There are cracks in the floor here. It is foggy, making it difficult to see.
-Thick cobwebs fill the corners of this room and wisps of webbing hang from the ceiling, wavering in a wind you can't feel. You notice a light humming sound.
-The floor is damp and looks quite slippery. You will need to be very careful here. A haze of smoke hangs in the air.
-This is a very large room with a large boulder in the center of it. Part of the wall has collapsed into this room.
-Several pieces of rotten fruit are scatted throughout the area. A hole has been dug into the wall. After looking inside you see that it doesn’t go anywhere.
-This room is very dusty, and you see footprints set in the dust. There are spiders on the walls.
-The passageway is very low; but if we crawl we can make it. After coming through the other side you see a stone stairway that goes up to the wall, where it abruptly ends.
-As you enter the room part of the ceiling collapses but you jump out of the way in time to avoid getting hurt. Duck your head in here; as large rock stalactites hang from the ceiling.
-This area is covered in rubble and dirt. There is a puddle and scraps of wood here.
-The floor is covered with sand and pottery shards.
-The walls have been engraved with geometric patterns. Fog gathers and swirls on the floor, concealing it.
-There is a salty, wet smell to this area. A small hole in the ceiling lets light from outside through ... But you would never fit through it.
-There are bones and several piece of rotting wood scattered here.
-It is misty here. Several empty flasks are scattered throughout the area.
-Rats run past you, in the direction you just came from. The floor here is covered in perfect hexagonal tiles.
-There are strange looking yellow stones here. Water drips through the ceiling.
-Your nostrils are overwhelmed by a sulphurous smell. The ceiling here is damp.
-Grime and filth smear this room. This area is filled with stalactites and stalagmites.
-This is a very dirty room; it was partially filled in by the last earthquake that hit. A slight breeze blows through this area.
-A shallow pit sits in the center of the room. The walls here have been engraved with spiral patterns.
-This cavern has a high, domed ceiling. There is a mold growing here.
-A slight, damp breeze blows through this area. This rooms smells of mildew.
-This area is very dusty. A dry well sits in the center of the room.
-As you enter this room some small rocks fall from the ceiling. Several broken arrows are scatted about.
-You are in a small passageway. The walls, ceiling and floor are composed of a smooth black stone. Illuminating your way is a silvery white glow coming from two long grooves midway up each wall that run the length of the passageway.
-You hear an eerie sound. Jagged steel blades project from cracks in the walls.
-Someone has scrawled the drawing of a door on the wall. A haze of dust hangs in the air.
-The walls are covered in slime. There is broken glass on the ground.
-There is a green slime on the floor. This room is very small; but I think we can make it through ok. 
-There is a stale smell here. Your steps echo here.
-This large room is illuminated by a low-burning fire pit. There is an iron sconce on the wall, but the torch has been removed.
-A rivulet of water slowly trickles from a hole in the wall. A narrow pit covered by iron bars lies in the center of the room.
-Several empty bottles lie on the floor. Water drips from the ceiling, landing on your head.
-You are in a low depression in the center of a medium-sized room. A flurry of bats suddenly fly past you as you enter. Their screeching fills your ears.
-Someone has left a lighted torch on the wall and it illuminates your passage. A liquid-filled pit sits in the center of the room and is so murky that you can't see its bottom. The room smells sour.
-This area is only a few feet high, but crawling on your stomach you make it through. You notice centipedes crawling along the wall.
-A rattling noise abruptly stops when you enter. Black mold grows on the walls and parts of the floor.
-You are in a small room with rocks and debris scattered everywhere. Part of the here ceiling has collapsed.
-A huge iron cage lies on its side in this room, and its gate rests open on the floor. A broken chain lies on the floor. This room has sour odor, like something rotten or fermented.
-An iron chandelier hangs from the ceiling. A old wooden barrel lies on its side, mostly collapsed.
-SPACE
-
-# Constants
-my $NORTH = 1;
-my $SOUTH = 2;
-my $EAST = 3;
-my $WEST = 4;
-
-# Update this constant to increase the number of rooms in the game.
-my $MAX_ROOMS = 50;
-
-# Update this constant if more room descriptions are added.
-my $MAX_ROOM_DESCRIPTIONS = 50;
-
-my $MAX_LINK_COUNT = 4;
-my $EARTHQUAKE = 3;
-my $EARTHQUAKE_CHANCE = 14;
-my $EVEN_CHANCE = 2;
-my $PIT_CHANCE = 32;
-
-my $SET = 1;
-my $RESET = 0;
-
-my $CLOSED = -1;
-my $GRUE = -2;
-my $EXIT = -3;
-my $BAT1 = -4;
-my $BAT2 = -5;
-my $PIT1 = -6;
-my $PIT2 = -7;
-
-# Game State
-my $grue_location = $CLOSED;
-my $exit_location = $CLOSED;
-my $bat1_location = $CLOSED;
-my $bat2_location = $CLOSED;
-my $pit1_location = $CLOSED;
-my $pit2_location = $CLOSED;
-my $player_location = $CLOSED;
-my $grue_bagged = 0;
-
-# Game Space
-my @rooms = ();
-
-sub randomize_rooms {
-       my @room_descriptions = split(/\n/, $space);
-       my %random_hash = ();
-       my $random_room = 0;
-       my $random_room_description = 0;
-       
-       for (my $i = 0; $i < $MAX_ROOMS;) {
-               $random_room = int(rand($MAX_ROOMS));
-               $random_room_description = int(rand($MAX_ROOM_DESCRIPTIONS));
-               
-               if (!$random_hash{$random_room}) {
-                       $random_hash{$random_room} = 1;
-                       my %room = ();
-                       $room{'description'} = $room_descriptions[$random_room_description];
-                       $room{$NORTH} = $CLOSED;
-                       $room{$SOUTH} = $CLOSED;
-                       $room{$EAST} = $CLOSED;
-                       $room{$WEST} = $CLOSED;
-                       $room{'link_count'} = 0;
-                       $rooms[$i] = \%room;
-                       $i++;
-               }
-       }
-}
-
-sub connect_rooms {
-       my $current_link_count = 0;
-       my $random_link_count = 0;
-       my $rooms_left_to_link = 0;
-       my $room_direction_state = 0;
-       my $next_room = 0;
-       
-       for (my $i = 0; $i < $MAX_ROOMS;) {
-       
-               # Take into consideration current link count and get random link count.
-               $current_link_count = $rooms[$i] -> {'link_count'};
-               if ($current_link_count < $MAX_LINK_COUNT) {
-                       $random_link_count = int(rand($MAX_LINK_COUNT - $current_link_count)) + 1;
-                       
-                       # Check that there are enough rooms left to link. If there are not
-                       # then substitute the random link count with the rooms left to link.
-                       $rooms_left_to_link = $MAX_ROOMS - $i;
-                       if ($random_link_count >= $rooms_left_to_link) {
-                               $random_link_count = $rooms_left_to_link;
-                       }
-               }
-               
-               # If the room is fully linked then set the random link count to 0.
-               else {
-                       $random_link_count = 0;
-               }
-               
-               # For each room create links upto a random link count by going through
-               # the vacant compass directions.
-               for (my $j = 0; $j < $random_link_count; $j++) {
-                       for (my $k = 1; $k < 5; $k++) {
-                               if ($i < $MAX_ROOMS) {
-                                       $room_direction_state = $rooms[$i] -> {$k};
-                                       if ($room_direction_state == $CLOSED) {
-                                               $next_room = $i + 1;
-                                               if ($next_room < $MAX_ROOMS) {
-                                                       $rooms[$i] -> {$k} = $next_room;
-                                                       $rooms[$next_room] -> {opposite($k)} = $i;
-                                               }
-                                               $i = $next_room;
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-sub place_directional_object {
-       my $room_number = shift;
-       my $object = shift;
-       my $direction;
-       
-       # Get a random direction and set the object in a random room direction.
-       $direction = int(rand(3)) + 1;
-       $rooms[$room_number] -> {$direction} = $object;
-       
-       # Update the room's link count
-       ($rooms[$room_number] -> {'link_count'})++;
-
-       if ($object == $GRUE) {
-               $grue_location = $room_number;
-       }
-       elsif ($object == $EXIT) {
-               $exit_location = $room_number;
-       }
-       elsif ($object == $PIT1) {
-               $pit1_location = $room_number;
-       }
-       elsif ($object == $PIT2) {
-               $pit2_location = $room_number;
-       }
-}
-
-sub get_random_rooms {
-       my $number_of_rooms = shift;
-       my $random_num = 0;
-       my %random_hash = ();
-       my @room_numbers = ();
-
-       for (my $i = 0; $i < $number_of_rooms;) {
-               $random_num = int(rand($MAX_ROOMS));
-               
-               if (!$random_hash{$random_num}) {
-                       $random_hash{$random_num} = 1;
-                       $room_numbers[$i] = $random_num;
-                       $i++;
-               }
-       }
-       return \@room_numbers;
-}
-
-sub set_state {
-       my $set = shift;
-       my $number_of_rooms;
-       my $room_numbers;
-       
-       if ($grue_bagged) {
-               $number_of_rooms = 5;
-       }
-       else {
-               $number_of_rooms = 6;
-       }
-       
-       $room_numbers = get_random_rooms($number_of_rooms);
-       
-       # Bats are non-directional objects and are placed in rooms. Since they are
-       # non-directional they do not occupy a compass direction and do not add to the
-       # room's link count. They are simply assigned to the Game State variables.
-       $bat1_location = @$room_numbers[0];
-       $bat2_location = @$room_numbers[1];
-       
-       # The Grue, Pits and Exit are directional objects, placed in rooms. They
-       # are directional they occupy compass dirctions and are added to the room's
-       # link count. In addition they are assigned to the Game State variables. The
-       # Grue is only placed in a room again if it has not been bagged.
-       place_directional_object(@$room_numbers[2], $PIT1);
-       place_directional_object(@$room_numbers[3], $PIT2);
-       place_directional_object(@$room_numbers[4], $EXIT);
-       if (!$grue_bagged) {
-               place_directional_object(@$room_numbers[5], $GRUE);
-       }
-       # If the game state is being set for the first time, then the player's
-       # location is set to the same location as the Exit.
-       if ($set) {
-               $player_location = @$room_numbers[4];
-       }
-}
-
-sub opposite {
-       my $direction = shift;
-       
-       if ($direction == $NORTH) {
-               return $SOUTH;
-       }
-       elsif ($direction == $SOUTH) {
-               return $NORTH;
-       }
-       elsif ($direction == $EAST) {
-               return $WEST;
-       }
-       elsif ($direction == $WEST) {
-               return $EAST;
-       }
-       else {
-               return 0;
-       }
-}
-
-sub action_handler {
-       my ($action, $sub_action) = @_;
-       my $action_success = 0;
-       
-       if (defined $action) {
-               $action = lc($action);
-       
-               # If the sub action (direction) is defined.
-               if (defined $sub_action) {
-                       $sub_action = lc($sub_action);
-                       
-                       # If sub action (direction) is a valid direction.
-                       if (is_direction($sub_action)) {
-                               if ($sub_action eq 'q' || $action eq 'quit') {
-                                       quit();
-                               }
-                               elsif ($action eq 'm' || $action eq 'move') {
-                                       move_player($sub_action);
-                                       $action_success = 1;
-                               }
-                               elsif ($action eq 's' || $action eq 'shoot') {
-                                       shoot($sub_action);
-                                       $action_success = 1; 
-                               }
-                       }
-                       
-                       # If the sub action (direction) is not a valid direction.
-                       else {
-                               print "Enter 'N', 'S', 'E' OR 'W'.\n";
-                               if ($action eq 'm' || $action eq 'move') {
-                                       move_player();
-                               }
-                               elsif ($action eq 's' || $action eq 'shoot') {
-                                       shoot();
-                               }
-                       }
-                       
-                       if ($action_success) {
-                               my $random_num = 0;
-                               $random_num = int(rand($EARTHQUAKE_CHANCE));
-                               
-                               if ($random_num == $EARTHQUAKE) {
-                                       print "\n<<<EARTHQUAKE>>>\n\n";
-                                       randomize_rooms();
-                                       set_state($RESET);
-                                       connect_rooms();
-                               }
-                               
-                               describe_location();
-                       }
-               }
-               # If the sub action (direction) is not defined.
-               else {
-                       if ($action eq 'm' || $action eq 'move') {
-                               move_player();
-                       }
-                       elsif ($action eq 's' || $action eq 'shoot') {
-                               shoot();
-                       }
-                       elsif ($action eq 'q' || $action eq 'quit') {
-                               quit();
-                       }
-               }
-       }
-}
-
-sub display_text {
-       $| = 1;
-       my $text = shift;
-       for my $word (split/%/, $text) {
-               print $word."\n";
-               print 'Press enter when ready to continue: ';
-               <STDIN>;
-       }
-       print "\033[2J";
-       print "\033[0;0H";
-       print "\t\t\t\t".'***********************'."\n";
-       print "\t\t\t\t".'***                 ***'."\n";
-        print "\t\t\t\t".'***   GRUE HUNTER   ***'."\n";
-       print "\t\t\t\t".'***                 ***'."\n";
-       print "\t\t\t\t".'***********************'."\n\n";
-}
-
-sub read_input {
-       my $action;
-       my @actions;
-       $action = <>;
-       @actions = split(/\s+/, $action);
-       return @actions;
-}
-
-sub is_direction {
-       my $direction = shift;
-       if (defined $direction) {
-               return (
-                       $direction eq 'n' or
-                       $direction eq 'north' or
-                       $direction eq 's' or
-                       $direction eq 'south' or
-                       $direction eq 'e' or
-                       $direction eq 'east' or
-                       $direction eq 'w' or
-                       $direction eq 'west' or
-                       $direction eq 'q' or
-                       $direction eq 'quit'
-               );
-       }
-       return '';
-}
-
-sub direction {
-       my $direction = shift;
-       
-       if ($direction == $NORTH) {
-               return 'north';
-       }
-       elsif ($direction == $SOUTH) {
-               return 'south';
-       }
-       elsif ($direction == $EAST) {
-               return 'east';
-       }
-       elsif ($direction == $WEST) {
-               return 'west';
-       }
-       else {
-               return '';
-       }
-}
-
-sub move_player {
-       my $sub_action = shift;
-       my $direction;
-       my $room_direction;
-       
-       if (defined $sub_action) {
-               if ($sub_action eq 'n' || $sub_action eq 'north') {
-                       $direction = $NORTH;
-               }
-               elsif ($sub_action eq 's' || $sub_action eq 'south') {
-                       $direction = $SOUTH;
-               }
-               elsif ($sub_action eq 'e' || $sub_action eq 'east') {
-                       $direction = $EAST;
-               }
-               elsif ($sub_action eq 'w' || $sub_action eq 'west') {
-                       $direction = $WEST;
-               }
-               
-               $room_direction = $rooms[$player_location] -> {$direction};
-               
-               # If the room that the player wants to move to is a room.
-               if ($room_direction > $CLOSED) {
-               
-                       # Check if the room has a bat.
-                       if ($room_direction == $bat1_location || $room_direction == $bat2_location) {
-                               print "Bats have you now.\n";
-                               print "They're lifting you up.\n";
-                               print "Ohhhh, where are we now?\n";
-                               
-                               my $number_of_rooms = 2;
-                               my $room_numbers = get_random_rooms($number_of_rooms);
-                               
-                               # Change player location (to where the bat dropped the player).
-                               $player_location = @$room_numbers[0];
-                               
-                               # Change location of offending bat.
-                               if ($room_direction == $bat1_location) {
-                                       $bat1_location = @$room_numbers[1];
-                               }
-                               else {
-                                       $bat2_location = @$room_numbers[1];
-                               }
-                       }
-                       
-                       # If free of bats, go ahead and move into the room.
-                       else {
-                               print "OK...\n";
-                               $player_location = $room_direction;
-                       }
-               }
-               elsif ($room_direction == $CLOSED) {
-                       print "You cannot go that way.\n";
-               }
-               elsif ($room_direction == $GRUE) {
-                       print "You bumped into the Grue.\n";
-                       print "He ate you before you could move.\n";
-                       quit();
-               }
-               elsif ($room_direction == $EXIT) {
-                       if ($grue_bagged) {
-                               print "You have reached the exit with your Grue.\n";
-                               print "Your supper will be filling tonight for sure!\n";
-                       }
-                       else {
-                               print "You have reached the exit without any Grue.\n";
-                               print "You are sure to starve.\n";
-                       }
-                       quit();
-               }
-               elsif ($room_direction < $PIT1) {
-                       my $pit_chance = int(rand($PIT_CHANCE));
-                       if ($pit_chance) {
-                               print "This room contains a bottomless pit. Part of the ground around it gave way when you entered and you almost fell in.\n";
-                               print "Be more careful next time!\n";
-                               $player_location = $room_direction;
-                       }
-                       else {
-                               print "You fell into a bottomless pit.\n";
-                               print "You fell a loooooong way...\n";
-                               quit();
-                       }
-               }
-       }
-       else {
-               my @actions;
-               print "Move which way?\n";
-               @actions = read_input();
-               action_handler('m', $actions[0]);
-       }
-}
-
-sub shoot {
-       my $sub_action = shift;
-       my $direction;
-       my $room_direction;
-       
-       if (defined $sub_action) {
-               if ($sub_action eq 'n' || $sub_action eq 'north') {
-                       $direction = $NORTH;
-               }
-               elsif ($sub_action eq 's' || $sub_action eq 'south') {
-                       $direction = $SOUTH;
-               }
-               elsif ($sub_action eq 'e' || $sub_action eq 'east') {
-                       $direction = $EAST;
-               }
-               elsif ($sub_action eq 'w' || $sub_action eq 'west') {
-                       $direction = $WEST;
-               }
-               
-               $room_direction = $rooms[$player_location] -> {$direction};
-               
-               # If the arrow was shot in a direction without the Grue.
-               if ($room_direction == $CLOSED) {
-                       print "Clunk!\n";
-                       print "The arrow bounced off the wall.\n";
-               }
-               # If the arrow was shot in a direction of the Grue.
-               elsif ($room_direction == $GRUE) {
-                       my $shot = int(rand($EVEN_CHANCE));
-                       if ($shot) {
-                               print "You caught the Grue!\n";
-                               print "Now to find a way out...\n";
-                               $grue_bagged++;
-                               
-                               # Remove the Grue from the Room once bagged. Set the Grue
-                               # location to an undefined state (the Grue object -2).
-                               $rooms[$player_location] -> {$direction} = $CLOSED;
-                               ($rooms[$player_location] -> {'link_count'})--;
-                               $grue_location = $GRUE;
-                       }
-                       else {
-                               print "The arrow missed the Grue.\n";
-                       }
-               }
-               else {
-                       print "The arrow missed the Grue.\n";
-               }
-       }
-       else {
-               my @actions;
-               print "Shoot which way?\n";
-               @actions = read_input();
-               action_handler('s', $actions[0]);
-       }
-}
-
-sub describe_location {
-       my $room_direction;
-       
-       print $rooms[$player_location] -> {'description'} . "\n";
-# print "Player Location: $player_location\n";
-# print "Grue Location: $grue_location\n";
-# print "Bat 1 Location: $bat1_location\n";
-# print "Bat 2 Location: $bat2_location\n";
-# print "Pit 1 Location: $pit1_location\n";
-# print "Pit 2 Location: $pit2_location\n";
-# print "Exit Location: $exit_location\n";
-       
-       print 'I see passages to the ';
-       my @passages;
-       for (my $i = 1; $i < 5; $i++) {
-               $room_direction = $rooms[$player_location] -> {$i};
-               if ($room_direction != $CLOSED) {
-                       push(@passages, direction($i));
-               }
-       }
-       
-       for (my $i = 0; $i < $#passages + 1; $i++) {
-               if ($i == 0) {
-                       print $passages[$i];
-               }
-               elsif ($i < $#passages) {
-                       print ', ' . $passages[$i];
-               }
-               elsif ($i == $#passages) {
-                       print ' and ' . $passages[$i];
-               }
-       }
-       print ". Choose wisely.\n";
-       
-       # If the Grue is in the player's current location.
-       if ($player_location == $grue_location) {
-               print "I smell the Grue!\n";
-       }
-       # If either pit is in the player's current location.
-       elsif ($player_location == $pit1_location || $player_location == $pit2_location) {
-               print "I feel a draft. A bottomless pit must be nearby. Be careful not to fall in.\n";
-       }
-       # If the Exit is in the player's current location, tell the player which
-       # direction the Exit is located.
-       elsif ($player_location == $exit_location) {
-               for (my $i = 1; $i < 5; $i++) {
-                       $room_direction = $rooms[$player_location] -> {$i};
-                       if ($room_direction == $EXIT) {
-                               print 'The exit is to the ' . direction($i) . ".\n";
-                       }
-               }
-       }
-       # Check the adjacent rooms for the Exit, Grue, Bats and Pits. Here
-       # check whether the adjacent rooms are equivalent to the game state
-       # variables for the Exit, Grue, Bats and Pits.
-       else {
-               for (my $i = 1; $i < 5; $i++) {
-                       $room_direction = $rooms[$player_location] -> {$i};
-                       if ($room_direction > $CLOSED) {
-                               if ($room_direction == $exit_location) {
-                                       print "Exit nearby...\n";
-                               }
-                               elsif ($room_direction == $grue_location) {
-                                       print "I smell the Grue!\n";
-                               }
-                               # If the room adjacent contains one of the two bats then warn the player.
-                               elsif ($room_direction == $bat1_location || $room_direction == $bat2_location) {
-                                       print "I hear bats flying around in the distance. Be careful or they may grab you and carry you away.\n";
-                               }
-                               # If the room adjacent contains one of the two pits then warn the player.
-                               elsif ($room_direction == $pit1_location || $room_direction == $pit2_location) {
-                                       print "I feel a draft. A bottomless pit must be nearby. Be careful not to fall in.\n";
-                               }
-                       }
-               }
-       }
-}
-
-sub quit {
-       exit;
-}
-
-sub main {
-       my @actions;
-       
-       display_text($instructions);
-       randomize_rooms();
-       set_state($SET);
-       connect_rooms();
-       describe_location();
-       while (1) {
-               print "Move or shoot?\n";
-               @actions = read_input();
-               action_handler(@actions);
-       }
-}
-
-main();
diff --git a/grue-hunter.inf b/grue-hunter.inf
new file mode 100644 (file)
index 0000000..76136e7
--- /dev/null
@@ -0,0 +1,65 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it 
+! under the terms of the GNU Affero General Public License as published 
+! by the Free Software Foundation, either version 3 of the License, or 
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but 
+! WITHOUT ANY WARRANTY; without even the implied warranty of 
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Global fuel_left = 20;
+Constant NO_SCORE;
+Constant DEATH_MENTION_UNDO;
+Constant Story "Grue Hunter";
+Constant Headline "^By Jason Self^
+This game gives you freedom; you can change and share it under the 
+terms of the GNU Affero General Public License as published by the 
+Free Software Foundation, either version 3 of the License, or (at your 
+option) any later version. See the GNU Affero General Public License 
+for details.^
+IFID 7521C1FD-B60F-4CA3-BCE6-59A42929BA78^";
+Include "parser";
+Include "verblib";
+Release 0;
+Serial "160930";
+
+Include "rooms/bottomofpit.inf";
+Include "rooms/northend.inf";
+
+Include "objects/backpack.inf";
+Include "objects/coppercoin.inf";
+Include "objects/lantern.inf";
+Include "objects/lengthofrope.inf";
+
+[ Initialise;
+       location = bottomofpit;
+       move backpack to player;
+       give backpack worn;
+       StartTimer(lantern, fuel_left);
+       thedark.description = "It is pitch black. You are likely to be eaten by a grue.";
+"^A ferocious grue has been attacking your village for the past few 
+weeks, taking a new person each night under cover of darkness. Despite 
+their best efforts your fellow villagers have been unable to stop it. 
+Three nights ago the grue came again and took your last parent. After 
+three days of grief, you decide to try to stop it and enter the cave 
+where it lives. After filling your trusty backpack with needed 
+supplies you depart in the early morning. Approaching the large hole 
+in the ground that serves as an entance to the underground cave you 
+tie your rope around a large rock and rapel down. About halfway down, 
+you look up and notice someone standing near that rock. With the sun 
+shining from behind them you can't make out who it is but they quickly 
+chop your rope and you fall the rest of the way to the bottom of the 
+pit. You pass out from the fall and once you wake up the person is 
+gone. There's no way you'll be able to get back out the way you 
+came.^";
+
+];
+
+Include "grammar";
diff --git a/lib b/lib
new file mode 160000 (submodule)
index 0000000..b56d0b7
--- /dev/null
+++ b/lib
@@ -0,0 +1 @@
+Subproject commit b56d0b7e8cda9be5a08886c71ec68460569140bf
diff --git a/objects/backpack.inf b/objects/backpack.inf
new file mode 100644 (file)
index 0000000..33de190
--- /dev/null
@@ -0,0 +1,20 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public 
+! License along with Grue Hunter. If not, see 
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object backpack "backpack" bottomofpit
+with   name 'backpack' 'pack' 'knapsack' 'rucksack',
+        description "A nice cotton canvas bag with two straps that go over your shoulders.",
+has    clothing container openable;
diff --git a/objects/coppercoin.inf b/objects/coppercoin.inf
new file mode 100644 (file)
index 0000000..055aa2b
--- /dev/null
@@ -0,0 +1,22 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object coppercoin "copper coin" northend
+with   name 'copper' 'coin' 'zorkmid',
+       description "The coin seems to be very old, in very poor condition, 
+       and somewhat irregular in shape. The only things clearly visible are 
+       what appears to be a name on one side: Belwit The Flat and a date on 
+       the other: 699 GUE.";
diff --git a/objects/lantern.inf b/objects/lantern.inf
new file mode 100644 (file)
index 0000000..8805f6b
--- /dev/null
@@ -0,0 +1,53 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object lantern "copper lantern" backpack
+with   name 'lantern' 'copper' 'lamp' 'light',
+        description [;
+               print "This is an exceptionally beautiful lamp. About 
+               eleven inches high, with a base of about 5 inches or so in diameter 
+               and a large, brass-closed hook at the top. The glass in the lamp has a 
+               fresnel type of design, which is used to distribute light widely. It 
+               appears to have been damaged in your fall and ";
+
+                       if (fuel_left > 0) print "is leaking fuel. ";
+                       else print "all the fuel has leaked out. ";
+
+               print "The words ~Manufactured By The Frobozz Magic 
+               Lantern Company~ are engraved in the base.^^";
+               ],
+
+       time_left,
+       time_out [;
+               if (lantern has on) print "The lantern has run out of fuel and is now off.";
+               fuel_left = 0;
+               give lantern ~on;
+               give lantern ~light;
+               ],
+
+       after [;
+               SwitchOn:
+                       if (fuel_left > 0) give lantern light;
+                       else {
+                               print "The lantern is out of fuel and cannot be turned on. 
+                               Perhaps there is a place to refuel?^";
+                               rtrue;
+                            }
+               SwitchOff:
+                       give lantern ~light;
+               ],
+
+has    switchable;
diff --git a/objects/lengthofrope.inf b/objects/lengthofrope.inf
new file mode 100644 (file)
index 0000000..c79c99c
--- /dev/null
@@ -0,0 +1,24 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object lengthofrope "rope" bottomofpit
+with   name 'rope',
+       description "It is the other part of the rope you climbed down on, now shorter after having been chopped in two.",
+               describe [;
+                       if (self in bottomofpit) rtrue;
+                       "^You can see your rope here.";
+               ],
+has    clothing;
diff --git a/rooms/bottomofpit.inf b/rooms/bottomofpit.inf
new file mode 100644 (file)
index 0000000..3ae22ba
--- /dev/null
@@ -0,0 +1,34 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object bottomofpit "Bottom Of Pit"
+with   description [;
+       print "You are at the south end of a north/south tunnel that also 
+       serves as the bottom of a large hole in the ground above. The tunnel 
+       continues to the north, and the ground slopes slightly downward in 
+       that direction. The walls here are dull and gray, smooth but damp, 
+       slowly turning into large chunky rocks toward the north.";
+
+               if (lengthofrope in self) print " Part of your rope, at least the 
+               part that you were holding onto when it was chopped in two, lies on 
+               the ground here.";
+               new_line;
+               ],
+
+       n_to northend,
+       u_to "The ground above is too far away and there's nothing for a foothold to climb.",
+
+has    light;
diff --git a/rooms/northend.inf b/rooms/northend.inf
new file mode 100644 (file)
index 0000000..8526b1b
--- /dev/null
@@ -0,0 +1,31 @@
+! This file is part of Grue Hunter.
+!
+! Grue Hunter is free software: you can redistribute it and/or modify it
+! under the terms of the GNU Affero General Public License as published
+! by the Free Software Foundation, either version 3 of the License, or
+! (at your option) any later version.
+!
+! Grue Hunter is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public
+! License along with Grue Hunter. If not, see
+! <https://gnu.org/licenses/>.
+!===================================================================
+Object northend "North End"
+with   description "You are at the north end of a north/south tunnel that 
+       also branches off in a T intersection as smaller tunnels to the west 
+       and east. The ceiling here is damp and the area smells of mildew. The 
+       walls consist of large, chunky rocks which become smaller toward the 
+       south, eventually becoming nothing more than smooth, gray, dull dirt 
+       walls. The ground here slopes slightly upward to the south.",
+
+       s_to bottomofpit,
+
+       before [;
+               Smell: "You smell the odor of mildew.";
+               ],
+
+has    light;