aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorculot <culot@FreeBSD.org>2018-07-27 11:22:11 +0200
committerculot <culot@FreeBSD.org>2018-07-27 11:22:11 +0200
commit2b3b9dc4649727851004b8223b6af38b57c0c790 (patch)
tree418867a8ac458e7b0a7fcaca90b551628a8e6810
downloadoldrunner-2b3b9dc4649727851004b8223b6af38b57c0c790.tar.gz
oldrunner initial import
-rw-r--r--ChangeLog20
-rw-r--r--GNUmakefile65
-rw-r--r--README21
-rw-r--r--TODO13
-rw-r--r--bricks.c169
-rw-r--r--cfg.h61
-rw-r--r--compat.h56
-rw-r--r--compat/fgetln.c86
-rw-r--r--compat/queue.h527
-rw-r--r--compat/strtonum.c65
-rwxr-xr-xconfigure78
-rw-r--r--coord.c117
-rw-r--r--foes.c290
-rw-r--r--game.c297
-rw-r--r--gfx.c448
-rw-r--r--hero.c188
-rw-r--r--io.c86
-rw-r--r--levels/original.lvl3155
-rw-r--r--lvl.c602
-rw-r--r--mem.c96
-rw-r--r--money.c100
-rwxr-xr-xoldrunner.6102
-rw-r--r--oldrunner.c86
-rw-r--r--oldrunner.h282
-rw-r--r--timer.c95
-rw-r--r--usr.c113
26 files changed, 7218 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..bf31bb8
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,20 @@
+2012-01-31 Frederic Culot <frederic@culot.org>
+
+ * Fix a display issue which caused part of the game board to be
+ hidden on wide screens.
+
+ * Fix an erroneous check which could lead to an out of bounds
+ access on the curlvl->lay array.
+
+2012-01-06 Frederic Culot <frederic@culot.org>
+
+ * Fix the sprite enum to avoid indexes past the end of arrays such
+ as with the SP_INVALID element in sprites_init().
+
+2010-07-17 Frederic Culot <frederic@culot.org>
+
+ * first public release
+
+2010-04-01 Frederic Culot <frederic@culot.org>
+
+ * beginning of the project
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..07ed10c
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,65 @@
+# $Id: GNUmakefile,v 1.4 2012/01/06 10:13:55 culot Exp $
+
+VERSION= 20120131
+
+PRJ= $(shell basename `pwd`)
+EXE= $(PRJ)
+BAK= $(PRJ)-$(shell date '+%Y%m%d-%H%M').tar.gz
+PKG= $(PRJ)-$(VERSION).tar.gz
+SRCDIR= ./
+
+CC?= gcc
+CFLAGS+= -Wall -DVERSION="\"$(VERSION)\""
+LDFLAGS+=
+LIBS+=
+
+#FDEBUG= 1
+
+ifdef FDEBUG
+CFLAGS+= -g -ggdb -DDEBUG
+endif
+
+SRCS= $(wildcard $(SRCDIR)/*.c)
+-include config.mk
+OBJ= $(SRCS:.c=.o)
+
+
+all: $(EXE)
+
+$(EXE): $(OBJ)
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+backup: clean-all
+ @cd .. && tar czvf $(BAK) $(PRJ) >/dev/null && mv $(BAK) $(PRJ)
+ @echo "==> Backup created: $(BAK)"
+
+dist: clean-all
+ @cd .. && tar -czvf $(PKG) --exclude='CVS' $(PRJ) >/dev/null && mv $(PKG) $(PRJ)
+ @echo "==> Package created: $(PKG)"
+
+clean-all: clean
+ @rm -f config.mk config.h TAGS
+
+clean:
+ @rm -f $(OBJ) $(EXE)
+ @rm -f core
+ @rm -f *.gz
+ @echo "==> Project cleaned"
+
+tags:
+ @etags *.[ch]
+ @echo "==> Tags generated"
+
+count:
+ @wc -l *.[ch]
+
+list-todo:
+ @grep -n XXX *.[ch]
+
+list-targets:
+ @cat GNUmakefile | grep -E ^[^[:space:]\.$$%]+: | cut -d: -f1
+
+.PHONY: all backup dist clean clean-all tags count list-todo list-targets
diff --git a/README b/README
new file mode 100644
index 0000000..0f5c066
--- /dev/null
+++ b/README
@@ -0,0 +1,21 @@
+Oldrunner is a text-mode remake of the Loadrunner game from Broderbund and
+contains the 150 original game levels. See the manpage for more information.
+
+INSTALL
+ To compile oldrunner, first run the configure script and then compile the
+ game using 'gmake' or 'make' depending on your system.
+
+LICENSE
+ The game is released under the BSD License. The original game levels are
+ copyright (c)1994 Presage Software Development Co.; all rights reserved.
+
+THANKS
+ Thanks go to:
+
+ * Joshua Neal for the 'lodetool' software which allowed the convertion of
+ the original game levels to human-readable ascii ones.
+
+ * Nicholas Marriott for the tmux configuration script which greatly inspired
+ the configure script distributed with oldrunner.
+
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..ce71a4c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,13 @@
+
+ oldrunner TODO list
+ -------------------
+
+Here are listed the modifications I should perform on loderunner in future
+releases. Feel free to send me an email/patch (frederic@culot.org) if you
+would like to see a feature added.
+
+
+ * Add a command-line flag to set game difficulty (acting on FOES_DELAY, BRICK_LATENCY...)
+ * Add support for high-scores recording
+ * Allow user to pause the game
+ * Make it possible to load user-created levels
diff --git a/bricks.c b/bricks.c
new file mode 100644
index 0000000..3060c21
--- /dev/null
+++ b/bricks.c
@@ -0,0 +1,169 @@
+/* $Id: bricks.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+#define BRICK_LATENCY (OLDRUNNER_TIMEOUT * 4)
+
+enum brick_state {
+ BRICK_SMALL_CRACK,
+ BRICK_LARGE_CRACK,
+ BRICK_BROKEN,
+ BRICK_COMEBACK_LARGE_CRACK,
+ BRICK_COMEBACK_SMALL_CRACK,
+ BRICK_REBUILT,
+ BRICK_STATES
+};
+
+struct brick {
+ enum brick_state state;
+ struct timer timer;
+ struct coord pos;
+ SLIST_ENTRY(brick) bricksp;
+};
+
+SLIST_HEAD(, brick) bricks;
+
+void
+bricks_init (void)
+{
+ SLIST_INIT (&bricks);
+}
+
+void
+bricks_free (void)
+{
+ while (!SLIST_EMPTY (&bricks))
+ {
+ struct brick *b;
+
+ b = SLIST_FIRST (&bricks);
+ SLIST_REMOVE_HEAD (&bricks, bricksp);
+ xfree (b);
+ }
+}
+
+void
+bricks_break (const struct coord *pos)
+{
+ struct brick *b;
+
+ b = xmalloc (sizeof *b);
+ coord_set_yx (&b->pos, pos->y, pos->x);
+ b->state = BRICK_SMALL_CRACK;
+ timer_start (&b->timer);
+ SLIST_INSERT_HEAD (&bricks, b, bricksp);
+}
+
+static void
+draw_brick (const struct coord *pos, enum brick_state state)
+{
+ switch (state)
+ {
+ case BRICK_SMALL_CRACK:
+ case BRICK_COMEBACK_SMALL_CRACK:
+ gfx_show_sprite (SP_BRICK_SCRACK, pos);
+ break;
+ case BRICK_LARGE_CRACK:
+ case BRICK_COMEBACK_LARGE_CRACK:
+ gfx_show_sprite (SP_BRICK_LCRACK, pos);
+ break;
+ case BRICK_BROKEN:
+ if (hero_at_pos (pos))
+ gfx_show_sprite (SP_HERO, pos);
+ else if (foes_at_pos (pos))
+ gfx_show_sprite (SP_FOE, pos);
+ else
+ gfx_show_sprite (SP_BRICK_BROKEN, pos);
+ break;
+ case BRICK_REBUILT:
+ gfx_show_sprite (SP_BRICK, pos);
+ break;
+ default:
+ return;
+ /* NOTREACHED */
+ }
+}
+
+void
+bricks_draw (void)
+{
+ struct brick *b;
+
+ SLIST_FOREACH (b, &bricks, bricksp)
+ draw_brick (&b->pos, b->state);
+}
+
+unsigned
+bricks_broken_at (const struct coord *pos)
+{
+ struct brick *b;
+
+ SLIST_FOREACH (b, &bricks, bricksp)
+ {
+ if (b->state == BRICK_BROKEN && coord_equal (&b->pos, pos))
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+bricks_update (void)
+{
+ struct brick *b;
+ struct timer now;
+
+ timer_get_time (&now);
+ SLIST_FOREACH (b, &bricks, bricksp)
+ {
+ double difftot;
+
+ difftot = timer_diff (&now, &b->timer);
+ if (difftot > BRICK_LATENCY)
+ {
+ timer_set (&now, &b->timer);
+ b->state++;
+ if (b->state == BRICK_BROKEN)
+ {
+ hero_dig_done ();
+ timer_add (&b->timer, BRICK_COMEBACK_TIME);
+ }
+ else if (b->state > BRICK_REBUILT)
+ {
+ foes_wallup_at (&b->pos);
+ if (!hero_wallup_at (&b->pos))
+ SLIST_REMOVE (&bricks, b, brick, bricksp);
+ }
+ }
+ }
+}
diff --git a/cfg.h b/cfg.h
new file mode 100644
index 0000000..79d64a1
--- /dev/null
+++ b/cfg.h
@@ -0,0 +1,61 @@
+/* $Id: cfg.h,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define CTRLVAL 0x1F
+#define CTRL(x) ((x) & CTRLVAL)
+
+/*
+ * User-definable variables are defined below.
+ * Update configuration to suit your needs and then recompile.
+ */
+
+/* User keys. */
+#define ORKEY_MOVE_RIGHT 'l'
+#define ORKEY_MOVE_LEFT 'h'
+#define ORKEY_MOVE_DOWN 'j'
+#define ORKEY_MOVE_UP 'k'
+#define ORKEY_DIG_LEFT 's'
+#define ORKEY_DIG_RIGHT 'd'
+#define ORKEY_LEVEL_NEXT CTRL('n')
+#define ORKEY_LEVEL_PREV CTRL('p')
+#define ORKEY_SUICIDE CTRL('g')
+#define ORKEY_EXIT CTRL('d')
+
+/* To set game speed (timeout in microseconds). */
+#define OLDRUNNER_TIMEOUT 80000
+
+/*
+ * If game levels files are installed in a system-wide location, set the
+ * LEVELS_PATH symbol to the appropriate path, such as:
+ *
+ * #define LEVELS_PATH "/usr/local/share/games/oldrunner/levels"
+ */
diff --git a/compat.h b/compat.h
new file mode 100644
index 0000000..f8aec7f
--- /dev/null
+++ b/compat.h
@@ -0,0 +1,56 @@
+/* $Id: compat.h,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#ifdef HAVE_QUEUE_H
+# include <sys/queue.h>
+#else
+# include "compat/queue.h"
+#endif
+
+#ifndef HAVE_BZERO
+# define bzero(buf, len) memset ((buf), 0, (len));
+#endif
+
+#ifndef HAVE_STRTONUM
+/* strtonum.c */
+long long strtonum (const char *, long long, long long, const char **);
+#endif
+
+#ifndef HAVE_FGETLN
+/* fgetln.c */
+char *fgetln (FILE *, size_t *);
+#endif
+
+#endif /* COMPAT_H */
diff --git a/compat/fgetln.c b/compat/fgetln.c
new file mode 100644
index 0000000..432677b
--- /dev/null
+++ b/compat/fgetln.c
@@ -0,0 +1,86 @@
+/* $NetBSD: fgetln.c,v 1.3 2007/08/07 02:06:58 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+char *
+fgetln(fp, len)
+ FILE *fp;
+ size_t *len;
+{
+ static char *buf = NULL;
+ static size_t bufsiz = 0;
+ char *ptr;
+
+
+ if (buf == NULL) {
+ bufsiz = BUFSIZ;
+ if ((buf = malloc(bufsiz)) == NULL)
+ return NULL;
+ }
+
+ if (fgets(buf, bufsiz, fp) == NULL)
+ return NULL;
+
+ *len = 0;
+ while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
+ size_t nbufsiz = bufsiz + BUFSIZ;
+ char *nbuf = realloc(buf, nbufsiz);
+
+ if (nbuf == NULL) {
+ int oerrno = errno;
+ free(buf);
+ errno = oerrno;
+ buf = NULL;
+ return NULL;
+ } else
+ buf = nbuf;
+
+ *len = bufsiz;
+ if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
+ return buf;
+
+ bufsiz = nbufsiz;
+ }
+
+ *len = (ptr - buf) + 1;
+ return buf;
+}
+
diff --git a/compat/queue.h b/compat/queue.h
new file mode 100644
index 0000000..a6fe39c
--- /dev/null
+++ b/compat/queue.h
@@ -0,0 +1,527 @@
+/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#ifdef QUEUE_MACRO_DEBUG
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != SLIST_END(head); \
+ (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_NEXT(head, elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/compat/strtonum.c b/compat/strtonum.c
new file mode 100644
index 0000000..e426388
--- /dev/null
+++ b/compat/strtonum.c
@@ -0,0 +1,65 @@
+/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
diff --git a/configure b/configure
new file mode 100755
index 0000000..7150f1b
--- /dev/null
+++ b/configure
@@ -0,0 +1,78 @@
+#!/bin/sh
+# $Id: configure,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $
+#
+# This configure script was greatly inspired by the script distributed with tmux
+# from Nicholas Marriott. The license from the original script is reproduced
+# below:
+#
+# Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+OLDRUNNER_PLATFORM=${OLDRUNNER_PLATFORM:-`uname -s`}
+
+CONFIG_H=config.h
+rm -f $CONFIG_H
+echo "/* $OLDRUNNER_PLATFORM */" >$CONFIG_H
+
+CONFIG_MK=config.mk
+rm -f $CONFIG_MK
+echo "# $OLDRUNNER_PLATFORM" >$CONFIG_MK
+
+cat <<EOF >>$CONFIG_H
+#undef HAVE_CURSES_H
+#undef HAVE_NCURSES_H
+#undef HAVE_NCURSES_NCURSES_H
+#undef HAVE_NCURSESW_NCURSES_H
+#undef HAVE_BZERO
+#undef HAVE_FGETLN
+#undef HAVE_QUEUE_H
+#undef HAVE_STRTONUM
+EOF
+
+case $OLDRUNNER_PLATFORM in
+# ------------------------------------------------------------------------------
+ OpenBSD|FreeBSD)
+ cat <<EOF >>$CONFIG_H
+#define HAVE_CURSES_H
+#define HAVE_BZERO
+#define HAVE_FGETLN
+#define HAVE_QUEUE_H
+#define HAVE_STRTONUM
+EOF
+ cat <<EOF >>$CONFIG_MK
+LIBS+= -lcurses
+EOF
+ ;;
+# ------------------------------------------------------------------------------
+ Linux)
+ cat <<EOF >>$CONFIG_H
+#define HAVE_NCURSES_H
+#define HAVE_BZERO
+EOF
+ cat <<EOF >>$CONFIG_MK
+CFLAGS+= -std=c99 -D_GNU_SOURCE -D_POSIX_SOURCE
+LIBS+= -lncurses
+SRCS+= compat/fgetln.c \
+ compat/strtonum.c
+EOF
+ ;;
+# ------------------------------------------------------------------------------
+ *)
+ echo Unable to configure for $OLDRUNNER_PLATFORM
+ exit 1
+esac
+
+echo Configured for $OLDRUNNER_PLATFORM
+exit 0
diff --git a/coord.c b/coord.c
new file mode 100644
index 0000000..e07c45f
--- /dev/null
+++ b/coord.c
@@ -0,0 +1,117 @@
+/* $Id: coord.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+void
+coord_copy (const struct coord *orig, struct coord *dest)
+{
+ dest->y = orig->y;
+ dest->x = orig->x;
+}
+
+void
+coord_below (const struct coord *orig, struct coord *dest)
+{
+ dest->y = orig->y + 1;
+ dest->x = orig->x;
+}
+
+void
+coord_above (const struct coord *orig, struct coord *dest)
+{
+ dest->y = orig->y - 1;
+ dest->x = orig->x;
+}
+
+enum move
+coord_opposite_dir (enum move dir)
+{
+ switch (dir)
+ {
+ case MOV_RIGHT:
+ return MOV_LEFT;
+ case MOV_LEFT:
+ return MOV_RIGHT;
+ case MOV_UP:
+ return MOV_DOWN;
+ case MOV_DOWN:
+ return MOV_UP;
+ default:
+ return MOV_NONE;
+ }
+}
+
+void
+coord_compute (const struct coord *orig, enum move move, struct coord *dest)
+{
+ coord_copy (orig, dest);
+ switch (move)
+ {
+ case MOV_UP:
+ dest->y--;
+ break;
+ case MOV_DOWN:
+ case MOV_FALL:
+ dest->y++;
+ break;
+ case MOV_LEFT:
+ dest->x--;
+ break;
+ case MOV_RIGHT:
+ dest->x++;
+ break;
+ default:
+ dest->y = dest->x = 0;
+ /* NOTREACHED */
+ }
+}
+
+void
+coord_set_yx (struct coord *coord, int y, int x)
+{
+ coord->y = y;
+ coord->x = x;
+}
+
+unsigned
+coord_equal (const struct coord *p1, const struct coord *p2)
+{
+ return p1->x == p2->x && p1->y == p2->y ? 1 : 0;
+}
+
+void
+coord_diff (const struct coord *p1, const struct coord *p2, struct coord *diff)
+{
+ diff->y = p1->y - p2->y;
+ diff->x = p1->x - p2->x;
+}
diff --git a/foes.c b/foes.c
new file mode 100644
index 0000000..abe3fba
--- /dev/null
+++ b/foes.c
@@ -0,0 +1,290 @@
+/* $Id: foes.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+#define FOES_DELAY (OLDRUNNER_TIMEOUT * 3)
+#define FOES_ESCAPE_DELAY (BRICK_COMEBACK_TIME * .75)
+
+struct foe {
+ struct coord pos;
+ struct timer timer;
+ enum move current_move;
+ int state;
+ SLIST_ENTRY(foe) foesp;
+};
+
+SLIST_HEAD(, foe) foes;
+
+void
+foes_init (void)
+{
+ SLIST_INIT (&foes);
+}
+
+void
+foes_free (void)
+{
+ while (!SLIST_EMPTY (&foes))
+ {
+ struct foe *f;
+
+ f = SLIST_FIRST (&foes);
+ SLIST_REMOVE_HEAD (&foes, foesp);
+ xfree (f);
+ }
+}
+
+void
+foes_add (const struct coord *pos)
+{
+ struct foe *f;
+
+ f = xmalloc (sizeof *f);
+ coord_set_yx (&f->pos, pos->y, pos->x);
+ f->current_move = MOV_NONE;
+ f->state = STATE_ALIVE;
+ SLIST_INSERT_HEAD (&foes, f, foesp);
+}
+
+void
+foes_draw (void)
+{
+ struct foe *f;
+
+ SLIST_FOREACH (f, &foes, foesp)
+ gfx_show_sprite (SP_FOE, &f->pos);
+}
+
+/*
+ * Once killed, a foe reappears on top of current level with
+ * a random horizontal position.
+ */
+static void
+get_random_inipos (struct coord *pos)
+{
+ coord_set_yx (pos, 0, -1);
+ while (lvl_obstacle_at (pos))
+ pos->x = lvl_random_xpos ();
+}
+
+static void
+foe_killed (struct foe *foe)
+{
+ struct coord inipos;
+
+ get_random_inipos (&inipos);
+ coord_copy (&inipos, &foe->pos);
+ foe->current_move = MOV_FALL;
+ foe->state = STATE_ALIVE;
+}
+
+static void
+foe_trapped (struct foe *foe)
+{
+ foe->state |= STATE_TRAPPED;
+ timer_start (&foe->timer);
+}
+
+static void
+check_trap (struct foe *foe)
+{
+ if (lvl_got_hole_below (&foe->pos))
+ {
+ struct coord below;
+
+ foe_trapped (foe);
+ coord_below (&foe->pos, &below);
+ gfx_move_sprite (SP_FOE, &foe->pos, &below);
+ coord_copy (&below, &foe->pos);
+ }
+}
+
+static void
+check_hole (struct foe *foe)
+{
+ if (lvl_nothing_below (&foe->pos))
+ foe->current_move = MOV_FALL;
+}
+
+static unsigned
+another_foe_at_pos (const struct foe *foe, const struct coord *pos)
+{
+ struct foe *f;
+
+ SLIST_FOREACH (f, &foes, foesp)
+ if (f != foe && coord_equal (pos, &f->pos))
+ return 1;
+
+ return 0;
+}
+
+unsigned
+foes_at_pos (const struct coord *pos)
+{
+ struct foe *f;
+
+ SLIST_FOREACH (f, &foes, foesp)
+ if (coord_equal (pos, &f->pos))
+ return 1;
+
+ return 0;
+}
+
+static void
+compute_move (const struct coord *hero, struct foe *foe)
+{
+ struct coord dpos;
+
+ if (foe->current_move == MOV_FALL)
+ coord_compute (&foe->pos, foe->current_move, &foe->pos);
+ else
+ {
+ coord_diff (hero, &foe->pos, &dpos);
+ if (dpos.y != 0)
+ {
+ enum move wanted_dir, prefered_move;
+
+ if (foe->current_move != MOV_LEFT && foe->current_move != MOV_RIGHT)
+ prefered_move = dpos.x >= 0 ? MOV_RIGHT : MOV_LEFT;
+ else
+ prefered_move = foe->current_move;
+ wanted_dir = dpos.y > 0 ? MOV_DOWN : MOV_UP;
+ foe->current_move = lvl_shortest_way (&foe->pos,
+ wanted_dir,
+ prefered_move);
+ coord_compute (&foe->pos, foe->current_move, &foe->pos);
+ }
+ else if (dpos.x > 0)
+ {
+ foe->current_move = MOV_RIGHT;
+ foe->pos.x++;
+ }
+ else if (dpos.x < 0)
+ {
+ foe->current_move = MOV_LEFT;
+ foe->pos.x--;
+ }
+ else
+ foe->current_move = MOV_NONE;
+ }
+}
+
+static void
+try_escape (struct foe *f)
+{
+ struct coord posorig;
+
+ if (!timer_delay_elapsed (&f->timer, FOES_ESCAPE_DELAY))
+ return;
+
+ coord_set_yx (&posorig, f->pos.y, f->pos.x);
+ coord_set_yx (&f->pos, f->pos.y - 1, f->pos.x);
+ gfx_move_sprite (SP_FOE, &posorig, &f->pos);
+ f->state &= ~STATE_TRAPPED;
+}
+
+static void
+update_foe_pos (const struct coord *hero_pos, struct foe *f)
+{
+ struct coord posorig;
+
+ coord_set_yx (&posorig, f->pos.y, f->pos.x);
+ compute_move (hero_pos, f);
+ if (!coord_equal (&posorig, &f->pos)
+ && lvl_valid_move (&posorig, f->current_move, &f->pos, SP_FOE)
+ && !another_foe_at_pos (f, &f->pos))
+ {
+ gfx_move_sprite (SP_FOE, &posorig, &f->pos);
+ check_trap (f);
+ check_hole (f);
+ if (coord_equal (&f->pos, hero_pos))
+ hero_die ();
+ }
+ else
+ {
+ /*
+ * The move is not possible, revert to current position
+ * and force next move to be in opposite direction using
+ * foe->current_move.
+ */
+ coord_copy (&posorig, &f->pos);
+ f->current_move =
+ f->current_move == MOV_FALL ?
+ MOV_NONE : coord_opposite_dir (f->current_move);
+ }
+}
+
+void
+foes_update_pos (void)
+{
+ static struct timer foes_timer;
+ struct timer now;
+ struct foe *foe;
+ struct coord hero_pos;
+
+ timer_get_time (&now);
+ if (timer_diff (&now, &foes_timer) < FOES_DELAY)
+ return;
+
+ hero_get_pos (&hero_pos);
+
+ SLIST_FOREACH (foe, &foes, foesp)
+ {
+ struct coord foe_prevpos;
+
+ coord_set_yx (&foe_prevpos, foe->pos.y, foe->pos.x);
+
+ if (foe->state & STATE_TRAPPED)
+ try_escape (foe);
+ else
+ update_foe_pos (&hero_pos, foe);
+ }
+ timer_get_time (&foes_timer);
+}
+
+unsigned
+foes_wallup_at (const struct coord *pos)
+{
+ struct foe *f;
+
+ SLIST_FOREACH (f, &foes, foesp)
+ {
+ if (coord_equal (pos, &f->pos))
+ {
+ foe_killed (f);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/game.c b/game.c
new file mode 100644
index 0000000..0cb27f9
--- /dev/null
+++ b/game.c
@@ -0,0 +1,297 @@
+/* $Id: game.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "oldrunner.h"
+
+#ifdef LEVELS_PATH
+# define LEVELS LEVELS_PATH "/original.lvl"
+#else
+# define LEVELS "./levels/original.lvl"
+#endif
+
+#define POINTS_FOR_MONEY 50
+#define LIVES_AT_START 5
+
+static struct game_info ginfo;
+
+static void
+game_lost (void)
+{
+ struct usr_input input;
+
+ gfx_game_over ();
+ gfx_get_input (&input);
+ game_end ();
+}
+
+void
+game_won (void)
+{
+ struct usr_input input;
+
+ gfx_game_won ();
+ gfx_get_input (&input);
+ game_end ();
+}
+
+void
+game_init (int startlvl)
+{
+ lvl_init ();
+ if (!game_load (LEVELS))
+ EXIT ("Could not load game levels. Aborting...");
+ ginfo.lives = LIVES_AT_START;
+ ginfo.level = startlvl + 1;
+ gfx_init ();
+ lvl_load (startlvl);
+ hero_init ();
+ game_update ();
+}
+
+/*
+ * The window will be centered on player either if the user requests it or if
+ * the level board is too large to fit it the screen.
+ */
+static void
+set_view (void)
+{
+ struct size lvl;
+
+ lvl.w = lvl_width ();
+ lvl.h = lvl_height ();
+
+ if (AUTO_CENTER_MODE || lvl.h > VIEWPORT_HEIGHT || lvl.w > VIEWPORT_WIDTH)
+ {
+ struct coord player_pos;
+
+ hero_get_pos (&player_pos);
+ gfx_center_at (&player_pos);
+ }
+ else
+ {
+ struct coord fixed_pos;
+
+ coord_set_yx (&fixed_pos, VIEWPORT_HEIGHT / 2, lvl.w / 2);
+ gfx_center_at (&fixed_pos);
+ }
+}
+
+void
+game_update (void)
+{
+ set_view ();
+ lvl_objects_update ();
+ hero_draw ();
+ if (!(ginfo.state & NO_CHANGE))
+ {
+ gfx_update_info (&ginfo);
+ ginfo.state = NO_CHANGE;
+ }
+ gfx_update ();
+}
+
+void
+game_end (void)
+{
+ gfx_end ();
+ exit (0);
+}
+
+static unsigned
+read_level_row (char *row, unsigned rownum)
+{
+ char *rowend;
+ int len;
+
+ if (*row != '[')
+ return 0;
+ row++;
+
+ if (!(rowend = strchr (row, ']')))
+ return 0;
+ *rowend = '\0';
+ len = rowend - row;
+
+ return lvl_set_row (rownum, len, row);
+}
+
+static unsigned
+store_level_attr (const char *attr, char *val)
+{
+ if (!strcmp (attr, "level"))
+ return lvl_set_name (val);
+ else if (!strcmp (attr, "author"))
+ return lvl_set_author (val);
+ else if (!strcmp (attr, "size"))
+ return lvl_set_size (val);
+ else
+ return 0;
+}
+
+/* XXX use strsep instead. */
+static unsigned
+read_level_attr (char *line)
+{
+ char *p, *attr, *val;
+
+ attr = p = line;
+
+ while (!isblank ((int)(*p)))
+ p++;
+ *p++ = '\0';
+
+ while (isblank ((int)(*p)))
+ p++;
+ val = p;
+
+ return store_level_attr (attr, val);
+}
+
+/*
+ * XXX improve comment.
+ *
+ * A game file contains the description of the levels.
+ * The following rules apply:
+ * - empty lines are ignored, as well as those beginning with #
+ * - the following keywords are used to describe a level:
+ * - level: name of the level (default: "")
+ * - author: author of the level (default: "")
+ * - size: in the form widthxlength (default: 26x16)
+ * - if keywords are present, they must be placed before the level layout
+ * - the reading of a level row stops as soon as the line does
+ * not start with '[', meaning a layout description must not have empty
+ * lines
+ */
+unsigned
+game_load (const char *path)
+{
+ FILE *f;
+ char *buf;
+ unsigned rownum, newlevel;
+
+ if (!(f = io_fopen (LEVELS)))
+ return 0;
+
+ newlevel = 1;
+ rownum = 0;
+ while ((buf = io_getln (f)))
+ {
+ char *p;
+
+#define CHK_NEW_LVL do { \
+ if (newlevel) \
+ { \
+ lvl_add_new (); \
+ newlevel = 0; \
+ rownum = 0; \
+ } \
+ } while (0)
+
+ /* Remove trailing spaces. */
+ p = buf;
+ while (isblank ((int)(*p)))
+ p++;
+
+ switch (*p)
+ {
+ case '[':
+ CHK_NEW_LVL;
+ read_level_row (p, rownum);
+ rownum++;
+ break;
+ case '#':
+ case '\0':
+ if (rownum)
+ newlevel = 1;
+ continue;
+ default:
+ if (rownum)
+ newlevel = 1;
+ CHK_NEW_LVL;
+ read_level_attr (p);
+ break;
+ }
+
+#undef CHK_NEW_LVL
+ }
+
+ io_fclose (f);
+
+ return 1;
+}
+
+void
+game_score_inc (void)
+{
+ ginfo.state |= SCORE_CHANGE;
+ ginfo.score += POINTS_FOR_MONEY;
+}
+
+int
+game_level_num (void)
+{
+ return ginfo.level;
+}
+
+void
+game_level_inc (void)
+{
+ ginfo.state |= LEVEL_CHANGE;
+ ginfo.level++;
+}
+
+void
+game_level_dec (void)
+{
+ ginfo.state |= LEVEL_CHANGE;
+ ginfo.level--;
+}
+
+void
+game_lives_inc (void)
+{
+ ginfo.state |= LIVES_CHANGE;
+ ginfo.lives++;
+}
+
+void
+game_lives_dec (void)
+{
+ ginfo.state |= LIVES_CHANGE;
+ if (ginfo.lives == 0)
+ game_lost ();
+ ginfo.lives--;
+}
diff --git a/gfx.c b/gfx.c
new file mode 100644
index 0000000..45c9522
--- /dev/null
+++ b/gfx.c
@@ -0,0 +1,448 @@
+/* $Id: gfx.c,v 1.2 2012/01/31 14:53:07 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "oldrunner.h"
+
+#ifdef HAVE_CURSES_H
+# include <curses.h>
+#elif defined HAVE_NCURSES_H
+# include <ncurses.h>
+#elif defined HAVE_NCURSES_NCURSES_H
+# include <ncurses/ncurses.h>
+#elif defined HAVE_NCURSESW_NCURSES_H
+# include <ncursesw/ncurses.h>
+#else
+# error "Missing curses library header. Aborting..."
+#endif
+
+#define INFOBAR_HEIGHT 2
+
+struct window {
+ WINDOW *p; /* pointer to window */
+ struct size siz;
+ struct coord pos;
+};
+
+struct scrollwin {
+ struct window pad;
+ struct window view;
+};
+
+static struct scrollwin scr;
+static struct size term;
+
+static chtype sprite[SPRITES];
+
+static void
+sprites_init (void)
+{
+ sprite[SP_NONE] = ' ';
+ sprite[SP_BRICK] = ACS_CKBOARD;
+ sprite[SP_BRICK_SCRACK] = '~';
+ sprite[SP_BRICK_LCRACK] = 'U';
+ sprite[SP_BRICK_BROKEN] = sprite[SP_NONE];
+ sprite[SP_CIMENT] = ' ' | A_REVERSE;
+ sprite[SP_FAKE_BRICK] = sprite[SP_BRICK];
+ sprite[SP_LADDER] = 'H';
+ sprite[SP_ROPE] = ACS_HLINE;
+ sprite[SP_ESCAPE_LADDER] = ACS_VLINE;
+ sprite[SP_MONEY] = ACS_DIAMOND;
+ sprite[SP_HERO] = '@';
+ sprite[SP_FOE] = '@' | A_REVERSE | A_BLINK;
+ sprite[SP_INVALID] = '?';
+}
+
+static void
+screen_init_size (void)
+{
+ scr.view.siz.w = VIEWPORT_WIDTH;
+ scr.view.siz.h = VIEWPORT_HEIGHT;
+
+ getmaxyx (stdscr, term.h, term.w); /* Size of the terminal. */
+ coord_set_yx (&scr.view.pos,
+ term.h > scr.view.siz.h ? (term.h - scr.view.siz.h) / 2 : 0,
+ term.w > scr.view.siz.w ? (term.w - scr.view.siz.w) / 2 : 0);
+ scr.pad.siz.w = LEVEL_MAX_WIDTH;
+ scr.pad.siz.h = LEVEL_MAX_HEIGHT;
+ coord_copy (&scr.view.pos, &scr.pad.pos);
+}
+
+static void
+screen_init (void)
+{
+ screen_init_size ();
+ scr.pad.p = newpad (scr.pad.siz.h, scr.pad.siz.w);
+ scr.view.p = newwin (scr.view.siz.h, scr.view.siz.w,
+ scr.view.pos.y, scr.view.pos.x);
+ keypad (scr.view.p, TRUE); /* Enable function and arrow keys. */
+ nodelay (scr.view.p, TRUE);
+ box (scr.view.p, 0, 0);
+ wnoutrefresh (scr.view.p);
+}
+
+static void
+screen_update (void)
+{
+ pnoutrefresh (scr.pad.p, scr.pad.pos.y, scr.pad.pos.x,
+ scr.view.pos.y + (scr.view.siz.h - lvl_height()) / 2,
+ scr.view.pos.x + (scr.view.siz.w - lvl_width()) / 2,
+ scr.view.pos.y + scr.view.siz.h - INFOBAR_HEIGHT,
+ scr.view.pos.x + scr.view.siz.w - 2);
+}
+
+static void
+newpopup (struct window *pop)
+{
+ const int BORDERWIDTH = 2;
+
+ pop->siz.w = scr.view.siz.w - 2 * BORDERWIDTH;
+ pop->siz.h = scr.view.siz.h - 2 * BORDERWIDTH;
+ pop->pos.y = scr.view.pos.y + BORDERWIDTH;
+ pop->pos.x = scr.view.pos.x + BORDERWIDTH;
+
+ pop->p = newwin (pop->siz.h, pop->siz.w, pop->pos.y, pop->pos.x);
+ keypad (pop->p, TRUE);
+}
+
+static void
+delpopup (struct window *pop)
+{
+ wclear (pop->p);
+ wrefresh (pop->p);
+ delwin (pop->p);
+}
+
+static void
+showpopup (struct window *pop)
+{
+ box (pop->p, 0, 0);
+ wrefresh (pop->p);
+}
+
+void
+gfx_init (void)
+{
+ /* Curses initialization. */
+ initscr (); /* start the curses mode */
+ cbreak (); /* control chars generate a signal */
+ noecho (); /* controls echoing of typed chars */
+ curs_set (0); /* make cursor invisible */
+ sprites_init ();
+
+ /* Game window initialization. */
+ screen_init ();
+}
+
+void
+gfx_end (void)
+{
+ wclear (scr.view.p);
+ wrefresh (scr.view.p);
+ delwin (scr.pad.p);
+ delwin (scr.view.p);
+ endwin ();
+}
+
+void
+gfx_alert (void)
+{
+ flash ();
+ napms (200);
+ flash ();
+}
+
+void
+gfx_center_at (struct coord *pos)
+{
+ coord_set_yx (&scr.pad.pos,
+ pos->y - VIEWPORT_HEIGHT / 2, pos->x - VIEWPORT_WIDTH / 2);
+}
+
+void
+gfx_update (void)
+{
+ screen_update ();
+ doupdate ();
+}
+
+void
+gfx_get_input (struct usr_input *input)
+{
+ int key;
+
+ key = wgetch (scr.view.p);
+ input->key = key == ERR ? -1 : key;
+}
+
+void
+gfx_show_sprite (enum sprite sp, const struct coord *pos)
+{
+ gfx_move_sprite (sp, 0, pos);
+}
+
+/*
+ * Show the given character at the current position.
+ * The optional previous position is also given so that graphics routines can
+ * properly clean it up if necessary.
+ *
+ * note:
+ * If the viewport is larger than the level size, a shift must be applied in
+ * order to center the level on screen.
+ */
+void
+gfx_move_sprite (enum sprite sp, const struct coord *prev,
+ const struct coord *current)
+{
+ mvwaddch (scr.pad.p, current->y, current->x, sprite[sp]);
+ if (prev)
+ {
+ sp = lvl_decor_at_pos (prev);
+ mvwaddch (scr.pad.p, prev->y, prev->x, sprite[sp]);
+ }
+
+ screen_update ();
+}
+
+/*
+ * Display information related to current game (score, number of lives and
+ * current level).
+ */
+void
+gfx_update_info (const struct game_info *info)
+{
+ const int HIGHLIGHT = WA_REVERSE | WA_BOLD;
+ char score[BUFSIZ], lives[BUFSIZ], level[BUFSIZ];
+ int score_len, lives_len, level_len, yoff, xoff;
+
+ score_len = snprintf (score, sizeof score, "[SCORE: %010d]", info->score);
+ lives_len = snprintf (lives, sizeof lives, "[LIVES: %03d]", info->lives);
+ level_len = snprintf (level, sizeof level, "[LEVEL: %03d]", info->level);
+
+ yoff = scr.view.siz.h - INFOBAR_HEIGHT + 1;
+ xoff = scr.view.siz.w - (score_len + lives_len + level_len);
+ xoff >>= 2;
+
+ if (info->state & SCORE_CHANGE)
+ wattron (scr.view.p, HIGHLIGHT);
+ mvwprintw (scr.view.p, yoff, xoff, score);
+ if (info->state & SCORE_CHANGE)
+ wattroff (scr.view.p, HIGHLIGHT);
+
+ if (info->state & LIVES_CHANGE)
+ wattron (scr.view.p, HIGHLIGHT);
+ mvwprintw (scr.view.p, yoff, score_len + 2 * xoff, lives);
+ if (info->state & LIVES_CHANGE)
+ wattroff (scr.view.p, HIGHLIGHT);
+
+ if (info->state & LEVEL_CHANGE)
+ wattron (scr.view.p, HIGHLIGHT);
+ mvwprintw (scr.view.p, yoff, score_len + lives_len + 3 * xoff, level);
+ if (info->state & LEVEL_CHANGE)
+ wattroff (scr.view.p, HIGHLIGHT);
+
+ wnoutrefresh (scr.view.p);
+}
+
+void
+gfx_popup (const char *title, const char *msg)
+{
+ struct window pop;
+ char *any_key = "Press any key...";
+
+ newpopup (&pop);
+
+ mvwhline (pop.p, 2, 1, ACS_HLINE, pop.siz.w - 2);
+ mvwprintw (pop.p, 1, (pop.siz.w - strlen (title)) / 2, "%s", title);
+
+ mvwprintw (pop.p, 5, 1, "%s", msg);
+ mvwprintw (pop.p, pop.siz.h - 2, pop.siz.w - (strlen (any_key) + 1), "%s",
+ any_key);
+
+ showpopup (&pop);
+ (void)wgetch (pop.p);
+ delpopup (&pop);
+}
+
+void
+gfx_game_over (void)
+{
+ const char *rip =
+ " +-+ \n"
+ " +-+-+-+ \n"
+ " +-+-+-+ \n"
+ " | | \n"
+ " +------+-+------+ \n"
+ " | | \n"
+ " | R I P | \n"
+ " ~~~~~~~~~~~| |~~~~~~~~~~ \n"
+ " +---------------+ \n";
+
+ gfx_popup ("G A M E O V E R", rip);
+}
+
+/*
+ * The ending screen was taken from the ncurses original sources
+ * (firework.c file).
+ * The original copyright is reproduced below.
+ */
+/****************************************************************************
+ * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+static void
+fw_show (struct window *win)
+{
+ const char *title = "C O N G R A T U L A T I O N S";
+ const int titlelen = 29;
+
+ mvwhline (win->p, 2, 1, ACS_HLINE, win->siz.w - 2);
+ mvwprintw (win->p, 1, (win->siz.w - titlelen) / 2, "%s", title);
+ showpopup (win);
+ napms (120);
+}
+
+static void
+fw_explode (struct window *win, int row, int col)
+{
+ werase (win->p);
+ mvwprintw (win->p, row, col, "-");
+ fw_show (win);
+
+ mvwprintw(win->p, row - 1, col - 1, " - ");
+ mvwprintw(win->p, row + 0, col - 1, "-+-");
+ mvwprintw(win->p, row + 1, col - 1, " - ");
+ fw_show (win);
+
+ mvwprintw(win->p, row - 2, col - 2, " --- ");
+ mvwprintw(win->p, row - 1, col - 2, "-+++-");
+ mvwprintw(win->p, row + 0, col - 2, "-+#+-");
+ mvwprintw(win->p, row + 1, col - 2, "-+++-");
+ mvwprintw(win->p, row + 2, col - 2, " --- ");
+ fw_show (win);
+
+ mvwprintw(win->p, row - 2, col - 2, " +++ ");
+ mvwprintw(win->p, row - 1, col - 2, "++#++");
+ mvwprintw(win->p, row + 0, col - 2, "+# #+");
+ mvwprintw(win->p, row + 1, col - 2, "++#++");
+ mvwprintw(win->p, row + 2, col - 2, " +++ ");
+ fw_show (win);
+
+ mvwprintw(win->p, row - 2, col - 2, " # ");
+ mvwprintw(win->p, row - 1, col - 2, "## ##");
+ mvwprintw(win->p, row + 0, col - 2, "# #");
+ mvwprintw(win->p, row + 1, col - 2, "## ##");
+ mvwprintw(win->p, row + 2, col - 2, " # ");
+ fw_show (win);
+
+ mvwprintw(win->p, row - 2, col - 2, " # # ");
+ mvwprintw(win->p, row - 1, col - 2, "# #");
+ mvwprintw(win->p, row + 0, col - 2, " ");
+ mvwprintw(win->p, row + 1, col - 2, "# #");
+ mvwprintw(win->p, row + 2, col - 2, " # # ");
+ fw_show (win);
+}
+
+/* XXX quit end screen properly (free popup window) */
+static void
+fireworks (void)
+{
+ struct window pop;
+ int start, end, row, diff, flag, direction;
+
+ newpopup (&pop);
+ showpopup (&pop);
+ flag = 0;
+ for (;;)
+ {
+ do
+ {
+ start = rand() % (pop.siz.w - 3);
+ end = rand() % (pop.siz.w - 3);
+ start = (start < 2) ? 2 : start;
+ end = (end < 2) ? 2 : end;
+ direction = (start > end) ? -1 : 1;
+ diff = abs (start - end);
+ }
+ while (diff < 2 || diff >= pop.siz.h - 2);
+
+ for (row = 0; row < diff; row++)
+ {
+ mvwprintw (pop.p, pop.siz.h - row, start + (row * direction),
+ (direction < 0) ? "\\" : "/");
+ if (flag++)
+ {
+ fw_show (&pop);
+ werase (pop.p);
+ flag = 0;
+ }
+ }
+ if (flag++)
+ {
+ fw_show (&pop);
+ flag = 0;
+ }
+ fw_explode (&pop, pop.siz.h - row, start + (diff * direction));
+ werase (pop.p);
+ fw_show (&pop);
+ }
+}
+
+void
+gfx_game_won (void)
+{
+ fireworks ();
+}
diff --git a/hero.c b/hero.c
new file mode 100644
index 0000000..040ec9b
--- /dev/null
+++ b/hero.c
@@ -0,0 +1,188 @@
+/* $Id: hero.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+struct hero {
+ struct coord pos, initpos;
+ int state;
+};
+
+static struct hero hero;
+
+void
+hero_init (void)
+{
+ hero.state = STATE_ALIVE;
+ hero_draw ();
+ usr_reset_input ();
+}
+
+void
+hero_draw (void)
+{
+ gfx_show_sprite (SP_HERO, &hero.pos);
+}
+
+void
+hero_set_pos (const struct coord *pos)
+{
+ coord_set_yx (&hero.pos, pos->y, pos->x);
+ if (hero.pos.y < 0)
+ lvl_won ();
+}
+
+void
+hero_set_initpos (const struct coord *pos)
+{
+ coord_set_yx (&hero.initpos, pos->y, pos->x);
+}
+
+void
+hero_get_pos (struct coord *pos)
+{
+ coord_set_yx (pos, hero.pos.y, hero.pos.x);
+}
+
+void
+hero_get_initpos (struct coord *pos)
+{
+ coord_set_yx (pos, hero.initpos.y, hero.initpos.x);
+}
+
+unsigned
+hero_at_pos (const struct coord *pos)
+{
+ if (coord_equal (&hero.pos, pos))
+ return 1;
+ return 0;
+}
+
+void
+check_collisions (const struct coord *hero_pos)
+{
+ if (lvl_got_hole_below (hero_pos))
+ {
+ struct coord below;
+
+ hero_trapped ();
+ coord_below (hero_pos, &below);
+ gfx_move_sprite (SP_HERO, hero_pos, &below);
+ hero_set_pos (&below);
+ }
+ else
+ {
+ if (foes_at_pos (hero_pos))
+ hero_die ();
+ money_check_at (hero_pos);
+ if (money_all_collected ())
+ lvl_draw_escape_ladder ();
+ }
+}
+
+void
+hero_move (enum move move)
+{
+ struct coord orig, dest;
+
+ /* First check if the move is valid with regards to current player state. */
+ if (hero.state & STATE_DIGGING)
+ return;
+
+ if ((hero.state & STATE_FALLING) && (move != MOV_FALL))
+ move = MOV_FALL;
+
+ /* Then check if the move is valid with regards to the level layout. */
+ hero_get_pos (&orig);
+ if (!lvl_valid_move (&orig, move, &dest, SP_HERO))
+ {
+ if (hero.state & STATE_FALLING)
+ hero.state &= ~STATE_FALLING;
+ return;
+ }
+ else
+ hero_set_pos (&dest);
+
+ if (move == MOV_FALL || lvl_nothing_below (&hero.pos))
+ hero.state |= STATE_FALLING;
+
+ gfx_move_sprite (SP_HERO, &orig, &hero.pos);
+ check_collisions (&hero.pos);
+}
+
+void
+hero_dig (enum move dir)
+{
+ struct coord heropos, digpos;
+
+ hero_get_pos (&heropos);
+ coord_set_yx (&digpos,
+ heropos.y + 1, heropos.x + (dir == MOV_RIGHT ? 1 : -1));
+ if (lvl_valid_dig (&digpos))
+ {
+ hero.state |= STATE_DIGGING;
+ bricks_break (&digpos);
+ }
+}
+
+void
+hero_dig_done (void)
+{
+ hero.state &= ~STATE_DIGGING;
+}
+
+void
+hero_trapped (void)
+{
+ hero.state |= STATE_TRAPPED | STATE_FALLING;
+ usr_reset_input ();
+}
+
+void
+hero_die (void)
+{
+ gfx_alert ();
+ game_lives_dec ();
+ lvl_lost ();
+}
+
+unsigned
+hero_wallup_at (const struct coord *pos)
+{
+ if (coord_equal (pos, &hero.pos))
+ {
+ hero_die ();
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/io.c b/io.c
new file mode 100644
index 0000000..171155a
--- /dev/null
+++ b/io.c
@@ -0,0 +1,86 @@
+/* $Id: io.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "oldrunner.h"
+
+FILE *
+io_fopen (const char *path)
+{
+ FILE *f;
+
+ if (!(f = fopen (path, "r")))
+ {
+ ERROR_MSG ("Could not open game file \"%s\": %s",
+ path, strerror (errno));
+ return 0;
+ }
+
+ return f;
+}
+
+static char *line;
+
+void
+io_fclose (FILE *f)
+{
+ (void)fclose (f);
+ if (line)
+ xfree (line);
+ line = 0;
+}
+
+char *
+io_getln (FILE *f)
+{
+ size_t len;
+ char *buf;
+
+ line = 0;
+ if (!(buf = fgetln (f, &len)))
+ return 0;
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ else
+ {
+ /* EOF without EOL, copy and add the NUL */
+ line = xrealloc (line, 1, len + 1);
+ memcpy (line, buf, len);
+ line[len] = '\0';
+ buf = line;
+ }
+
+ return buf;
+}
diff --git a/levels/original.lvl b/levels/original.lvl
new file mode 100644
index 0000000..4a57f75
--- /dev/null
+++ b/levels/original.lvl
@@ -0,0 +1,3155 @@
+#-----------------------------------------------------------------------------
+level "Level 0 (original)"
+author "Broderbund"
+size 0x0
+
+#-----------------------------------------------------------------------------
+level "Level 1 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ $ | ]
+[######H####### | ]
+[ H----------| $ ]
+[ H ##H ######H##]
+[ H ##H H ]
+[ &H ##H $&H ]
+[##H#### ########H######]
+[ H H ]
+[ H & H ]
+[########H##########H ]
+[ H H ]
+[ $ H----------H $ ]
+[ H##### ######H]
+[ H @ $ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 2 (original)"
+author "Broderbund"
+size 26x16
+[ $ H]
+[HXX#XXH $ H]
+[H H H########H $ H]
+[H $ & H H H###VH]
+[H#X#X#H H H |]
+[H H----H----- &H |]
+[H H H H###XXXXXH]
+[H H H $ H H]
+[H & H $ H####H H]
+[X###X##X##XH H##H##]
+[X###X H H H ]
+[X$ X H ------H H $]
+[########H###XXX H ####]
+[ H H ]
+[ H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 3 (original)"
+author "Broderbund"
+size 26x16
+[ |]
+[--------- $ |]
+[H$ H#########H |]
+[####H H HXXXXXXX]
+[ H & H $ H ]
+[ H#####H#####H## ]
+[ $ H H H -- ]
+[###H# H & H -- ]
+[ H H#####H## --$]
+[ H----H H & #]
+[ H H#########H ]
+[ H H#########H ]
+[##H######### $ #####H#]
+[##H######### H###H #####H#]
+[ H @ H###H H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 4 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[|---------- ]
+[H H # $ # H ]
+[H$ HHH $ ##### $ HHH $]
+[ HH H HH HH H HH]
+[ H HHHHH H H HHHHH H]
+[ H $&$ H H H $&$ H]
+[H H#####H HHH H#####H ]
+[H HHHHH HH H HH HHHHH ]
+[H H HHHHH H ]
+[H $ H $&$ H $ ]
+[H#####H H#####H H######]
+[H H HHHHH H ]
+[H H H ]
+[H H $ @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 5 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | $ & ]
+[### | ###H######]
+[ # | ## H ]
+[ ## | ## H ]
+[$& ### | $### H $ ]
+[##H#### | ####H##H######]
+[ H ## | ## H ]
+[ H$& ##H## H $ ]
+[H###H H #H#H### ]
+[H H H ]
+[H H $ & H ]
+[H H#######H#####H####H##]
+[H H H ]
+[H H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 6 (original)"
+author "Broderbund"
+size 26x16
+[################|#########]
+[# $ |# & $ #]
+[#V##H####H $ |#######H#]
+[#V##H############# ### H#]
+[# H $ & #### ### H#]
+[#H########H####### ### H#]
+[#H ######H####$$# ###$ H#]
+[#H ######H#############H#]
+[#H # $H $ & $ #H#]
+[#H ###H######H#######H#H#]
+[#H $###H H#######H#H#]
+[#H#V# H @ H ## H#H#]
+[#H#V#H#####H#######$$ H#H#]
+[#H#V#H#####H#####$######H#]
+[#H& H##$##H $ & H#]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 7 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | --------]
+[ | & H H]
+[####H# #H### &H $ H]
+[ H H ###H#######]
+[ & H $ H H ]
+[####H### H H ]
+[ H H H ]
+[ $ H $ H H ]
+[#H###########H H #### H]
+[ H H $ H #### H]
+[ H $ H----H # $# H]
+[######H H #####H]
+[ H H H]
+[ H @ $ H & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 8 (original)"
+author "Broderbund"
+size 26x16
+[ | | ]
+[ | | ]
+[ $ H#| |#H & ]
+[H#####H-H#| |#H-H#####H]
+[H# #H #| |# H# #H]
+[H# #H #| |# H# #H]
+[H# $ #H #| |# H# $ #H]
+[H#####H #| |# H#####H]
+[H# #H #| |# H# #H]
+[H# #H--#H####H#--H# #H]
+[H# # H#H H#H # #H]
+[H#&$ # H#H $&H#H # $&#H]
+[H##V## HXXXXXXX#H ##V##H]
+[H V H H V H]
+[H VH& @ HV H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 9 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[|-------------------------]
+[H# & # # #]
+[H ##### ##### ]
+[H # ### #$### ]
+[H ##### & & & ##### ]
+[H ### #V############### # ]
+[H #####V### $## $######H# ]
+[H #####V###############H# ]
+[H #####V###############H# ]
+[H #####V#### #######H# ]
+[H #####V#### #######H# ]
+[H #####V#### $H######H# ]
+[H ####H------H ]
+[H XXXX ]
+[H @ XXXX & ]
+
+#-----------------------------------------------------------------------------
+level "Level 10 (original)"
+author "Broderbund"
+size 26x16
+[ $ | ]
+[ H###### $ | ]
+[ $ H ###### | ]
+[##########H $ | ]
+[ H######|####H## ]
+[& H | H ]
+[##########H | & H $]
+[##########H#######XX H###]
+[##########H H ]
+[##########H $ ---H ]
+[## ##H ## H ]
+[## $$ ##H $ H ]
+[###########H######H H ]
+[ H #######H]
+[ $ @ H H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 11 (original)"
+author "Broderbund"
+size 26x16
+[ H ]
+[ &$ H $& ]
+[H##&$ H $&##H]
+[H ## H####|H#####H ## H]
+[H HH$ H H]
+[H $HH H H]
+[H HH$ H]
+[H $HH H]
+[H HH$ H]
+[H $HH H]
+[H HH$ H]
+[H $HH H]
+[H HH$ H]
+[H $HH H]
+[H @ HH$ H]
+[H H##############H H]
+
+#-----------------------------------------------------------------------------
+level "Level 12 (original)"
+author "Broderbund"
+size 26x16
+[ $ $ H ]
+[H###############H H ]
+[H $ H-----H $]
+[#########H####### H###]
+[########HH H ]
+[#######HH------H H ]
+[#$ $##HH & H $ & H $]
+[#####HH H####XX####H###]
+[ H H H ]
+[ H H H ]
+[ &H $ H----------H $]
+[H##########H $ $ H###]
+[H H ######## H ]
+[H H H ]
+[H $ H @ $ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 13 (original)"
+author "Broderbund"
+size 26x16
+[ & & ]
+[VHVHVHVHVHVHVHVHVHVHVHVHV|]
+[VHVHVHVHVHVHVHVHVHVHVHVHV|]
+[#H H#H$H#H H#H$H#H H#H$H#|]
+[#HVH#HVH#HVH#HVH#HVH#HVH#|]
+[#HVH#HVH#HVH#HVH#HVH#HVH#|]
+[#HVH#HVH#HVH#HVH#HVH#HVH#|]
+[#H$H#H H#H$H#H H#H$H#H H#|]
+[#HVH#HVH#HVH#HVH#HVH#HVH#|]
+[#HVH#HVH#HVH#HVH#HVH#HVH#|]
+[$H H H H H H H H H H H H#|]
+[H########################|]
+[H $ & $ $ & |]
+[HXXXXXXXXXXXXXXXXXXXXXXXX|]
+[H$ @ $|]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 14 (original)"
+author "Broderbund"
+size 26x16
+[ H & - &-H H- $]
+[ -H -H- - - H- H -H]
+[- H - H - - H - H H]
+[$ H - H - - H -$H -H]
+[ H- -H -- H$ -H H]
+[H- - H- -- - H------ ]
+[H - -H -$ - H - H ]
+[H- - H$--H - H -H ]
+[H - - H-- H - H - H ]
+[H- $ -&H- H - -H- - H ]
+[H -H - H - - H ]
+[H- H - H - - - H ]
+[H -H - - H$- - - H ]
+[H- H - H- - $- - H$]
+[H -H - -H - - - -H-]
+[ H $ $@ H ]
+
+#-----------------------------------------------------------------------------
+level "Level 15 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[| $ & $ $ & $ |]
+[|||########H H#######|||]
+[ H H ]
+[ H#############H ]
+[$ & $H $ $ H$ & $]
+[######H $ $#####$ $ H#####]
+[ H #### #### H ]
+[ $ H $ H $ ]
+[ H####################H ]
+[ H @ H ]
+[ H $ $H#######H$ $H ]
+[#########H H########]
+[ H H ]
+[ $ H H $ ]
+[#X#X#X#X#X#X#X#X#X#X#X#X#X]
+
+#-----------------------------------------------------------------------------
+level "Level 16 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ @ | ]
+[ V####HH#####HHHHH |]
+[ H # H | ]
+[ $ H H# H | ]
+[ #$ HH# H | ]
+[ ###$ H# H | ]
+[ #####$ H# H | ]
+[######## H# H | ]
+[ $##### H# H | ]
+[ ### H# H | ]
+[ # H# H | ]
+[ & H# H & |]
+[ H#############V######## |]
+[ ############## H#|]
+[############### $$$$$$H##]
+
+#-----------------------------------------------------------------------------
+level "Level 17 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[| |]
+[| & |]
+[H###V####################H]
+[H###V####################H]
+[H $ ##-------## H]
+[H $#H & $## & H]
+[H ### ##H ####### ####H]
+[H #$# ##H ## #$##H]
+[H @ ##H ## ####H]
+[H ### #######HH## #$##H]
+[H ### #######HH## ####H]
+[H ### ## H ## H]
+[H ### ## $H ## $ H]
+[##########H########H######]
+[####### $H##### $ H######]
+
+#-----------------------------------------------------------------------------
+level "Level 18 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | $ $ $]
+[HV#H H###H H##H# #H]
+[H ###### H####H H $ H]
+[H$ & H H #### H]
+[HV#### ##H# H]
+[H X#### ## H# H]
+[H X##### ## H#H H]
+[H X########### $ H ##]
+[H X########### ## H ]
+[H X ### ### H &$]
+[H X $ ## $ ## & H ##]
+[H XH###########H####H ##]
+[H H H H ##]
+[H H @ H ##]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 19 (original)"
+author "Broderbund"
+size 26x16
+[ H##H ]
+[ &$H##H$& ]
+[ H######H ]
+[ $H######H$ ]
+[ H##########H ]
+[ &$H##########H$& ]
+[ H##############H ]
+[ $H $$$$$$$$ H$ ]
+[ H##################H ]
+[ $H##################H$ ]
+[ H######################H ]
+[ H######################H ]
+[ H H ]
+[ H H ]
+[ H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 20 (original)"
+author "Broderbund"
+size 26x16
+[ &$ ]
+[ #######H & $ ]
+[ & $ H#H#####H]
+[ $#####H H H H]
+[##V### H------H H$ H]
+[ H H #######]
+[ $ H H ]
+[##H H H--------]
+[$ H & H $ H $]
+[######## #######H ####]
+[ $ $ H ]
+[####H###V###H $ H $ ]
+[ H #############H]
+[ H H]
+[ H $ @ $ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 21 (original)"
+author "Broderbund"
+size 26x16
+[XXXXXXXXXXXXXXXXXXXXXXXXX|]
+[H---------------------H|||]
+[H H ## & $ H|$ ]
+[H H ####################H]
+[H H ### H]
+[H H # #################]
+[H H H# $ # $ # $ # $ ]
+[H H H##H################]
+[H H--H H##### #### ]
+[H H H H # $# & ]
+[H H H H--H ####H-######]
+[H H H H H H ######]
+[H H H H H--H H ######]
+[H H H H H H H## $$$ ]
+[H H@ H H &H H H##H####]
+[##################H$$H####]
+
+#-----------------------------------------------------------------------------
+level "Level 22 (original)"
+author "Broderbund"
+size 26x16
+[ $ $ ]
+[$$###############H ]
+[## $ $ H ]
+[ H########H $ $ ]
+[ H H####### ]
+[ $&$ H ]
+[ H#####H------ $ ]
+[ H H H########H]
+[ $ H H H H]
+[###H & H & $ H $ H]
+[ H###H######H H#####]
+[ H-------- $ H ]
+[ $H$ H#####H $ ]
+[######H H H#####]
+[ H H ]
+[ H $ @ H $ ]
+
+#-----------------------------------------------------------------------------
+level "Level 23 (original)"
+author "Broderbund"
+size 26x16
+[ XXXXXXXX | ]
+[ X X | XX ]
+[ X $$ & #H | XX ]
+[X##H########XXH & |$XX ]
+[###H###########H##XX#HXXXX]
+[##HHH#-------#HHH#---H---H]
+[##H H# $ #H H# $ $ H]
+[##H H# @ #H H# H]
+[##H$H####H####H$H#X XH]
+[#########H###############H]
+[ ##HHH## $ $ $ H]
+[------#HH HH-------------H]
+[ $ #H H & H]
+[ H H ########## H]
+[XXX H H ### $## $ ##H]
+[X#####XH$ $H ############]
+
+#-----------------------------------------------------------------------------
+level "Level 24 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ || ]
+[ || ]
+[ || ]
+[ || ]
+[ | ]
+[ H##H ]
+[ H##H$ ]
+[ H#######H & ]
+[#H & H# $ $ #H #H#H ]
+[ ###H############H###H ]
+[ ## $ #### $ H$ ##H ]
+[ ####H $ ###H H##H #H ]
+[ #$#H###H $ H H$#H$#H ]
+[ & ##################H @]
+[XXXXXXXXXXXXXXXXXXXXXXXXXX]
+
+#-----------------------------------------------------------------------------
+level "Level 25 (original)"
+author "Broderbund"
+size 26x16
+[ X X X |]
+[ X X X $ |]
+[ XV####X X#### ###|]
+[## ###H& $ $|]
+[##########H H######## #H]
+[ @ H ##H $ #H]
+[H#########H $#H #####H #H]
+[--------##H ##H # H #H]
+[ # # $##H HH # ###H #H]
+[ # # #HH####H##$###H #H]
+[ # $# #H# # ###H H]
+[ #### #H# #### # H#HH]
+[H## ##HHH# #$## #######H ]
+[H XX#HH## # ##$ H#]
+[H X H##V####V#######H#]
+[H### H & H ]
+
+#-----------------------------------------------------------------------------
+level "Level 26 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ & | ]
+[H##########H & $ $ | ]
+[H H#####H ##H###]
+[H $ $ H XH H ]
+[H # ### # H $$ XH & H ]
+[H # ### # H XX X########X]
+[H # ### # H XX X$]
+[H # ### # H X------ $ XH]
+[H #$ ### # H X$ ###HXH]
+[H ##### # H XX H H]
+[H ######## H XX $ H##]
+[H H XX #### H ]
+[HXXXXXXXX#XXXXX H ]
+[H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 27 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[| @ & |]
+[| X#H#X----------X#H#X |]
+[| X$H X $ $ X H X |]
+[|X## H ##X X## H$##X|]
+[|X$ H $X $ $X $ H #$X|]
+[X####H ##X X#####H # #|]
+[H H X $X$ H # $]
+[H H#####XH#X## $H ## #]
+[H$ & H & H ##H ]
+[H####H X##H###X H #H]
+[HX $ H # H $ # H &XH]
+[HX## H ### H ### H ##XH]
+[H $# H X H $X H X$ H]
+[H ### H ### H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 28 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[----------- | ]
+[ $ $ XH | $ ]
+[#########XXXXXXH $HXH ]
+[#X#X#X#XXXX XXXXXXXH ]
+[ X $ XH &$ ]
+[--------H X#####H XX###H]
+[ H X H& ###H]
+[ H X ########H ###H]
+[ $ $ H X # #H ###H]
+[###& # H X # $ #H #$#H]
+[####### H X ########H # #H]
+[ H # $ #H #H]
+[############# H##H ######H]
+[ @ H $H H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 29 (original)"
+author "Broderbund"
+size 26x16
+[ & -- - & ]
+[#### H - ##H ]
+[#### H ## - & -##H ]
+[#$$# H ##- ####### -H ]
+[#### H ####### H H###]
+[ H--- ####### H #$#]
+[ - H ####### H ###]
+[ #### H ##$$$## H ]
+[ - #### H ####### H ]
+[###- #$$# H- - -H ]
+[#$# #### H - - H #### ]
+[### H @ H #### ]
+[ H ### H #$$# ]
+[ ## H #$# H #### ]
+[ ## H #V# H ]
+[ H H ]
+
+#-----------------------------------------------------------------------------
+level "Level 30 (original)"
+author "Broderbund"
+size 26x16
+[X |]
+[X $$$$& & & @ |]
+[X#########V##############H]
+[ H]
+[ X $ $ $ $X H]
+[ X#######V######V####X H]
+[ H]
+[ X $ $ $ X H]
+[ X###V######V####X H]
+[ H]
+[ X $ $ $X H]
+[ XX############X H]
+[ H]
+[ H]
+[$$$$ & & HX H]
+[#########XXXXXX######XXX H]
+
+#-----------------------------------------------------------------------------
+level "Level 31 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[$ || $]
+[H H----------|---------H H]
+[#HH & $ HH#]
+[##H H------ ---------H H##]
+[###HH $ HH###]
+[###VH H------ -----H&HV###]
+[###V#HH $ HH#V###]
+[###V##H H--- ----H H##V###]
+[###V###HH $ HH###V###]
+[###V####H H-- -H H####V###]
+[###V#####HH HH#####V###]
+[###V######H H######V###]
+[###V#######H@$H#######V###]
+[###& H##H ###]
+
+#-----------------------------------------------------------------------------
+level "Level 32 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[##|#### ----- & ]
+[ | -- & XXXXXH]
+[ H# #####H######-- # H]
+[H### #$---H-----# ####H#]
+[H #### ###H# #$ H ]
+[H #----H----H# #- H ]
+[H@# #H$#$H$#H$H# # H$]
+[H## ############ ##H###]
+[H $# $ # H ]
+[H ## ###H # H ]
+[H $# # H # H#####]
+[H # # $ H #$ H ]
+[H$# # H######H ##$H ]
+[H# $ # H# $ H #H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 33 (original)"
+author "Broderbund"
+size 26x16
+[#####|################ ###]
+[ |# ------ ]
+[|##| |# #$ #H# & ]
+[| ##### #####H#####$ #H###]
+[#| $---###H########H# #]
+[####### # #H### ####H# #]
+[ & #H### ## #H#$ ]
+[H#######H#H$#H### ## #H###]
+[H H####H###$ # #H## ]
+[H H###### #H##$]
+[H # H H ]
+[H###H####HX#X#X#X#X#X#H#X#]
+[H###H####H##### #####H#X#]
+[H H H###### ####H ]
+[H########H#######$ ######H]
+[H@ H $###### & H]
+
+#-----------------------------------------------------------------------------
+level "Level 34 (original)"
+author "Broderbund"
+size 26x16
+[ -------$$######$$------- ]
+[H $###HHHH###$ H]
+[H $##HHH&&HHH##$ H]
+[H ##HH HH## H]
+[H $#HH HH#$ H]
+[H ##H$ $H## H]
+[H #HH$ $HH# H]
+[H #H$$ $$H# H]
+[H #HH$ $HH# H]
+[H ##H$ $H## H]
+[H #HH$ $HH# H]
+[H #VHH$$ $$HHV# H]
+[H V#HHH$$HHH#V H]
+[H ###HHHH### H]
+[H@ & ###### & H]
+[########H H########]
+
+#-----------------------------------------------------------------------------
+level "Level 35 (original)"
+author "Broderbund"
+size 26x16
+[| ## |]
+[| XX |]
+[| $ $ ## $ $ |]
+[#X#X#X#X#X#HXXH#X#X#X#X#X#]
+[ $ $ H##H $ $ ]
+[H#X#X#X#X#X#X#X#X#X#X#X#XH]
+[H $ $ ## $ $ H]
+[#X#X#X#X#X#HXXH#X#X#X#X#X#]
+[ $&&$ H##H $&&$ ]
+[H#X#X#X#X#X#XX#X#X#X#X#X#H]
+[H $ $ ## $ $ H]
+[#X#X#X#X#X#HXXH#X#X#X#X#X#]
+[ $ $ H##H $ $ ]
+[H#X#X#X#X#X#XX#X#X#X#X#X#H]
+[H @ H]
+[#X#X#X#X#X#X#X#X#X#X#X#X#X]
+
+#-----------------------------------------------------------------------------
+level "Level 36 (original)"
+author "Broderbund"
+size 26x16
+[ $ $ $ &$ ]
+[H######H### #####H## ####H]
+[H H H H]
+[ H H - H H ]
+[H H - - H H]
+[ H H- - H ------H ]
+[H------H - H H]
+[ & H- -H H ]
+[###### H - - H &$ $H]
+[## ### H - - H -###XX]
+[ $ $ H - H -###XX]
+[##V### H - - H -###XX]
+[##V# # H - - H -##$$X]
+[ $ $ H- -H -XXXXX]
+[###### H $ @ H$ XXXXX]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 37 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| & ]
+[|#########XXXXXX#XXXX#XXXH]
+[$ H H]
+[## X $ $---$ H]
+[####HH#HH######## # # H]
+[ #HH HH# XX#### & H]
+[ #HH$HH# X #### ###H###H]
+[ ####### X$### H H]
+[ H H]
+[ @ #H#####HXXXH]
+[##H#######H### H $$ H H]
+[ H H H XX ##H]
+[ H##$# H ### XX#### H]
+[ H#### &H $ XX H]
+[#################XX####XXX]
+
+#-----------------------------------------------------------------------------
+level "Level 38 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[| |]
+[#####H####H& &H####H######]
+[ - H HXHXH H - ]
+[H #### H $ ##### H]
+[H #### #HHHHHHH# ##### H]
+[H ##$# #HXXXXXH# #$### H]
+[H #### #HHHHHHH# ##### H]
+[H ------- H]
+[H & H X H & H]
+[HXXXXH $XXX$ HXXXXXH]
+[H H XXXXX H H]
+[H####H XXXXXXX H#####H]
+[H H $XXXXXXXXX$ H H]
+[HXXXXH XXXXXXXXXXX HXXXXXH]
+[$ HXXXXXXXXXXXXXH @ $]
+
+#-----------------------------------------------------------------------------
+level "Level 39 (original)"
+author "Broderbund"
+size 26x16
+[## | ## ## ## | ##]
+[### |#### &#### &####| ###]
+[H ##H# ##H# #H## #H## H]
+[H #H--H #H $H# H--H# H]
+[H&####$H####HH####H$####@H]
+[H## ##H# #H## #H## ##H]
+[H# #H$ H# $H# #H]
+[H## ####HH####HH#### ##H]
+[H ##H# ##H# #H## #H## H]
+[H #H #H $H# H# H]
+[H ####HH####HH####HH#### H]
+[H## ##H# #H## #H## ##H]
+[H# #H H# H# #H]
+[H## ####HH####HH#### ##H]
+[H $ HH $ HH $ H]
+[H########################H]
+
+#-----------------------------------------------------------------------------
+level "Level 40 (original)"
+author "Broderbund"
+size 26x16
+[| #################]
+[| ########X ------#]
+[| $ H# $ XH # $ #]
+[#######HX####### XH ######]
+[ $ HX $ XH ######]
+[H######HX ##V### XH ######]
+[H &$ X $ XH & ]
+[#######HX ##VVV# ########H]
+[ $ HX $ H]
+[H#######X ##V### H]
+[H $ X $ H]
+[#######HX ##VVV# ##### H]
+[ $HX $ # $# H]
+[H#######X ##V### H## H]
+[H & @ H# $ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 41 (original)"
+author "Broderbund"
+size 26x16
+[ --$ --------&----- ----]
+[ $H $#$ H- # -H $$$]
+[@H $# #$ H- ### -H $$]
+[# $# #$ H- # # -H $]
+[ &V # # H- ## ## -H&]
+[H# ### XXX- #$$$# #H]
+[H # # $ HH### H]
+[H - ### $H H##H# H]
+[H - # $H H$$H ------H]
+[H - $H HXXXXH H]
+[XXH ---H H$ $H -----H]
+[ H H######H H]
+[ H###H H$ $H ----H]
+[ H HXXXXXXXXH H]
+[ H & H$ & $H ---H]
+[#######XXXXX########H H]
+
+#-----------------------------------------------------------------------------
+level "Level 42 (original)"
+author "Broderbund"
+size 26x16
+[ $ $ $ $ ]
+[H## H### H#########H]
+[H$ $ H $ H $ $ H]
+[H##H###H #####X##X###X##]
+[H H &H -------------- ]
+[###H######H $ $& H]
+[ H H X####XXXXX###H]
+[ HXXXXX H X $ $ H]
+[ H $ X H X XXXXXXXX H]
+[$$XXX###X H X X $$ X H]
+[##XXX###X H X $ X H###HX H]
+[ $ $ H XXVXX H HX H]
+[######## H X H &HX H]
+[ $ $ X H X#######XXXX H]
+[#####H XXXX####X $ $ @H]
+[###$#H H########]
+
+#-----------------------------------------------------------------------------
+level "Level 43 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ | |]
+[ H#######################H]
+[ H H## $ $ & $ ##H H]
+[ H###H###############H###H]
+[ H H H ### $ $&##H H H H]
+[ ##H###H H#######H H###H##]
+[ H H H H H H###H H H H H H]
+[ H###H###H H $ H H###H###H]
+[$H H H H H&HXXXH&H H H H$H]
+[###H###H$HXHXXXHXH$H###H##]
+[#H H H HXHXHXXXHXHXH H H H]
+[#H## HXHXHXHXXXHXHXHXH ##H]
+[#H HXHXHXHXHXXXHXHXHXHXH H]
+[#HXH H H H H @H H H H HXH]
+[###########H#$#H##########]
+
+#-----------------------------------------------------------------------------
+level "Level 44 (original)"
+author "Broderbund"
+size 26x16
+[#########################|]
+[ HHHHHHHHHHHHHHHHHHH |]
+[ @ H HHH H HH H & |]
+[###H HHH HH H HH H HHH###|]
+[ H HHH HH H HH H H |]
+[ & H HHH HH H HH H HHH & |]
+[###H H H HH H###|]
+[HHHHHHHHHHHHHHHHHHHHHHHHHH]
+[ $ H $ H $ H $ H $ H $ H]
+[HHHHHHHHHHHHHHHHHHHHHHHHHH]
+[ H H H HH H HH H H H]
+[ H H H H H H H H HHH H H]
+[ HH H H H H H H H HH]
+[ H H H H HH H HH H HHH H H]
+[ H H H HH H HH H H H H]
+[HHHHHHHHHHHHHHHHHHHHHHHHHH]
+
+#-----------------------------------------------------------------------------
+level "Level 45 (original)"
+author "Broderbund"
+size 26x16
+[XXXXXXXXXXXXX | XXXXXXXXX]
+[ &H H--- | H $ ]
+[XXX|##XXX#V#XXX| HXXXX HX#]
+[X--H H----H H #####]
+[X H $ #$#H& H $ ##]
+[$ VH H X#H XX####X#]
+[X#VH-----H-----XH-------HX]
+[#$ X H $HXXX H#]
+[XXV# $$$H HX---- $ HH]
+[ H HXH $ V#XH]
+[###V# H @ HXH H]
+[H---- HX##X##VXXH H]
+[H$ #H H#H X#### H]
+[HX--###H HXH # $ X H]
+[H ###X#H & H H #XX#XX]
+[#####XXXX#############X###]
+
+#-----------------------------------------------------------------------------
+level "Level 46 (original)"
+author "Broderbund"
+size 26x16
+[ $ | ]
+[####H & | ]
+[ $ H H######H $ ]
+[#######H######H ######]
+[ H H $ $ ]
+[ $ H H###########]
+[#H#####H $ H ]
+[ H $ HXXXXXXH $ ]
+[#H#####H #####H#####H]
+[ H & $ H H]
+[ $ H###H#######XXXXXXX]
+[###H#### H $ $ & ]
+[ H H########H######]
+[ H------H H ]
+[ H @ H $ ]
+[######################|###]
+
+#-----------------------------------------------------------------------------
+level "Level 47 (original)"
+author "Broderbund"
+size 26x16
+[ XXXXXXXXXXX|]
+[& & X $ X |]
+[X------####H @X HX XHX###|]
+[##### $ ##XX HX XHX###|]
+[ ###### HX XHX |]
+[##H ###H $ HX XHX $ |]
+[ ###X#H H###XX XHX###|]
+[ $ ##X#H H X XHX###|]
+[#### ####H X XHX |]
+[ $ #XH# ##X##HX XHX$$ |]
+[## H##XX# $ XHX XHX###|]
+[ #X##H ##XX#XHX XHX###|]
+[ ###X##H $ XHX XHX ##|]
+[ H## $###X#H#XHX XHX #|]
+[ H# H $HX H $|]
+[$H#X###X#####X##XX##X#####]
+
+#-----------------------------------------------------------------------------
+level "Level 48 (original)"
+author "Broderbund"
+size 26x16
+[ $ ]
+[ ------- ####H@ ]
+[H $ H $ $ ]
+[H HXXXX #####H#####]
+[H H $ H ]
+[H######H ####H H ]
+[H H $ H&H#########H]
+[H H HXXXX HXXXXXXXXXH]
+[H $H# H $ HX $ XH]
+[H H# ####H HXHXXXXXHXH]
+[H $H# $ H HXHX $ HXH]
+[H H# HXXXX HXHXXXXXXXH]
+[H H# H $ HXH $ H]
+[HH# ####H HXXXXXXXXXX]
+[HH & | H & ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 49 (original)"
+author "Broderbund"
+size 26x16
+[ - - - - $ $ ]
+[- - - - H - - H######]
+[ -- -- H - - H ]
+[ H -- H & ]
+[ $ $ $ H - HXXXXXH]
+[XXXXXXVXXXXXH- HX $ XH]
+[ X HXHX$XH]
+[ $X @ $ HXHX$XH]
+[H########H#XXH####-HXHX$XH]
+[H & H##HH HXHX$XH]
+[H ## H##H $& XHX$XH]
+[H ## ## H##XX#####HXH----]
+[H ## ## H## H ]
+[H ##$$## H# --$H #### ]
+[H $$##$$ H## H# #H##$$##]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 50 (original)"
+author "Broderbund"
+size 26x16
+[H - H----]
+[H H H X ]
+[H H & H X$$]
+[H $ H### $ $H####V#H###]
+[H## H ######### HH#V]
+[H H HHV]
+[H H-----------------HH]
+[H H H]
+[H H$ & $ $H]
+[H ####HXXXXXXXXX##V###]
+[H--- H --- ]
+[ &$ H H ]
+[########H H $ H- $ ]
+[ #####HXXXH### #$###]
+[$ @ H H & #####]
+[############H H#########]
+
+#-----------------------------------------------------------------------------
+level "Level 51 (original)"
+author "Broderbund"
+size 26x16
+[##XX# |X#XX###X]
+[#XX## |#XX###XX]
+[ X#X# $ $ |#X X]
+[H X##X###XH##X |#X #XH X]
+[HX X#XX###XH ##$|X #XH X]
+[H# X##XXH #### $#XH X]
+[H##$ #XX#H ##XH$ ]
+[HX#### X##H ------#XX#H]
+[HXX#X##$ #XH $ #X H]
+[H H## XX#XX# #X H]
+[X##XXHX## $#X H]
+[##XXXH#X##$ & $###X H]
+[ $ HXX###VXXXXXV###XXH##]
+[HX###XX & @ HX#]
+[H###X H##XX#XX#X#XX##XXX#]
+[H $ H & X#X]
+
+#-----------------------------------------------------------------------------
+level "Level 52 (original)"
+author "Broderbund"
+size 26x16
+[ H ]
+[ H $ & ]
+[---- $ | XXXXXXXXXXXXH]
+[H XXXXXX H]
+[H ---- ----- HXXXX]
+[H-------- H H ]
+[ & $ H# H ]
+[HXXXXXXXXXXXXXXXX# XXXXH]
+[H HH]
+[H $ $ & X H ]
+[XXXX##XXXH #X#XXXXXXXX H ]
+[ H H ]
+[ $ H $ H ]
+[HXXXXXXXXX XXXXXXX H ]
+[H ------H ]
+[H @ & ]
+
+#-----------------------------------------------------------------------------
+level "Level 53 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ & & $ $|]
+[ H############# H####]
+[ H ########### H#####]
+[H##### #$##$##$# H######]
+[H###### &H#######]
+[H############V######## ]
+[H####### $ $ $ $##### $$ ]
+[H#########V##V############]
+[H & $###### ]
+[H H#####H#####H -H#### $H]
+[H H H H H H ### $H##]
+[H H$$H$$H$$H$$H # $H####]
+[H H#####H#####H $H######]
+[H @ H########]
+[H#########################]
+
+#-----------------------------------------------------------------------------
+level "Level 54 (original)"
+author "Broderbund"
+size 26x16
+[| ############]
+[| $ $ ############]
+[#############H $ ]
+[#########################H]
+[ $ & & $ H]
+[H#########################]
+[H $ $ ]
+[#########################H]
+[ $ $ $ H]
+[H#########################]
+[H $ & & & $ ]
+[#########################H]
+[ $ $ $ $ H]
+[H#########################]
+[H $ $ @ ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 55 (original)"
+author "Broderbund"
+size 26x16
+[###########| #############]
+[#---------#| #---------# ]
+[ #$ H $# | #$ H $# ]
+[ #$ H $# | #$ H $# ]
+[ #$H$# | #$H$# ]
+[ #H# |XXXXX##H# ]
+[ @ #H# |X $ #H# & ]
+[###H#H#####V#######H#####H]
+[ H H & H H]
+[H##X#H#############H#X####]
+[H---#H#-----------#H# ]
+[H $# H #$ $# H # ]
+[H$# $H$ #$ $# H # ]
+[H# $#H#$ #$ H### H #$ ]
+[H $##H$#HH#H#X# & H $ ##]
+[#########H H $############]
+
+#-----------------------------------------------------------------------------
+level "Level 56 (original)"
+author "Broderbund"
+size 26x16
+[$$----$$$ $$$-----------$$]
+[## ###H### ##]
+[## ###H### ##]
+[## ###H### $$$ ##]
+[## ###H### ### ##]
+[## ###H### ### ##]
+[## ###H### ### ##]
+[## ###H### ### ##]
+[## ###H### ### ##]
+[##$--$###H###$--$###$--$##]
+[###$$####H####$$#####$$###]
+[#########H################]
+[######## H ####### #######]
+[ ###### H ##### ##### ]
+[ & @H & ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 57 (original)"
+author "Broderbund"
+size 26x16
+[|#########################]
+[|------------------------ ]
+[|#XXX#XXX#XXX#XX#XH#X---#H]
+[|# $ $ $ H $H#H]
+[|$HXXXXXXXXXXXXXXXXXXXXHXH]
+[|#H#----------------X $H#H]
+[|$H# XXXXXXXXXXXXXXXXX###H]
+[|#H# X $$$$$$$$$$$$ $#$H]
+[|$H# X###XXXXXX#XXXXXH###H]
+[|#H# & H$#$H]
+[|$H#XXXXXXXXXXX##XXXXH# #H]
+[|#H------------------ H#H]
+[|#XX##XXHXX#X#XXHXXXXXXH$H]
+[| & H XX H & $H#H]
+[XXX#X###XXXXHXX#X#XX##XX#H]
+[@ H H]
+
+#-----------------------------------------------------------------------------
+level "Level 58 (original)"
+author "Broderbund"
+size 26x16
+[#################### |]
+[ @##--- XX $ |]
+[ #X $ HXX######HH H#H H |]
+[ # H XX# HH$H H H |]
+[ #H####X##$ # HH H H#H |]
+[ H# X## HH H H H |]
+[$ H# $ #X# H# H H H H |]
+[#HH##V#X###X# H#$#|##H#H |]
+[#H & H#V#|# H H |]
+[#H##X#######XHHH #|# H H |]
+[#H #X#######XHH #|# H H&H]
+[ H X $ XH #|#HH###H]
+[ HH#X#######XH $ #|#H& H]
+[ #H#X#######XHXXX#|#### H]
+[ #H# $ XX# | # H]
+[ $H #XXXXXXXXX# & | ####]
+
+#-----------------------------------------------------------------------------
+level "Level 59 (original)"
+author "Broderbund"
+size 26x16
+[ -- $ -$ $ ]
+[ H ## H ## ##H ]
+[ H $& H H $]
+[ $H-- ##$H &$ HH#]
+[##H H$& #H ## $ H ]
+[ $ H## H ## H ]
+[ ## H- --&$--H H ]
+[ $ H ## $ $- H$]
+[ ## H ## ## H$H##]
+[ - $H $ H## ]
+[ H ##H ## $ H ]
+[ $ H $ ## $ H$ ]
+[H##H ## ## H## ]
+[H ]
+[H @ ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 60 (original)"
+author "Broderbund"
+size 26x16
+[ ----- ]
+[ ----H &$ $ ]
+[ ----H & $ #####H]
+[ ---H $ ##### $ H]
+[H @$ #### $&#V#H]
+[H V#V ## #### $ #V### #H]
+[H $ $ $ # $ ##V# $ #H]
+[H ## V#V # #### $###H#H]
+[H $ $ $ # # $ #V#V #H#H]
+[H ### V# # # ##V# $ #H#H]
+[H $ $ $ # # # $ ##H#H#H]
+[H #V V## # # # #####H#H#H]
+[H $ $ $ # # # # #H#H#H]
+[H ##V V# # # # # $ #H#H#H]
+[H &# # # #####H#H#H]
+[########### H H H]
+
+#-----------------------------------------------------------------------------
+level "Level 61 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ $ & $ XHX --------@ ]
+[HX###X# XH$ ### ]
+[HX XHX $ $]
+[HX--- XHX ####--- H]
+[HX $XHX $ $ H]
+[H $X##XXHX### H### H]
+[HX#XX XHX &$ H# H]
+[HX------$HX ######## H]
+[HX $ XHX $ $ H]
+[HX X##XHX--####-- H# H]
+[HX$ XHX $ H H]
+[HX## XHX ##### H]
+[H & H H]
+[X###X###XXXX###X####XX#XXX]
+
+#-----------------------------------------------------------------------------
+level "Level 62 (original)"
+author "Broderbund"
+size 26x16
+[#|####|#####|#####|#####|#]
+[ |$& | | $ | $ | ]
+[H########V####V##########H]
+[H#$ &$ $ #H]
+[H#####V########V#######H#H]
+[H# $ $ #H#H]
+[H#H####V####V#####V##H#H#H]
+[H#H# #H#H#H]
+[H#H#H#$ & $ #H#H#H]
+[H#H#H###V##V###V#####H#H#H]
+[H#H#H $ $ H#H#H]
+[H#H###V############V###H#H]
+[H#H $ $ H#H]
+[H###V####V####V######V###H]
+[H & $ @ $ & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 63 (original)"
+author "Broderbund"
+size 26x16
+[ & ]
+[#########################|]
+[$& # $ # $ |]
+[##H# #H#H######## #H# ##H#]
+[##H#H#H#H# $ # #H# ##H#]
+[##H#H# #H# #### # #H# HH]
+[$#H#H#H#H#H#@ # # #H# ###H]
+[ H#H#H#H#H## # # #H# H H]
+[H#H#H#H#H#H $# # #H# H###]
+[H## H#H#H###### # #H# H H]
+[H# #H#H#H $ # #H -###H]
+[H -#H#H########## #H# H H]
+[H# #H#H #H# H###]
+[-# #H##############H# H H]
+[ H & H# ###H]
+[##################### & H]
+
+#-----------------------------------------------------------------------------
+level "Level 64 (original)"
+author "Broderbund"
+size 26x16
+[X| |X]
+[X| &$$$$$$$$ $$$$$$$$$& |X]
+[XXXXXXXXXXXX|XXXXXXXXXXXXX]
+[ $ $ | $ $ ]
+[ XHXXXX | XHXXXX ]
+[ H$ $ | H$ $ ]
+[ XXXXXXHX | XXXXXXHX ]
+[ $ $H | $ $H ]
+[ XHXXXXXXXX | XHXXXXXXXX ]
+[ H $ $ | H $ $ ]
+[XXXXXXXXXXHX|XXXXXXXXXXXHX]
+[ $ $ H | $ $ H ]
+[XHXXXXXXXXXX|XXXXXXXXXXXXX]
+[ H ]
+[ H $ $ @ $ $ &]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 65 (original)"
+author "Broderbund"
+size 26x16
+[ ####### ]
+[--------$ &| ###### ]
+[H H#H---- | ######H]
+[H HV#VH $H$ | ## #H]
+[H-----HV#VH ###H | #$ #H]
+[H HV#VH&###H | ###H]
+[H& HHHHH ###H | ##H]
+[H---- XVHVX ###H | #H]
+[#$ H XVHVX H ||H]
+[##$ H XVHVX H--H---------H]
+[###$H XVHVX H ]
+[####H&XVHVX H------H##$###]
+[ H XVHVX H HX######]
+[ H XVHVX H HX#######]
+[ H @H H HX#######]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 66 (original)"
+author "Broderbund"
+size 26x16
+[######HH----------HH######]
+[#####HH - - HH#####]
+[####HH #&&# HH####]
+[###HH - #### - HH###]
+[##HH - ###### - HH##]
+[#HH----- ######## -----HH#]
+[HH - ####$$#### - HH]
+[H ############ H]
+[HH - ####$$#### - HH]
+[#HH - ######## - HH#]
+[##HH - ###### - HH##]
+[###HH - #### - HH###]
+[####HH - - HH####]
+[#####HH HH#####]
+[######HH& @ &HH######]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 67 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| # & # & & ]
+[|-----$H#H ##H##||#||##H ]
+[H #H #H# H# $# $# H ]
+[H @ # # H# H# # H ]
+[##### ## H# # # H ]
+[ # $# H# $# # H ]
+[ # # HHH # # ####H]
+[ $# $# #HH# ## V H]
+[## # $# H# # # # H]
+[# $# # H# # # #$ H]
+[ # $# H# $# H# #$ # H]
+[ $# # H# # H # # # H]
+[ # $# H# # H #$ # #H]
+[ # HH $ H # H]
+[ H################## H]
+
+#-----------------------------------------------------------------------------
+level "Level 68 (original)"
+author "Broderbund"
+size 26x16
+[XXXXXXXXXXXXXXXXXXXXX| ]
+[ & | ]
+[ H#X##XX#HX | ]
+[ H |HX#X##XX#| ]
+[ ##XH H|H# # &#-------]
+[$ H $|H|## # X# $]
+[ H H|H|# # # &]
+[H H H|H|# $#@ # #]
+[H H H|X## ## # $#]
+[HXXXXV#XX|X # # ##]
+[H --------X-----# # $ #]
+[H $ H ## # ###]
+[H HXVXXXHXXX#H# # $# ]
+[H HX XHX #H####V#X# $ ]
+[H HX XHX$ #H ##X]
+[H $HX & XHX#####XX###X####]
+
+#-----------------------------------------------------------------------------
+level "Level 69 (original)"
+author "Broderbund"
+size 26x16
+[H & # ------------]
+[H#### #H ]
+[H#### #H #X#X#X#X#X#]
+[H#### #H $ $ $ $ $ $]
+[H##$# #H#V#V#V#V#V#V]
+[H#### $ & #H#V#V#V#V#V#V]
+[H############H------------]
+[H############H X X X X X]
+[H @ & H #V#V#V###]
+[H#######H#######H V###]
+[H#######H #####H####HV###]
+[H#######H#$ ###H####HV###]
+[H#######H###$ #H & HV###]
+[ H##### H####HV###]
+[ $ $ H#######H####HV###]
+[################H $$ HV###]
+
+#-----------------------------------------------------------------------------
+level "Level 70 (original)"
+author "Broderbund"
+size 26x16
+[ |]
+[ |]
+[ &-$$$-|]
+[ $- H$###$H]
+[$H# $- $H#####H]
+[#H # $ #H##$##H]
+[ H $- #H-H#####H]
+[ H # $ -H $###$ ]
+[ H #H ]
+[ H $ H $$$$ ]
+[ H # $ -H $####$ ]
+[ H #H ####HV ]
+[ H $- H ###HV# ]
+[ H # $-H ##HV## ]
+[ H $# H #HV### ]
+[ H @ # H & HV#### ]
+
+#-----------------------------------------------------------------------------
+level "Level 71 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | & ]
+[ | H#####H ]
+[$H####H#H& $ H# #H ]
+[H#####H#####H##H######H##H]
+[H XH $ XH XH X# #H $H]
+[H ###XH X# XH XH $X# #H #H]
+[H $##XH $XH XH # # #H #H]
+[H ###XH # #XH XH XX #H #H]
+[H $XH X H$#H ##$ #H&$H]
+[H#####H#####HV#H######H##H]
+[H$------ $$ H & ## X$H]
+[XXH ##XXX##HXX#$ $XH]
+[ H###$#XXXXX#HXXXXXXHXXXH]
+[@ H#$##$$$$$$ H$ H H]
+[XXXXX####XXXXXXX##########]
+
+#-----------------------------------------------------------------------------
+level "Level 72 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| -----------------##]
+[H $& H #]
+[H##V#### H #]
+[H # H $&H ## $#]
+[H $ H # $ --H###H######]
+[H###H$ ##### $ H H ]
+[ H#########VH H $ ]
+[H H## $ ###VH $#H-----#]
+[H###H#########VH###H $ H #]
+[H #--------H#$#HV##H #]
+[H$&H # $ H###H H #]
+[###H # $ ## H###H H #]
+[ H # $ ## H###H H #]
+[ H @#### $ H###H &H #]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 73 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ |||||||@| |& ]
+[ & | || ||X ]
+[ $H$ | || ||XXX ]
+[ $HHH$ | || ||XXXXX ]
+[$HHHHH$ | |||XXXXXXX]
+[HHHHHHH | $& $ |---HHH ]
+[ H ############ H ]
+[ $X$ # $ $ # H ]
+[ $XXX$ # -------- # H ]
+[ XXXXX # H H # H ]
+[ XXX # H H # H ]
+[H#####H#$H & H$# H ]
+[H H############ H ]
+[H H H H H ]
+[H#####H############H#####H]
+
+#-----------------------------------------------------------------------------
+level "Level 74 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | XXXXXXXXX]
+[XXXX|XXXXXH----H ]
+[ | H @ H & ]
+[####H#####################]
+[#H H H### #### ]
+[HH#####H### ## ###########]
+[H###### H## $# ### ## ## ]
+[H# ### #H## ## ### $### $ ]
+[H## $ ##H## ### ## $## ]
+[H#######H#########V#######]
+[H # #$ HH &H]
+[H####### H########H######H]
+[H $### H ##H H]
+[H & H $ ##H $ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 75 (original)"
+author "Broderbund"
+size 26x16
+[ $ $ ]
+[ $ $ ##H## $ $ $ ]
+[ ##H## H ##H## #H#]
+[ H H H H ]
+[ H H H H ]
+[ H &H $$ H H ]
+[ H H ## H --- H]
+[ H H H H ]
+[ H H ----- H H@ ]
+[ H ----- &H H ##]
+[ H $$ H H ]
+[ H ## H H ]
+[ & H H H & ]
+[#####VVVVVVVVVVVVVV######H]
+[ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 76 (original)"
+author "Broderbund"
+size 26x16
+[############## |]
+[ # |]
+[ ------------HH#######$ |]
+[ H# $ # #--H]
+[$ $& @ H# # #& H]
+[H######HXXXXXX#XX H # H]
+[H #H ### H H]
+[H$ #H------- & #H H]
+[H ##XH #######H H]
+[H ##$XH ### #H####]
+[H # XH $##$# $$ #H## #]
+[H# XH ## #######H# # ]
+[H#$ XH ## #-----#H## #]
+[H HHH# # $ #H#$# ]
+[H H#H #H## #]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 77 (original)"
+author "Broderbund"
+size 26x16
+[ --- $$$$$$$ --- ]
+[H ################## H]
+[H XX##################XX H]
+[H ################## H]
+[H&XH##################HX&H]
+[XXXH# # # ###HXXX]
+[ H#$$$$#$$$$#$$$$###H ]
+[ H##################H ]
+[ H##################H ]
+[ H##################H ]
+[ H### # # #H ]
+[ H###$$$$#$$$$#$$$$#H ]
+[ H##################H ]
+[ H##################H ]
+[ H##################H ]
+[ H @H ]
+
+#-----------------------------------------------------------------------------
+level "Level 78 (original)"
+author "Broderbund"
+size 26x16
+[# #|]
+[# $ & ----------$#|]
+[############HH & $ H##|]
+[### HH########## |]
+[#### $ & HH ## |]
+[############HH $ ###H |]
+[###### HH####### H |]
+[ $ ## $ HH ###V#H |]
+[H###########HH$ ## H |]
+[H# # #### HH#### $ H |]
+[H H#H# $## HH #####V##H |]
+[XXH H#H####@HH # $ H |]
+[XXXXH H# ###HH####V####H |]
+[XXXXXXHHH# #HH# H |]
+[ H H HH H |]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 79 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ & X | & $]
+[HXXXX XXXXXXXHXX #|#H###]
+[H --- HX$##H#|#H###]
+[#H## ## H#& H ###H#|#H#$#]
+[ H ##$# H # H## H#|#H###]
+[H ####VH #H H###|#H ]
+[H @ H # H# | ###H]
+[H####### # $# $H#H######H]
+[H#######V# # ####H## H]
+[H#######V# $##H #####]
+[H#$ ##V#----H# #H----- ]
+[H# $##V#H # #$ # #H]
+[H#######V#H #######H##$#H]
+[H ##$ H ## H ###H]
+[H#########H########## H]
+
+#-----------------------------------------------------------------------------
+level "Level 80 (original)"
+author "Broderbund"
+size 26x16
+[ -----------$ ]
+[XXXXX ## #XXXXXX#H ]
+[X----- $$ # #H ]
+[XH ###V # $#H ]
+[XH$$ $ $ ######V#H ]
+[XXXH $ #V## &HH ]
+[ H $ $ &-- H ]
+[ H #XXXXXXXXX#-- H ]
+[ H$& $ #& $ # H ]
+[ H####H######V#### H ]
+[ # #H H ]
+[ # #H H ]
+[ #$$#H H ]
+[ ##V#H H ]
+[ H & @ H ]
+[###XXXX###XXXX###XXXX###XX]
+
+#-----------------------------------------------------------------------------
+level "Level 81 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| ]
+[XXXXXH HXXXX]
+[# H & & H ]
+[# H#######XXX#####H ]
+[# H H ]
+[# --H H ]
+[# $ $H $#$ $$$H ]
+[# #$#H-- # # $$$ ###H-- ]
+[# #$#H$ $--$# ### #$#H$ $-]
+[# ###H#$# $#$ $$$ ###H#$# ]
+[# #H$#$ ### ### #$#H$#$ ]
+[# #H#$# ###H#$# ]
+[# H-H H-H ]
+[# H @ H ]
+[##XX#########XXXX#########]
+
+#-----------------------------------------------------------------------------
+level "Level 82 (original)"
+author "Broderbund"
+size 26x16
+[XXXXXXXXXXX | XXXXXXXXXXXX]
+[--------H#X-|-X#H---------]
+[ $ H#--|--#H $ ]
+[ $ ##H--$|$--H## $ ]
+[ $##V-HH#X#|#X#HH-#V# $ ]
+[ $##--H-#V-H|H-V#-H--###$ ]
+[$##--H-----H|H-----H---##$]
+[V---H------H|H------H----V]
+[---H&------H|H------&H----]
+[ H######VH@HV######H ]
+[ $ H ### H $ ]
+[H H & #$# & H H]
+[H--H#V#####H H#####V#H---H]
+[H$ H H H H $ H]
+[H H $ H H $ H H]
+[########X#######X######XXX]
+
+#-----------------------------------------------------------------------------
+level "Level 83 (original)"
+author "Broderbund"
+size 26x16
+[----$ $$@#|]
+[ #H H####|]
+[ #H HV####|]
+[ #H H#V# #|]
+[ #H H##V#$ #|]
+[$ & #H H#$#V#VV#|]
+[### #H H# H#V# #|]
+[$ #$ #H$ H# $H#V# #|]
+[##H # ##H H####H#V# #|]
+[$ #H #$ #H$&H# $ $H#V# #|]
+[#H #H # ##H######H#V# #|]
+[$#H #H #$ #H $ $ -H#V# #|]
+[H #H #H # #H##### H#V#VV#|]
+[#H #H #H H#V# |]
+[ H H H & H |]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 84 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[& $#$ |#$ ]
+[#####H#######H#H#########H]
+[$ #H $ H#H # H]
+[###H#####H########H#H#####]
+[$ H H & H#H $]
+[#H#############H##########]
+[$H##$ # $#H & #$ ]
+[#########H#######H########]
+[##H &H##$ ## H ## $#]
+[##H####H########H##H######]
+[$ H####H# $####$H##H ##]
+[##H####H########H#####H###]
+[##H #H # @ H # H $]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 85 (original)"
+author "Broderbund"
+size 26x16
+[ & $ ]
+[ $ ######H# $ ]
+[ ###V#### H#####V# ]
+[ # # H# # ]
+[ # &$ # H# # ]
+[####### $ #$ #H#####$$# ]
+[# ###V#####H #V####]
+[# # $ #H &$ - #]
+[# # H########### H#]
+[# $ $# H# $ H#]
+[# ##### H# $ H#H H####]
+[### # $#H#### H###V# ]
+[ # $ ####H # $H# ]
+[ ##### #H ###V# ]
+[ H @ ]
+[X#X#X#X#X#X#X#X#X#X#X#X#X#]
+
+#-----------------------------------------------------------------------------
+level "Level 86 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[|------------------------|]
+[HH HH]
+[H #V## ###V## ###### H]
+[H # ## # # # V H]
+[H # ## # # H]
+[H # # # # H]
+[H # $# # $ # H]
+[H # ## # ## # $ H]
+[H #$ ## # $# #$ $# H]
+[H #### ###V## ##V### H]
+[H @ H]
+[H H###### ###### #H#### H]
+[H H# $# ######H#H##$# H]
+[H&H# #&## $##H H#### H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 87 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[ H$ $H $H $H ]
+[ $H H$ H$ H$ ]
+[@H$ $H &$H & $H &]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 88 (original)"
+author "Broderbund"
+size 26x16
+[ --------# & ]
+[H # $ H###H # #H]
+[H VVVVVV ####HX HX H # #H]
+[H VVVVVV # $HX HXHXH # #H]
+[H VVVVVV #H###X HXHXH # #H]
+[H VV$$VV #H $ X HXHXH # #H]
+[H VVVVVV ####HX HXHXH # #H]
+[H VVVVVV # $HX HXHXH #$#H]
+[H &#H###X HXHXH ##VH]
+[H#########H $ X HXHXH H]
+[H############HX##XHX#####H]
+[H######### $HXXXXHXXX###H]
+[H##$$#####H###X $ |$ X$##H]
+[H########$HX#XXXXXXXXX###H]
+[HXXXXXXXXXX $ &$ H]
+[H @ H##############]
+
+#-----------------------------------------------------------------------------
+level "Level 89 (original)"
+author "Broderbund"
+size 26x16
+[|#XXX#XX##X##XX#X XX#XX##X]
+[H|||||X|X#XX#|X||||||XX###]
+[H @ $|X| $$$ | | & | $ |]
+[HX#X#|X|#X##XH#HX###H####|]
+[H $ |X| $$$ H H $##H###X|]
+[HX#X||X| ### H H XX$H$##$|]
+[H||| $X| H$H #XHX#XX|]
+[H ##X| $ HXH $ H----|]
+[H$ &| X| ### HXH #XH $X#]
+[H####HX| # H$H # H ##$|]
+[H X HX||||||HXH # H XH]
+[H X H---------H$&# HX$$$H]
+[H X$HX####H $XH##########]
+[H X#HX #####X#X-------H]
+[H $ H $ $ & $$$H]
+[######X#XXXXXXXXXXXX#XXXXH]
+
+#-----------------------------------------------------------------------------
+level "Level 90 (original)"
+author "Broderbund"
+size 26x16
+[ H | ]
+[ -- H | ]
+[$ $ -- H --H $|& ]
+[####H-- H & ---#V##H#H ]
+[ H X#V#H ---$#$ |#H ]
+[VV###H $ H-HXX X######H ]
+[V$ H X H XXXX --H ]
+[ V$ H $H $ HX ]
+[ #$ H#V##HXXXXXXH#VXHX ]
+[ H#$H H $ H HX ]
+[ H VHX H#V####H##XHX ]
+[ H -H $ H $ H XHX ]
+[ HX $ X H####V#H X$H$X ]
+[ H X H $ H XXHXX ]
+[ H H##V###H &H ]
+[##########H & @H########]
+
+#-----------------------------------------------------------------------------
+level "Level 91 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ | ]
+[ ----- & H#H & -----]
+[ H---H#$H#H$#H---H ]
+[ H#$#H H#######H H#$#H]
+[ H### H-H# #H-H ###H]
+[ HH# H###H #HH]
+[ H# H# #H #H ]
+[ H# H###H #H ]
+[ H# H# #H #H ]
+[ H# H###H #H ]
+[ H# H# #H @ & #H ]
+[ H########H###H########H ]
+[$ H# $ #H $ H# $ #H$]
+[XXXXXXXXXXXXXXXXXXXXXXXXXX]
+
+#-----------------------------------------------------------------------------
+level "Level 92 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ $ #&#|# ]
+[ H--H########## #|# ]
+[$ ----H # $ # #|# ]
+[#H # ##### #|# ]
+[##H & # $ #|# ]
+[###H $ # ---- #|# ]
+[####H ----#$ $# H | ]
+[XXXXXXH ###### H--| ]
+[ H ###### H #####]
+[ H ###### H #$ & ]
+[ H ###### H ####H]
+[ H H H]
+[ --H H H]
+[& $# H @ H H]
+[#### H##$#########H ###H]
+
+#-----------------------------------------------------------------------------
+level "Level 93 (original)"
+author "Broderbund"
+size 26x16
+[ || ]
+[ & HHHHH $$||$$ HHHHH & ]
+[ HHHHH H######H HHH H ]
+[ H#H H H H $ H H H H#H ]
+[ H#H H H H######H H H H#H ]
+[ #H H H-H @ $ H-H H H# ]
+[ $X H X-########-X H X$ ]
+[ VH H H-H######H-H H HV ]
+[ HVH H H-H######H-H H HVH ]
+[ HHH H H H#VV#H H H HHH ]
+[ HHH H H H#VV#H H H HHH ]
+[ HH H H #$$# H H HH ]
+[ HHH H H HHH ]
+[ HHHH HHHH ]
+[ HHH HHH ]
+[ &H##########H& ]
+
+#-----------------------------------------------------------------------------
+level "Level 94 (original)"
+author "Broderbund"
+size 26x16
+[$ #############|##########]
+[H#--- - $#|# ]
+[H#$# #### #####|#H###H###H]
+[H#$# # # $#|#H###H###H]
+[H#$# #$$#######|#H #H&$#H]
+[H#$# ##########|###H#H###H]
+[H#$# $ & | #H#H###H]
+[H#$#####H####$ | $#H#H H]
+[H#$# H #######H#####H]
+[H#$#H###$##H $ #H $ #H]
+[H#$#H# $ #######H#######H]
+[H#$#H H##H&$ #H $ #H]
+[H#$############H#######H#H]
+[H#$#$ # $ # $ H$ # $ H#H]
+[H#V#H#H#H#H#H######H#####H]
+[H $ H#H$H#H$H##@ $ H $ H]
+
+#-----------------------------------------------------------------------------
+level "Level 95 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ | ----- -----H]
+[ &H - H --&H H]
+[V#H---H #V## H# #H ##V##]
+[V# H##V### H# #H ##V# ]
+[V# H##&- H# #H ## ]
+[V# H##H ## H# #H- # ]
+[V# $ H##H$## H#$ #$HVV$@ ]
+[V --H-H##H ## H# # H#### ]
+[## HH ##H # H# # H#### ]
+[##HH ##H V -H# # H## ]
+[##H ##H ## # # H## ]
+[##H $--##H $ # $# H $ ]
+[#####H ######H ##V# H####H]
+[#####H $#### H $#V$ H#####]
+
+#-----------------------------------------------------------------------------
+level "Level 96 (original)"
+author "Broderbund"
+size 26x16
+[ - & ### & $ ### ]
+[H H####H###H###### ######H]
+[H H####H $H###$## ###$##H]
+[H H#$$#H########## ####H]
+[H #####H -------------H]
+[H #H& $ $ ]
+[H#V#H #H####V#######H$ $ ]
+[H$ #H #H---- -----HXXXXXXX]
+[## #H #H $ $ H @$ $ ]
+[ $H #H####V#####H######H]
+[##HXX #H----------H H]
+[##H $H $ X#####H H]
+[##H#############|X $ H H]
+[$#H# |X####V# H]
+[##H# $ $ |X & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 97 (original)"
+author "Broderbund"
+size 26x16
+[ HH---HHHHH####]
+[ H##H--H$$ H####]
+[ H####H HH$H H H]
+[ H######H HH$H$H]
+[ H######H HHHHH]
+[ H#X#XVXH H H H]
+[ H$X#XV$H H H H]
+[ H#X#XVXH H$H$H]
+[$--------H#X#XVXH HHHHH]
+[H$ H$X#XV$H H H H]
+[#H$ H#X#XVXH H H H]
+[##H$ H#X#XVXH H$H$H]
+[###H$ H$###V$H HHHHH]
+[####H$ H######H H H H]
+[#####H$ HX# #X #XH @H$H$H]
+[######H&HX# #X #XH&H######]
+
+#-----------------------------------------------------------------------------
+level "Level 98 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[|XXXX XXXXXXXXX#XXXXXXXXX$]
+[| $ $---- --------H]
+[| H## ##### ##H]
+[| $ H $# # $#$H]
+[| ###H $ @ ## #V##XH]
+[| $ H#####H # & H]
+[| ### H# #H #---H####]
+[| & H#$ #H # H--- ]
+[| H#########H### H $ ]
+[### H#$ # $ # # H ###]
+[$ ##H######### # H # ]
+[####H---$$X$$#$ ##XXXHX##]
+[ #H ###X#####H# H $]
+[ $ #H $ HH & H#H ]
+[####H############H########]
+
+#-----------------------------------------------------------------------------
+level "Level 99 (original)"
+author "Broderbund"
+size 26x16
+[ --- $ $ --- X #H]
+[## #H H###H H& ##X H]
+[ ## #H H#########H ##X #H]
+[## #H####$#$#####H #$X##H]
+[$##$#H & H #H]
+[###############V#########H]
+[ $ & $ @ & H]
+[XXXXXXXXXXXXXXH###########]
+[ ----------- XH ]
+[H - HXH---------- ]
+[H - - HX## ## ## ##H]
+[H - # - HXXXXXXXXXXXXH]
+[H - ### - H------------H]
+[H - ##### - HV#V#V#V#V#V#V]
+[H- ##$$$## -HX ]
+[H ######### HX & ]
+
+#-----------------------------------------------------------------------------
+level "Level 100 (original)"
+author "Broderbund"
+size 26x16
+[ & & &- ]
+[ H###### H##H]
+[ H# # H##H]
+[ H###### # H##H]
+[ H # # H##H]
+[ H###### #$$$# H##H]
+[ H# # ##### H##H]
+[ H##### #$$$# H##H]
+[ &H# # ##### H######H]
+[##### #$$$# &H# #H]
+[# # ##### H###### #H]
+[# #$$$# H# # #H]
+[# ##### H##### $$$#$$$#H]
+[#$$$# H#XXXXXX#XXX#XXH]
+[##### H##### @ H]
+[ H###################]
+
+#-----------------------------------------------------------------------------
+level "Level 101 (original)"
+author "Broderbund"
+size 26x16
+[H H]
+[H H#$##H H##$#H H]
+[H$& H####H H####H $H]
+[###H H####H----H####H H###]
+[ H H##$#H H#$##H H ]
+[ $&H H####H H####H H$ ]
+[H### H####H H####H ###H]
+[H H#$##H----H$###H H]
+[H$ H####H H#$##H $ H]
+[###H H##$#H H####H H###]
+[ H H$###H H##$#H H ]
+[ $ H H####H----H####H H $ ]
+[H### H#$##H H###$H ###H]
+[H H####H H#$##H H]
+[H @ H##$$H & H####H & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 102 (original)"
+author "Broderbund"
+size 26x16
+[--------- H ----- ]
+[ H H H ]
+[ ------H $ H H ]
+[ H $ & ### H H ]
+[ H #### H --- H $$--]
+[ H H $ H ## ]
+[ H--- $ H X H $]
+[ H ## H H #]
+[ H H XXX###X#]
+[ H H -- ]
+[ $&$ H H X X]
+[ ### H---- H XXXXXX X]
+[$ $$ H $ $ $&X]
+[X XX H # ########]
+[ @ H ]
+[####XXX#########XXX#######]
+
+#-----------------------------------------------------------------------------
+level "Level 103 (original)"
+author "Broderbund"
+size 26x16
+[-----------------------H ]
+[ $ $ $ $ H ]
+[#### #### ###V ##V# H ]
+[ $ $ $ H ]
+[# #V## ##V# V### # H ]
+[ $ $ $ $ H ]
+[#### #### ###V ##V# H ]
+[ $ $ $ H ]
+[# ##V# #V## V### # H ]
+[ $ $ $ $ H ]
+[#### #### ###V ##V# H ]
+[& @ & H &]
+[########################|#]
+[########################|#]
+[###################### | ]
+[###################### &|&]
+
+#-----------------------------------------------------------------------------
+level "Level 104 (original)"
+author "Broderbund"
+size 26x16
+[ & |]
+[ $ $ |]
+[ H###H ##H## H###H |]
+[H# $ #HH#HHHHHH##HH# $ #H|]
+[H#####H##HHHHHHH#H######H|]
+[ & HHHH$HHHH |]
+[########HHHHHHHHH########|]
+[##$## #HHHHHHH# ##$## |]
+[ ### #HHHHH# ### |]
+[ # #HH## # |]
+[ #H# |]
+[ #H# |]
+[ #H# |]
+[ #H# |]
+[ & H @ |]
+[#########################|]
+
+#-----------------------------------------------------------------------------
+level "Level 105 (original)"
+author "Broderbund"
+size 26x16
+[###XX####################|]
+[ $ X $ & @ #|]
+[H#H X#V#H######V####### #|]
+[H##H V#HH##$--------$ #|]
+[H ##H V##HH##$ $ $##H#|]
+[H ##H ###HH##$ $## H#|]
+[HH ##H ##HHH##$ $## HH|]
+[HHH$ #HH #H#HH## ## #HH|]
+[HHHH H#H H##HH#V## #HH#|]
+[$HHHH&H##HH###HHV# $HHH$#|]
+[HH$ HH ##H ###HV #HHHH#|]
+[##H####$ ##H ##H HHHH&H#|]
+[HHHHHHHH #HH HH&HHH$ H#|]
+[H HH $ H H#HHH#HH####H#|]
+[$ H#H####H HHH$ H |]
+[####HHHH$H#####HH#########]
+
+#-----------------------------------------------------------------------------
+level "Level 106 (original)"
+author "Broderbund"
+size 26x16
+[XXXXXXXXXXX| XX X#X]
+[#######X##X| #X #X#]
+[ $ #X#XX| XX # ]
+[HX###V# X| & X $# $]
+[H#### ---H##XXV#####HX H]
+[H# $# ---XXH# VX####H# H]
+[H###--- XXH#---VX####HX#H]
+[H##--- HX $ ##XH##H]
+[H#--$ #X#H# V##XX#H##H]
+[H-- X------H ---- ##H #H]
+[ X#& $ XHV##X@ $ H##H]
+[##V#X## X#XHV##X#XX#X H]
+[##V#X XHV & $ XX####]
+[##V#X------HV## ####X $ #]
+[## $ XH #####]
+[#X####X#H H H###X#######]
+
+#-----------------------------------------------------------------------------
+level "Level 107 (original)"
+author "Broderbund"
+size 26x16
+[ --------- @ --------- ]
+[H ---- ###### ---- H]
+[H --- ########## --- H]
+[H -- ############ -- H]
+[H - #####$$$$##### - H]
+[H - ############## - H]
+[H ################ H]
+[H ##$$$$####$$$$## H]
+[H ################ H]
+[H ######$$$$###### H]
+[H ############## H]
+[H - ############## - H]
+[H - #$$$$##$$$$# - H]
+[H -- ########## -- H]
+[H&$$---$ ###### $---$$&H]
+[########H$$$$$$$$H########]
+
+#-----------------------------------------------------------------------------
+level "Level 108 (original)"
+author "Broderbund"
+size 26x16
+[########## ######XX###|]
+[-------------------- ## #|]
+[ H#########H |#-----H----|]
+[@H$X$$$$ H |#$ $$H $|]
+[#H#####X###H |###H###V#H#|]
+[ HHHHH X $H |#$ H-----H |]
+[$ X$H $$#H |#X H XXX H$|]
+[######V####H |#$ H& $$HXH]
+[ $X$$ X #H |######H####H]
+[ XXXX X #H-H#$ H $$|]
+[ $$$ $$X$ #H&H#X$ H ###H]
+[H###V####H########H######H]
+[H--------H##$-----H-X ---H]
+[H $ $$$ H H $ $ H XH$ $#]
+[#H##HX#H###VH##X#V#####H##]
+[$H$$H& H H $$H$$]
+
+#-----------------------------------------------------------------------------
+level "Level 109 (original)"
+author "Broderbund"
+size 26x16
+[HH #####&HXX XXH&##### HHX]
+[HXHH $ HHXHHHHHXHH $ HHXHH]
+[$HXH#H#HXH$#H#$HXH#H#HXH$#]
+[# HXHHHXH # H # HXHHHXH #H]
+[ #HHXHXHH# H H #HHXHXHH# ]
+[H# HHHHH #H # H# HHHHH #H#]
+[H#H H#H#$#H#H H#H@]
+[H# HHHHH #H # H# HHHHH #H#]
+[ #HHXHXHH# H H #HHXHXHH# ]
+[V HXHHHXH # H # HXHHHXH #H]
+[$HXH#H#HXH$#H#$HXH#H#HXH$#]
+[HXHH $ HHXHHHHHXHH $ HHXHH]
+[XH ##### HXXHXXH ##### HXX]
+[XH H $ H HXXHXXH H $ H HXX]
+[XH H#H#H&HHXHXHH&H#H#H HXX]
+[HXHXHHHXHXHHHHHXHXHHHXHXHH]
+
+#-----------------------------------------------------------------------------
+level "Level 110 (original)"
+author "Broderbund"
+size 26x16
+[ X------ --- HH##H |]
+[$ & $X-----$## HH##HH |]
+[###H#X $## HH##HH$ |]
+[ H X $## HH##HH$ XX|]
+[$ H$X $## HH##HH$ XX |]
+[###H#X $## HH##HH$ XX |]
+[ @H X$## HH##HH$ XX $$|]
+[###H$X## HH##HH$ XX H## ]
+[###H#X# HH##HH$ XX H$$ ]
+[#$#H X $$HH& HH$ XX H#### ]
+[###H$X##########HX H$ &$ ]
+[$##H#X----------HX H##### ]
+[###H$X $ H X H$ $ ]
+[#XXXXX## H #### X H##### ]
+[ &H##$$##X H$ $ ]
+[##########X######X #######]
+
+#-----------------------------------------------------------------------------
+level "Level 111 (original)"
+author "Broderbund"
+size 26x16
+[ HHH ]
+[ HHHH ]
+[ HH ]
+[ & HHHH & ]
+[----------HHHHHH----------]
+[----------HHHHHH----------]
+[ ---------HHHHHH--------- ]
+[ -------HHHHHH------- ]
+[ -----HHHHHH----- ]
+[ --HHHHHH-- ]
+[$ $ $ $ $ HHHHHH $ $ $ $ $]
+[ HH&@HH ]
+[##########HH##HH##########]
+[##########HH##HH##########]
+[ $ $ $ $ H H $ $ $ $ ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 112 (original)"
+author "Broderbund"
+size 26x16
+[ XXXXXXH]
+[------------ & H]
+[ H HXXXXXXX H# H|#]
+[&HXH H-----H #H #H ]
+[XXXHXHX @ H ## |#V]
+[H--H H#V###XXX ##H ##H||#V]
+[H H H# $# $ H # H#--V]
+[H H# $#### XXH $H#$ $$]
+[H H# &##### H #H# #]
+[H # #####$ XXH||H#H###]
+[H # $##### $ H # H## ]
+[HV$ # ###### HXH ###H ##]
+[H # #H $#$ # H H # H# $]
+[H # H###### HXH # ## ##]
+[H # H ]
+[X#X#########XXXX#X#XXX#XXX]
+
+#-----------------------------------------------------------------------------
+level "Level 113 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| ]
+[###############H## $ @ ]
+[ & H##V#XXXXXH]
+[$ HHHHHHHHHHH H H]
+[#$ H HHHHHHHH H $ $ H###H]
+[ #$H H H #|# ####H]
+[ #H H$ $ $ $ H # H]
+[ #$ H#V#V#V# H &$$$H]
+[ # H H #H##H]
+[ H H H H H H ]
+[ H H H& ]
+[ H H H H ###H]
+[ H H H H H]
+[ & $|# H & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 114 (original)"
+author "Broderbund"
+size 26x16
+[ -- -- - ]
+[ #####$-H########H-$####$ ]
+[ ######$H########H$###### ]
+[ #######H########H####### ]
+[ ## ####H### H### # ]
+[ ## ###H###$$$ H###$$$- ]
+[ ## ###H###### H######$ ]
+[ ## ###H###### H ###### ]
+[ ## ###H###### H ##### ]
+[ ## $###H### H ## ]
+[ ##$####H###$$$$$H##$$$## ]
+[ #######H########H##V#### ]
+[ ###### H########H #V#### ]
+[ ##### H########H V### ]
+[ & & H @ H & & ]
+[########|###HH###|########]
+
+#-----------------------------------------------------------------------------
+level "Level 115 (original)"
+author "Broderbund"
+size 26x16
+[ |]
+[-------- #H $$ |]
+[ $#$ H#H#X#X#X#XVX#X#X#]
+[ $# #$ H#H $ $ ------]
+[ $# #$H##X#X#X#X#H H]
+[ # VH#XXXXXXXXXH $ H]
+[ H--------H###V###H]
+[ H# H]
+[ $ @$ H# H]
+[H#######H &$ $ H# $ $&H]
+[H &$ $ H#XXX#X#X#XX#XVX#H]
+[H#######H####$ ### H]
+[H $ $ H###### ## H]
+[H#######H####### # H]
+[H $ $ H######## $ $ H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 116 (original)"
+author "Broderbund"
+size 26x16
+[#|#X#X#X#X#XX# #|#X ##|###]
+[#|######X#XXHX X|X# # | H]
+[X| #X H | $ &| H]
+[##V##H------H##V#########H]
+[@ $ H$H#X$ H X X#X # H]
+[####H##HX#X $ X X ---H]
+[ X# HX HXXX#XX# X -----#H]
+[ & H H #---------X $##H]
+[VX##H H$XX#$ #X$ X ## H]
+[V X H $X#XX#$ X#---H# H]
+[ # H $X $$$ X$ X H H]
+[----H$X H#X# X$ #H#####]
+[ H XX--H X $ H XXXX]
+[ H#X#$$ H--H H ####H X ]
+[ H$ $##$&$$H--H ##XH &$]
+[###########H $H$##########]
+
+#-----------------------------------------------------------------------------
+level "Level 117 (original)"
+author "Broderbund"
+size 26x16
+[ ## |]
+[ $ & $ XX $& $ |]
+[H############H############]
+[H--------- XXH ]
+[ H##H --------- ]
+[ ---------HXXH$ H]
+[H $ ---@ ##### $H#]
+[##### #H XXXXX &$H###]
+[ - # #H ##### $H#####]
+[##$H# #H XXXXX $H#######]
+[$##H# #H---- $H#########]
+[##$H# #H XX HXXXXXXXXXXX]
+[$##H#$$ #H ## H ]
+[##$H###V#H XX H##########H]
+[$##H & H$##$H#$ H]
+[###########XX###XXXXXXXXXX]
+
+#-----------------------------------------------------------------------------
+level "Level 118 (original)"
+author "Broderbund"
+size 26x16
+[--------------- ]
+[ $ H& ]
+[ $$$ HHH ]
+[ $$$ HHH ]
+[ $$ HH ]
+[ $$ $$$ HH HHH -------]
+[$$ $$ $$ HH HH HH & ]
+[ HH HH HHHHH ]
+[ & HHH HHH $$$$$ ]
+[HHHH HH HHHH HH HHHHH ]
+[ HH HH $$$$$ ]
+[ HH @ HH HHHHH ]
+[###########H##############]
+[ H ]
+[ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 119 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ $ | ]
+[HX## |XH]
+[HX$## $ $|XH]
+[H #$### & ######H]
+[H # # ###$ ### $ H]
+[H-- #$ # # $ ##$ XXXX H]
+[H ###### ##V# ##XH]
+[H$ @ #XXXH# $ H]
+[HXXXX-------- H###$H]
+[H X &$$$$ H ###]
+[H $ X$ XXXXXXXXX H $X $]
+[H##### H##XX#]
+[H----H------ H ]
+[ H H& ]
+[ $ H #################]
+
+#-----------------------------------------------------------------------------
+level "Level 120 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ H | H ]
+[ #####H H------------H ]
+[ # $ #H H & H ]
+[ # #H HXXXXXX##XX##XX]
+[X#XX#X#XX#XH#-----#V### #]
+[ $& $ $ H# H #-- # #]
+[######V####H# H#$$#$#H#$ #]
+[ ----------H# H####V#H# #]
+[H& H# H$ --HHH##]
+[H##########H######H $ H ]
+[H @H H## HHH]
+[H$#### $ ##H## $ #H#$-- H]
+[H## $#####$H$#####H##$ ##H]
+[##################H #####]
+
+#-----------------------------------------------------------------------------
+level "Level 121 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[#####H| |H#####]
+[##HHH$| |$HHH##]
+[H###HHH$ $HHH#V#H]
+[HHH#V#HHH$& &$HHH###HHH]
+[ $HHH###HHH$ $HHH#V#HHH$ ]
+[ $HHH#V#HHHHHH###HHH$ ]
+[ $HHH###HH###HHH$ ]
+[ $HHH#HH#HHH$ ]
+[ $HHH###HH###HHH$ ]
+[ $HHH###HHHHHH#V#HHH$ ]
+[ $HHH#V#HHH$ $HHH###HHH$ ]
+[HHH###HHH$ $HHH#V#HHH]
+[H#V#HHH$ $HHH###H]
+[##HHH$| |$HHH##]
+[#####H| @ |H#####]
+
+#-----------------------------------------------------------------------------
+level "Level 122 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| & $ ]
+[| XXHXXXX XXXHXXXX]
+[| H #$ # H# --]
+[|---H-----# #----HXH $]
+[#$ H $ # # H#H- ]
+[ #& H--- #H # # $ HX H]
+[ # # H V H#$ H]
+[@ # # H HX -H]
+[XX# # # H# ----- $ H#H ]
+[ #V H # $ # HXH& ]
+[$H### H # # $H###H]
+[#HX-------H # # #H###H]
+[ H VV H H]
+[ H H H]
+[XXXXXX#######XXXX####XXXXX]
+
+#-----------------------------------------------------------------------------
+level "Level 123 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ -------- -|--- ]
+[ H H- H H##H ]
+[ H-------&H------ H#H-#H ]
+[ H H# --- H# H$ VH]
+[ H HV #H H# H $#]
+[ H -- H# #H - @--H---#]
+[H #HH| H#$H## #H # #]
+[H# #H| H#######H ### ####]
+[##V##| H# #$ #H-H - &H]
+[##V##| H####### H### ###H]
+[# $ #| H# $# #H H#$# ###H]
+[#####| H#######H H### #$#H]
+[#####| H# #$ H H# # H]
+[# #| H#######H H#V###V#H]
+[# $ |#H #H#H # $ H]
+
+#-----------------------------------------------------------------------------
+level "Level 124 (original)"
+author "Broderbund"
+size 26x16
+[| |]
+[| |]
+[|----H H------H# #H]
+[ H-----H H# $ #H]
+[ $ H H & $ H####V#H]
+[###$ #HH ############V#H]
+[###### H $ $ H]
+[####$ H## $#$ ## H]
+[#####$ H## $###$ ## H]
+[######$H## $#####$ ## &$ H]
+[#######H##V###########HX#H]
+[# &H H #H]
+[# $ ##H @ H #H]
+[#######H----H####H$---H #H]
+[# $ H $ H##$#H# #H$#H]
+[#################H####H##H]
+
+#-----------------------------------------------------------------------------
+level "Level 125 (original)"
+author "Broderbund"
+size 26x16
+[ ------ - ]
+[### H-- & H#### ]
+[#$ H-- #####H#### ]
+[### -- V###VH#$$# ]
+[ ###V V###VH#### ]
+[ ###V ##-V#$$VH V###]
+[ #$$V ## V###VH V###]
+[ ###V H V$$#]
+[ H V###]
+[ V##V H ]
+[V##V V$$V HV### ]
+[V V V##V HV### ## ]
+[V $V HV$$# ## ]
+[V##V HV### ]
+[ & H @ ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 126 (original)"
+author "Broderbund"
+size 26x16
+[ $ - - & - -&]
+[H## H####$#$####H - - H]
+[H $ H###########H -$ - $ H]
+[H## H##$#####$##H- - - -H]
+[H $ H###########H $ $ H]
+[H## H#$#######$#H -- - H]
+[H $ H###########H - $ -$-H]
+[H## H##$#####$##H - - H]
+[H $ H###########H - - H]
+[H## H###$###$###H- - - -H]
+[H $ H###########H $ - H]
+[H## H####$#$####H -- $ H]
+[H $ H###########H - - - H]
+[H## H###$###$###H $ - - -H]
+[H& H###########H @ ]
+[H###H##$#####$##H#########]
+
+#-----------------------------------------------------------------------------
+level "Level 127 (original)"
+author "Broderbund"
+size 26x16
+[ | |]
+[ | & |]
+[--- & |------#####H |]
+[H##X### #######H$########H]
+[H##$### X$ H#H## $ $ H]
+[H###### XXXXXHXH ----- H]
+[H ----H H H H]
+[##V###H H H # H]
+[--- H###### #######H####]
+[$ H## ----# HHHHHH--]
+[ H# XXXH #$HHHHHH $]
+[H#### # XXXH #-HHHHHH -]
+[H # H####H #$HHHHHH ]
+[H H# H####H #-HHHHHH ]
+[H@ H#H H# $#H #########H]
+[############### H]
+
+#-----------------------------------------------------------------------------
+level "Level 128 (original)"
+author "Broderbund"
+size 26x16
+[ - - ]
+[H ###################### H]
+[H # # $ $# # # H]
+[H # $ ####V### # # H]
+[H #V#### # $& $ # $# H]
+[H # # ########### H]
+[H # $ # # # # H]
+[H ##### $ & # # # H]
+[H # ######### # $ # H]
+[H # # #$ &#V### H]
+[H # $ $ # ###### # H]
+[H ###V#### # # # H]
+[H # $ #$ &$ #$ #$ # H]
+[H ###V##########V#####V# H]
+[H @ & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 129 (original)"
+author "Broderbund"
+size 26x16
+[ HH ]
+[ &H HH H & ]
+[ ##H## ##HH## ##H## ]
+[##$H$## ###HH### ##$H$##]
+[# H ##$ HH $## # H ]
+[##$H$ --## HH ##$H$ ]
+[ ##H## ##$ HH&$ ##H## ]
+[ $H$## ###HH## $H$##]
+[ H # ##HH### - H #]
+[##$H$## $ HH $## ##$H$##]
+[ #VHV# HH ## ##HV# ]
+[ H ##$ HH&$## H ]
+[ ###HH### ]
+[ ##HH## ]
+[ @ HH ]
+[############HH############]
+
+#-----------------------------------------------------------------------------
+level "Level 130 (original)"
+author "Broderbund"
+size 26x16
+[H ]
+[H -- ----------------]
+[H | $H $ H &H]
+[### ######H-------H H HXXX]
+[ $ H $ H H H ]
+[XXXH###& H-------H H XXXH]
+[ H $ #### $ H H H]
+[ @ H ####$#-------H H HXXX]
+[H# H--------------H H H $ ]
+[H######V##### & H XXXH]
+[H$ ### #$ ####H H]
+[H############XX ######H###]
+[HX########### ######H##$]
+[HX###########HX ##$###H###]
+[HX $#########HX H ]
+[H ######$ HX###########]
+
+#-----------------------------------------------------------------------------
+level "Level 131 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ #$|$# # ]
+[#---H-----#H#-----H---# ]
+[ #$ H & $H$ & H $# ]
+[ #-H-H---#H#---H-H-# ]
+[ # H V H V H # ]
+[H---# H #--H--# H #------H]
+[H-H #H# #H# H-H]
+[ H #H# #H# H ]
+[H-H #H# @ $ #H#### H-H]
+[H #H#########H#### H]
+[H-H #H# ##### #H##$# H-H]
+[ $H #H# ##$## #H#### H$ ]
+[H-H& #H# ##### #H# &H-H]
+[H---- H - - H ------ H]
+[H #H# ##### #H# H]
+
+#-----------------------------------------------------------------------------
+level "Level 132 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[|-------------------------]
+[| V###H###V ]
+[| $V#V H V## $ ]
+[| $V#V$$$$$H$$&$$#V# $ ]
+[| ##V#V#####H######V#V# $ ]
+[### H #V#V]
+[# $$$$ H& $$$$ #V]
+[ H######VH#######H ]
+[ H H H ]
+[ $H $$$$$H $ $$$$H & ]
+[ HV#########HV#########H ]
+[ H H H ]
+[ H H H ]
+[ H H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 133 (original)"
+author "Broderbund"
+size 26x16
+[-------------H------------]
+[ $ $ H $ $&$ $]
+[&$ $ & $ H $ $ $ ]
+[ #V##V#H H#V####H H#V# ]
+[ #V##V##HH#V####VHH#V# ]
+[ #V##V##VH#V####V#H#V# ]
+[ #V# ##VH#V# #V#H#V# ]
+[ #V# ##VH#V# #V#H#V# ]
+[ #V# ##VH#V# #V#H#V# ]
+[ #V# ##VH#V# #V#H#V# ]
+[ #V# $##VH#V# $#V#H#V# ]
+[ #V#V###VH#V#V##V#H#V##V# ]
+[ #V#V### H#V#V##V H#V##V# ]
+[ #V#V## H#V#V## H#V##V# ]
+[ H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 134 (original)"
+author "Broderbund"
+size 26x16
+[$& ####################]
+[##H ####################]
+[H###H #################]
+[H######H & ##############]
+[H#### ####H ###########]
+[H#### #######H ########]
+[H#### ##########H & #####]
+[H### $ ############H ##]
+[H###### $ ############H ]
+[H#### #### $ ############H]
+[H#### ####### $ #########H]
+[H#### #########H $ ######H]
+[H#### #########H### #####H]
+[H$ $ $ $ #H### #####H]
+[############# H### @H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 135 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ | HXXXXXXXXXXXXXXX]
+[#HH###H###H & -------]
+[$#H# #H# #H############ $ ]
+[ #H#$#H#$#HHHH$HHHH$HHH##H]
+[VHH###H# #HHXXXXHHXXXHH $H]
+[HHHHHHHHHHHHX $HHX HH##H]
+[H H ## HHX -XHHX $HH# H]
+[H ###H #$#HHXXXXHHXXXHH#H ]
+[H #$ H ##HH---- HHHHHH#H$]
+[H ## H # #H $ HHHHH###H]
+[H H@## H####### $H###H]
+[HHHHHHXXXXH#HHHHHX ##H###H]
+[H $ XXH#H H HX ##H ##H]
+[####H & #H H$HX $H# &H]
+
+#-----------------------------------------------------------------------------
+level "Level 136 (original)"
+author "Broderbund"
+size 26x16
+[ &&& ]
+[ $$$$$$| ]
+[ $$$$$$|####### ]
+[ $$$$$|XXXXXXX ]
+[ |###### ]
+[ || ]
+[ | ]
+[$$$| ]
+[###H ]
+[########H ]
+[#############H ]
+[#################H ]
+[####################H ]
+[######################H ]
+[#######################H ]
+[#######################H@ ]
+
+#-----------------------------------------------------------------------------
+level "Level 137 (original)"
+author "Broderbund"
+size 26x16
+[| ]
+[| $ $ $& &$ $ $ ]
+[#############|############]
+[ H ]
+[ #H# ]
+[ $H$ ]
+[ & ##H## & ]
+[ H $ H $ H ]
+[ #H# ###H### #H# ]
+[ $H$ $ H $ $H$ ]
+[ ##H## ####H#### ##H##]
+[ $ H $ $ H $ $ H $]
+[###H### #####H##### ###H##]
+[$ H $ $ H $ $ H $]
+[ H H @ H ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 138 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ | ]
+[ & | $-- ]
+[ --------HXXX#V## H ]
+[H H $ H ]
+[H #####XXX###### ]
+[H #$ # # # # ]
+[H & $$ # # $# $$#$$# $ ]
+[H####### ############## ]
+[H# # ##### # ]
+[H# $# $ # H$ # @ $ ]
+[H##########XHX#####V##### ]
+[H H --- ]
+[H H H $ ]
+[H $ H H ### ]
+[############H $& H $ ]
+
+#-----------------------------------------------------------------------------
+level "Level 139 (original)"
+author "Broderbund"
+size 26x16
+[| | X#### ]
+[|##############| X $H# $ ]
+[|-----------H #H--X##H# XX]
+[$H#X# $ H-#H $ H# H]
+[XH ## H #H X##H# $H]
+[XH## $# @H #H $X& H#H-H]
+[HH $########H #H X#H##H H]
+[H ### XH #H H H$ ]
+[H ## $XH ##H H H##]
+[HH ######XH& ###H H H ]
+[XH###------X#H ###HH H#H]
+[#H & #XH ##H# H]
+[#H#######H #XH H# H]
+[#H##$####H####H###XXHH## H]
+[#H#####$#H####H$ $ HH#$ H]
+[#H##################H####H]
+
+#-----------------------------------------------------------------------------
+level "Level 140 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ |||||||| ]
+[ H######H ]
+[ & H# & #H & ]
+[ H# $ #H ]
+[ H################H ]
+[ H# # # #H ]
+[ H# # # #H ]
+[ H# # # #H ]
+[ H# $ #& $ # $ #H ]
+[H############V###########H]
+[H# # # # # #H]
+[H# # # # # #H]
+[H# $ # $ # $ # $ # $ #H]
+[H#H#H#H##H#H##H#H##H#H#H#H]
+[H H#H H##H@H##H&H##H H#H H]
+
+#-----------------------------------------------------------------------------
+level "Level 141 (original)"
+author "Broderbund"
+size 26x16
+[--------- ---------]
+[H ######## H]
+[H ############ H]
+[H & ############## & H]
+[H XXX################XXX H]
+[H ########## H]
+[H XH #### HX H]
+[XXXH HXXX]
+[ H $ $ $ $ $ $ H ]
+[ H H ]
+[ H #### H ]
+[ H ###VVVV### @ H ]
+[ H ###VVVVVVVVVV### H ]
+[ H VVVVVVVVVVVVVV H ]
+[ H VVVVVVVVVVVV H ]
+[ H VVVVVVVV H ]
+
+#-----------------------------------------------------------------------------
+level "Level 142 (original)"
+author "Broderbund"
+size 26x16
+[--------- ]
+[ H # - - ]
+[ $ $ $&H---- #### H ####]
+[######### H#### H V###]
+[ ----H#### H V###]
+[$$ $$H # ## H V$$#]
+[##$ $##H---- # ## H V###]
+[###$ $### H# ## H V$$#]
+[####$#### & H# ## H V###]
+[#########H######$$# H V$$#]
+[ H #### H V###]
+[|# @ H &H V$$#]
+[|##########H##########V###]
+[| ###$##H#####$ ]
+[| ####$#H##$ $##H $]
+[|$ $##### H ############]
+
+#-----------------------------------------------------------------------------
+level "Level 143 (original)"
+author "Broderbund"
+size 26x16
+[########|#################]
+[@ X XXX| XH # H----- ]
+[#H H XHXX XH$#HXXH ]
+[$HXX#H XHXX H H $]
+[##H H XH ###HXH----- ]
+[$XH##X$XH##---HXH ##]
+[ H XHX $X HX## $ ]
+[ &H $ XHX####HX H & ]
+[XX##H# XHX H--HXXXXXXXX]
+[H XH# HX###### H X----]
+[H# H###HX $#$ ###H X ]
+[HX HXX XHX # H ]
+[HX HX $XH ###########HX ]
+[H ### XXHX### H ]
+[H & HX$ XH $ $ H ]
+[#########X##$HXX####XXXH $]
+
+#-----------------------------------------------------------------------------
+level "Level 144 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ ---| --- - ]
+[H H -#XXXXXX #### XXH]
+[H$ H$ # X$ H]
+[##H-XXH XH XX#X VVVV## HV]
+[ $H &$H XH X$ H ]
+[H##-HXX XHH XX#H V V H ]
+[H$ H$ X HH XH #$$# H ]
+[##H-XXH X HH XH ##H--H$]
+[&$H $H X HHXH H #V]
+[H##-HXX X HXH & H ]
+[H$ H$& X XHXXXXXXXXH$]
+[##H-XXH X XH# $ $ #HV]
+[ $H $H X XH#H#X#X##H ]
+[H##-XXX X&$$H# H#H $ $ H ]
+[H @ ######XX##X#X#X#X#]
+
+#-----------------------------------------------------------------------------
+level "Level 145 (original)"
+author "Broderbund"
+size 26x16
+[ & | | & ]
+[ | | ]
+[ | | ]
+[ $###H###$ ]
+[ #$#$H$#$# ]
+[ $ #$H H#H H$# $ $ ]
+[ ##H#H#####H H#####H#H## ]
+[ $# H#H HHH H#H$# ]
+[ # HH#HHHHHHHHHHHHHHH#HH #]
+[ #H&$ #HHHHHH#HHHHHH# $&H#]
+[ ###H #H$ H H $H# H### ]
+[ $##H######H######H##$ ]
+[ ## H $ H $ H ## ]
+[ # H##HHHHH#HHHHH##H # ]
+[ $ H###HH#HHHHH#HH###H@$ ]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 146 (original)"
+author "Broderbund"
+size 26x16
+[ - @ - # $ ]
+[###H ########## H#### ###H]
+[###H # ##### # H#### $ H]
+[$##H # ##### # H##$# H###]
+[###H # ##### # H#### H $ ]
+[#$#H # ##### # H#$## ###H]
+[###H # ##### # H#### $ H]
+[$##H # ##### # H#### H###]
+[###H # ##### # H ### H $ ]
+[#$#H # ##### # H#### ###H]
+[###H # #### # H#$## $ H]
+[$##H #$#####$$# H#### H###]
+[###H ########## H##$ H $ ]
+[#$#H ########## H#### ###H]
+[###H & & H#### & H]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 147 (original)"
+author "Broderbund"
+size 26x16
+[ | ]
+[ & -@ | - ]
+[ HH H H | H H H]
+[H$H H H | H H H]
+[ #HH H #$# H| H #$# H-H]
+[ #H ---H&### H---H&#H# H]
+[X#H#V##X##X##X##V##XH#V##H]
+[# H V # $### $# #H V H]
+[#-H-V--# H#----H----H-#--H]
+[# H V # H# # HVH #& $ H]
+[#VHX#VX##H##X##XVHX##X#V#H]
+[ V## ##H## #VH## V#H]
+[ H-- --#H#-- --VH#-- --#H]
+[ H $ #H# $ #H $ #H]
+[ $H X #H# X #H# X #H]
+[#VHV#X## H ##X## H ##X#V H]
+
+#-----------------------------------------------------------------------------
+level "Level 148 (original)"
+author "Broderbund"
+size 26x16
+[ && || && ]
+[ $$$|##|$$$ ]
+[ $$$$$|XXXXXXXXXX|$$$$$ ]
+[ |###### ######| ]
+[ ||| ||| ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | | ]
+[ | @ | ]
+[#######X#####XX#####X#####]
+
+#-----------------------------------------------------------------------------
+level "Level 149 (original)"
+author "Broderbund"
+size 26x16
+[ ]
+[ H## ##H ]
+[ H## ##H ]
+[ H## ##H ]
+[ H##$ & $##H ]
+[ $--H################H--$&]
+[H#H ##$ $## H#H]
+[HH#H ## $ $ ## H#HH]
+[$HH#H& #### #### H#HH$]
+[ $HH#H ### ### H#HH$ ]
+[ $HH#H ##$@## H#HH$ ]
+[ $HH#H #### H#HH$ ]
+[ $HH#H HH H#HH$ ]
+[ $HH#H HH H#HH$ ]
+[$ & $H##H HH H##H$ & $]
+[##########################]
+
+#-----------------------------------------------------------------------------
+level "Level 150 (original)"
+author "Broderbund"
+size 26x16
+[ --- &@ --- ]
+[H ##H$ $H## H]
+[H ##H$ $H## H]
+[H ##H$ $H## H]
+[H$$ ##H$ $H## $ $H]
+[H###H ##H$ $H## H###H]
+[H$ $H ##H$ $H## H$ $H]
+[H####H ##H$ $H## H####H]
+[H$&&$H ##H$ $H## H$&&$H]
+[H#####H ##H$ $H## H#####H]
+[H$ $H ##H$ $H## H$ $H]
+[H######H ##H$$H## H######H]
+[H$ $H ######## H$ $H]
+[H#######H ###V## H#######H]
+[H$ $H $$#V$$ H$ $H]
+[############XX##|#########]
+
diff --git a/lvl.c b/lvl.c
new file mode 100644
index 0000000..addea43
--- /dev/null
+++ b/lvl.c
@@ -0,0 +1,602 @@
+/* $Id: lvl.c,v 1.3 2012/01/31 14:36:29 culot Exp $ */
+
+/*
+ * Copyright (c) 2010, 2012 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "oldrunner.h"
+
+struct lvlattr {
+ struct size siz;
+ char *name;
+ char *author;
+};
+
+/* Doubly-linked to store information about game levels. */
+TAILQ_HEAD(levels_head, level) levels;
+
+struct level {
+ struct lvlattr attr;
+ char **lay;
+ TAILQ_ENTRY(level) levelsp;
+};
+
+static struct level *curlvl;
+
+static enum sprite char2sprite[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* ! " # $ % & ' ( ) * + , - . / */
+ 0, 0, 0, SP_BRICK, SP_MONEY, 0, SP_FOE, 0, 0, 0, 0, 0, 0, SP_ROPE, 0, 0,
+
+/*0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* @ A B C D E F G H I J K L M N O */
+ SP_HERO, 0, 0, 0, 0, 0, 0, 0, SP_LADDER, 0, 0, 0, 0, 0, 0, 0,
+
+/*P Q R S T U V W X Y Z [ \ ] ^ _ */
+ 0, 0, 0, 0, 0, 0, SP_FAKE_BRICK, 0, SP_CIMENT, 0, 0, 0, 0, 0, 0, 0,
+
+/*` a b c d e f g h i j k l m n o */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/*p q r s t u v w x y z { | } ~ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SP_ESCAPE_LADDER, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static unsigned obj_is_static[SPRITES] = {
+ 1, /* SP_NONE */
+ 1, /* SP_BRICK */
+ 1, /* SP_BRICK_SCRACK */
+ 1, /* SP_BRICK_LCRACK */
+ 1, /* SP_BRICK_BROKEN */
+ 1, /* SP_CIMENT */
+ 1, /* SP_FAKE_BRICK */
+ 1, /* SP_LADDER */
+ 1, /* SP_ROPE */
+ 0, /* SP_ESCAPE_LADDER */
+ 0, /* SP_MONEY */
+ 0, /* SP_HERO */
+ 0, /* SP_FOE */
+ 0, /* SP_INVALID */
+};
+
+static unsigned obj_is_obstacle[SPRITES] = {
+ 0, /* SP_NONE */
+ 1, /* SP_BRICK */
+ 1, /* SP_BRICK_SCRACK */
+ 1, /* SP_BRICK_LCRACK */
+ 0, /* SP_BRICK_BROKEN */
+ 1, /* SP_CIMENT */
+ 0, /* SP_FAKE_BRICK */
+ 0, /* SP_LADDER */
+ 0, /* SP_ROPE */
+ 0, /* SP_ESCAPE_LADDER */
+ 0, /* SP_MONEY */
+ 0, /* SP_HERO */
+ 0, /* SP_FOE */
+ 0, /* SP_INVALID */
+};
+
+static void
+init_layout (struct level *l)
+{
+ int i;
+
+ l->lay = xcalloc (l->attr.siz.h, sizeof (char *));
+ for (i = 0; i < l->attr.siz.h; i++)
+ l->lay[i] = xmalloc (l->attr.siz.w);
+}
+
+static enum sprite
+sprite_at_pos (const struct coord *pos)
+{
+ if (pos->y >= curlvl->attr.siz.h || pos->x >= curlvl->attr.siz.w)
+ return SP_INVALID;
+
+ return char2sprite[(unsigned char)curlvl->lay[pos->y][pos->x]];
+}
+
+enum sprite
+lvl_decor_at_pos (const struct coord *pos)
+{
+ enum sprite sp;
+
+ sp = sprite_at_pos (pos);
+ return obj_is_static[sp] || (sp == SP_ESCAPE_LADDER
+ && money_all_collected ())
+ ? sp : SP_NONE;
+}
+
+unsigned
+lvl_set_name (const char *name)
+{
+ if (!(curlvl->attr.name = xstrdup (name)))
+ return 0;
+ return 1;
+}
+
+unsigned
+lvl_set_author (const char *author)
+{
+ if (!(curlvl->attr.author = xstrdup (author)))
+ return 0;
+ return 1;
+}
+
+/* The size must be of the form AxB. */
+unsigned
+lvl_set_size (char *sizstr)
+{
+ const char *errstr;
+ char *x, *y;
+ int sizex, sizey;
+
+ x = sizstr;
+ if (!(y = strchr (sizstr, 'x')))
+ return 0;
+ *y++ = '\0';
+
+ sizex = strtonum (x, 0, LEVEL_MAX_WIDTH, &errstr);
+ if (errstr)
+ return 0;
+ sizey = strtonum (y, 0, LEVEL_MAX_HEIGHT, &errstr);
+ if (errstr)
+ return 0;
+
+ curlvl->attr.siz.h = sizey;
+ curlvl->attr.siz.w = sizex;
+
+ return 1;
+}
+
+unsigned
+lvl_set_row (int rownum, int rowlen, const char *row)
+{
+ if (rowlen != curlvl->attr.siz.w)
+ {
+ fprintf (stderr, "Incorrect row length (was: %d, expected: %d)!\n",
+ rowlen, curlvl->attr.siz.w);
+ return 0;
+ }
+ if (rownum >= curlvl->attr.siz.h)
+ {
+ fprintf (stderr, "Level row number too large (was: %d, max: %d)!\n",
+ rownum, curlvl->attr.siz.h);
+ return 0;
+ }
+ if (!curlvl->lay)
+ init_layout (curlvl);
+
+ memcpy (curlvl->lay[rownum], row, rowlen);
+
+ return 1;
+}
+
+unsigned
+lvl_width (void)
+{
+ return curlvl->attr.siz.w;
+}
+
+unsigned
+lvl_height (void)
+{
+ return curlvl->attr.siz.h;
+}
+
+unsigned
+lvl_add_new (void)
+{
+ struct level *lvl;
+
+ lvl = xmalloc (sizeof *lvl);
+ bzero (lvl, sizeof *lvl);
+ lvl->attr.siz.w = LEVEL_DEFAULT_WIDTH;
+ lvl->attr.siz.h = LEVEL_DEFAULT_HEIGHT;
+ TAILQ_INSERT_TAIL (&levels, lvl, levelsp);
+ curlvl = lvl;
+
+ return 1;
+}
+
+void
+lvl_init (void)
+{
+ TAILQ_INIT (&levels);
+ money_init ();
+ foes_init ();
+ bricks_init ();
+}
+
+static void
+dynaobj_free (void)
+{
+ money_free ();
+ foes_free ();
+ bricks_free ();
+}
+
+static void
+lvl_load_dynaobjs (void)
+{
+ struct coord lvlpos;
+ int r, c;
+
+ dynaobj_free ();
+
+ for (r = 0; r < curlvl->attr.siz.h; r++)
+ {
+ lvlpos.y = r;
+ for (c = 0; c < curlvl->attr.siz.w; c++)
+ {
+ lvlpos.x = c;
+ switch (sprite_at_pos (&lvlpos))
+ {
+ case SP_HERO:
+ hero_set_initpos (&lvlpos);
+ break;
+ case SP_MONEY:
+ money_add (&lvlpos);
+ break;
+ case SP_FOE:
+ foes_add (&lvlpos);
+ break;
+ default:
+ /* DO NOTHING */
+ break;
+ }
+ }
+ }
+}
+
+static void
+draw_hero_init_pos (void)
+{
+ struct coord pos;
+
+ hero_get_initpos (&pos);
+ hero_set_pos (&pos);
+}
+
+static void
+draw_static_objects (void)
+{
+ int r;
+
+ for (r = 0; r < curlvl->attr.siz.h; r++)
+ {
+ struct coord pos;
+ int c;
+
+ pos.y = r;
+ for (c = 0; c < curlvl->attr.siz.w; c++)
+ {
+ enum sprite sp;
+
+ pos.x = c;
+ sp = sprite_at_pos (&pos);
+ gfx_show_sprite (obj_is_static[sp] ? sp : SP_NONE, &pos);
+ }
+ }
+}
+
+static void
+draw_level (void)
+{
+ draw_static_objects ();
+ money_draw ();
+ bricks_draw ();
+ foes_draw ();
+}
+
+static void
+lvl_update_new (void)
+{
+ draw_hero_init_pos ();
+ draw_level ();
+}
+
+static void
+show_level_info (void)
+{
+ char title[BUFSIZ], info[BUFSIZ];
+
+ (void)snprintf (title, sizeof title, "LEVEL #%d", game_level_num ());
+ (void)snprintf (info, sizeof info,
+ "\t Name: %s\n\n"
+ "\tAuthor: %s\n",
+ curlvl->attr.name, curlvl->attr.author);
+ gfx_popup (title, info);
+}
+
+static void
+load_level (void)
+{
+ lvl_load_dynaobjs ();
+ lvl_update_new ();
+ hero_init ();
+ show_level_info ();
+}
+
+static void
+lvl_select_current (int lvlnum)
+{
+ curlvl = TAILQ_FIRST (&levels);
+ while (lvlnum)
+ {
+ curlvl = TAILQ_NEXT (curlvl, levelsp);
+ EXIT_IF (curlvl == 0, "lvl_select_current: invalid level number");
+ lvlnum--;
+ }
+}
+
+/* Load the level, assign initial player position and draw it. */
+unsigned
+lvl_load (int levelnum)
+{
+ lvl_select_current (levelnum);
+ load_level ();
+
+ return 1;
+}
+
+unsigned
+lvl_load_next (void)
+{
+ if (!(curlvl = TAILQ_NEXT (curlvl, levelsp)))
+ game_won ();
+ game_level_inc ();
+ load_level ();
+
+ return 1;
+}
+
+unsigned
+lvl_load_prev (void)
+{
+ struct level *previous_lvl;
+
+ if (!(previous_lvl = TAILQ_PREV (curlvl, levels_head, levelsp)))
+ return 0;
+
+ curlvl = previous_lvl;
+ game_level_dec ();
+ load_level ();
+
+ return 1;
+}
+
+void
+lvl_won (void)
+{
+ lvl_load_next ();
+}
+
+void
+lvl_lost (void)
+{
+ load_level ();
+}
+
+void
+lvl_draw_escape_ladder (void)
+{
+ int r;
+
+ for (r = 0; r < curlvl->attr.siz.h; r++)
+ {
+ struct coord pos;
+ int c;
+
+ pos.y = r;
+ for (c = 0; c < curlvl->attr.siz.w; c++)
+ {
+ pos.x = c;
+ if (sprite_at_pos (&pos) == SP_ESCAPE_LADDER)
+ gfx_show_sprite (SP_ESCAPE_LADDER, &pos);
+ }
+ }
+}
+
+static unsigned
+valid_decor_move (const struct coord *pos_orig, const struct coord *pos_dest,
+ enum move wanted_move, enum sprite sp)
+{
+ enum sprite sp_orig, sp_dest;
+
+ sp_orig = lvl_decor_at_pos (pos_orig);
+ if (wanted_move == MOV_FALL && sp_orig == SP_ROPE)
+ return 0;
+
+ if (pos_dest->y < 0 && sp_orig == SP_ESCAPE_LADDER)
+ return 1;
+
+ sp_dest = lvl_decor_at_pos (pos_dest);
+ switch (sp_dest)
+ {
+ case SP_NONE:
+ case SP_ROPE:
+ if (wanted_move == MOV_UP)
+ return sp_orig == SP_LADDER || sp_orig == SP_ESCAPE_LADDER ? 1 : 0;
+ else
+ return 1;
+
+ case SP_BRICK:
+ return wanted_move != MOV_UP && bricks_broken_at (pos_dest) ? 1 : 0;
+
+ case SP_CIMENT:
+ return 0;
+
+ case SP_LADDER:
+ return wanted_move == MOV_FALL ? 0 : 1;
+
+ case SP_ESCAPE_LADDER:
+ if (sp == SP_HERO)
+ return wanted_move == MOV_FALL ? 0 : 1;
+ else
+ return wanted_move == MOV_UP ? 0 : 1;
+
+ default:
+ return 0;
+ /* NOTREACHED */
+ }
+}
+
+unsigned
+lvl_valid_move (const struct coord *orig, enum move wanted_move,
+ struct coord *dest, enum sprite sp)
+{
+ if (wanted_move == MOV_NONE)
+ return 0;
+
+ coord_compute (orig, wanted_move, dest);
+ if (dest->y >= (int)curlvl->attr.siz.h
+ || dest->x < 0 || dest->x >= curlvl->attr.siz.w)
+ return 0;
+
+ return valid_decor_move (orig, dest, wanted_move, sp);
+}
+
+unsigned
+lvl_valid_dig (const struct coord *pos)
+{
+ switch (lvl_decor_at_pos (pos))
+ {
+ case SP_BRICK:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+unsigned
+lvl_nothing_below (const struct coord *pos)
+{
+ struct coord below;
+
+ coord_below (pos, &below);
+ return lvl_decor_at_pos (&below) == SP_NONE ? 1 : 0;
+}
+
+unsigned
+lvl_obstacle_at (const struct coord *pos)
+{
+ enum sprite sp;
+
+ if (pos->y < 0 || pos->x < 0
+ || pos->y > curlvl->attr.siz.h || pos->x > curlvl->attr.siz.w)
+ return 1;
+
+ sp = char2sprite[(unsigned char)curlvl->lay[pos->y][pos->x]];
+ return obj_is_obstacle[sp];
+}
+
+void
+lvl_objects_update (void)
+{
+ bricks_update ();
+ bricks_draw ();
+ money_draw ();
+ foes_update_pos ();
+}
+
+unsigned
+lvl_got_hole_below (const struct coord *pos)
+{
+ struct coord below;
+
+ coord_below (pos, &below);
+ if (!bricks_broken_at (&below))
+ return 0;
+ else
+ {
+ if (foes_at_pos (&below) || hero_at_pos (&below))
+ return 0;
+ else
+ return 1;
+ }
+}
+
+static unsigned
+got_way (const struct coord *orig,
+ enum move wanted_dir, enum move prefered_move)
+{
+ struct coord pos;
+
+ coord_copy (orig, &pos);
+ while (!lvl_obstacle_at (&pos))
+ {
+ struct coord wanted_pos;
+
+ coord_set_yx (&wanted_pos,
+ pos.y + (wanted_dir == MOV_UP ? -1 : 1), pos.x);
+ if (valid_decor_move (&pos, &wanted_pos, wanted_dir, SP_NONE))
+ return 1;
+
+ pos.x += prefered_move == MOV_RIGHT ? 1 : -1;
+ }
+
+ return 0;
+}
+
+enum move
+lvl_shortest_way (const struct coord *orig,
+ enum move wanted_dir, enum move prefered_move)
+{
+ struct coord dest;
+
+ if (lvl_valid_move (orig, wanted_dir, &dest, SP_NONE))
+ return wanted_dir;
+ else
+ {
+ if (got_way (orig, wanted_dir, prefered_move))
+ return prefered_move;
+ else
+ return coord_opposite_dir (prefered_move);
+ }
+}
+
+int
+lvl_random_xpos (void)
+{
+ return rand () % curlvl->attr.siz.w;
+}
diff --git a/mem.c b/mem.c
new file mode 100644
index 0000000..1d4c471
--- /dev/null
+++ b/mem.c
@@ -0,0 +1,96 @@
+/* $Id: mem.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "oldrunner.h"
+
+void *
+xmalloc (size_t size)
+{
+ void *p;
+
+ EXIT_IF (size == 0, "xmalloc: zero size");
+ p = malloc (size);
+ EXIT_IF (p == 0, "xmalloc: out of memory");
+
+ return p;
+}
+
+void *
+xcalloc (size_t nmemb, size_t size)
+{
+ void *p;
+
+ EXIT_IF (nmemb == 0 || size == 0, "xcalloc: zero size");
+ EXIT_IF (SIZE_MAX / nmemb < size, "xcalloc: overflow");
+ p = calloc (nmemb, size);
+ EXIT_IF (p == 0, "xcalloc: out of memory");
+
+ return p;
+}
+
+void *
+xrealloc (void *ptr, size_t nmemb, size_t size)
+{
+ void *new_ptr;
+ size_t new_size;
+
+ new_size = nmemb * size;
+ EXIT_IF (new_size == 0, "xrealloc: zero size");
+ EXIT_IF (SIZE_MAX / nmemb < size, "xrealloc: overflow");
+ new_ptr = realloc (ptr, new_size);
+ EXIT_IF (new_ptr == 0, "xrealloc: out of memory");
+
+ return new_ptr;
+}
+
+char *
+xstrdup (const char *str)
+{
+ size_t len;
+ char *cp;
+
+ len = strlen (str) + 1;
+ cp = xmalloc (len);
+
+ return strncpy (cp, str, len);
+}
+
+void
+xfree (void *p)
+{
+ EXIT_IF (p == 0, "xfree: null pointer");
+ free (p);
+}
diff --git a/money.c b/money.c
new file mode 100644
index 0000000..91688cd
--- /dev/null
+++ b/money.c
@@ -0,0 +1,100 @@
+/* $Id: money.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+struct money {
+ struct coord pos;
+ SLIST_ENTRY(money) moneyp;
+};
+
+SLIST_HEAD(, money) money_list;
+
+void
+money_init (void)
+{
+ SLIST_INIT (&money_list);
+}
+
+void
+money_free (void)
+{
+ while (!SLIST_EMPTY (&money_list))
+ {
+ struct money *m;
+
+ m = SLIST_FIRST (&money_list);
+ SLIST_REMOVE_HEAD (&money_list, moneyp);
+ xfree (m);
+ }
+}
+
+void
+money_add (const struct coord *pos)
+{
+ struct money *m;
+
+ m = xmalloc (sizeof *m);
+ coord_set_yx (&m->pos, pos->y, pos->x);
+ SLIST_INSERT_HEAD (&money_list, m, moneyp);
+}
+
+void
+money_draw (void)
+{
+ struct money *m;
+
+ SLIST_FOREACH (m, &money_list, moneyp)
+ gfx_show_sprite (SP_MONEY, &m->pos);
+}
+
+void
+money_check_at (const struct coord *hero_pos)
+{
+ struct money *m;
+
+ SLIST_FOREACH (m, &money_list, moneyp)
+ {
+ if (coord_equal (&m->pos, hero_pos))
+ {
+ SLIST_REMOVE (&money_list, m, money, moneyp);
+ game_score_inc ();
+ return;
+ }
+ }
+}
+
+unsigned
+money_all_collected (void)
+{
+ return SLIST_EMPTY (&money_list);
+}
diff --git a/oldrunner.6 b/oldrunner.6
new file mode 100755
index 0000000..fb91ef0
--- /dev/null
+++ b/oldrunner.6
@@ -0,0 +1,102 @@
+.\" $Id: oldrunner.6,v 1.2 2012/01/06 10:13:55 culot Exp $
+.\"
+.\" Copyright (c) 2010, 2012 Frederic Culot <frederic@culot.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" - Redistributions of source code must retain the above
+.\" copyright notice, this list of conditions and the
+.\" following disclaimer.
+.\"
+.\" - Redistributions in binary form must reproduce the above
+.\" copyright notice, this list of conditions and the
+.\" following disclaimer in the documentation and/or other
+.\" materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.fam C
+.TH OLDRUNNER 6 "January 31, 2012" "OLDRUNNER(6)" "Oldrunner Manual"
+.SH NAME
+Oldrunner \- Broderbund's Loderunner remake
+.SH SYNOPSIS
+.B "oldrunner "
+[\fB-v\fP] [\fB-l\fP<\fInum\fP>]
+.SH DESCRIPTION
+Oldrunner is a remake of Broderbund's Loderunner which contains the
+150 original game levels. In order to win a level, the player '\fB@\fP'
+must collect all gold bags '\fB$\fP' without being touched by ennemies
+(same sprite '\fB@\fP' as player but in reverse video). Once all gold
+is collected an escape ladder usually appears and the player must
+travel to the top of the screen to reach the next level. The player can
+dig holes into floors to temporarily trap ennemies and may then safely
+walk atop them. Over time, floors dug into will regenerate, filling in
+these holes. A trapped ennemy who cannot escape a hole before it fills
+is consumed, immediately respawning in a random location at the top of
+the level.
+.SH OPTIONS
+The following options are supported:
+.TP
+\fB-l\fP <num>
+Start the game at level number \fInum\fP.
+.TP
+\fB-v\fP
+Display oldrunner version and exit.
+.SH CONFIGURATION
+The game can be configured by modifying the variables found in
+the cfg.h header file and recompiling. The default keys are the
+following (\fB^X\fP means \fBcontrol\fP and \fBX\fP keys pressed
+simultaneously):
+.TP
+\fBh\fP
+move left
+.TP
+\fBl\fP
+move right
+.TP
+\fBk\fP
+move up
+.TP
+\fBj\fP
+move down
+.TP
+\fBs\fP
+dig on the left
+.TP
+\fBd\fP
+dig on the right
+.TP
+\fB^g\fP
+commit suicide
+.TP
+\fB^n\fP
+go to next level
+.TP
+\fB^p\fP
+go back to previous level
+.TP
+\fB^d\fP
+quit the game
+.SH SEE ALSO
+ncurses(3)
+.br
+oldrunner web page: http://culot.org/public/Code/oldrunner.html
+.SH AUTHOR
+\fBFrederic Culot\fP <frederic@culot.org>.
+.SH COPYRIGHT
+Copyright (c) 2010, 2012 by Frederic Culot.
+.br
+This software is released under the BSD License.
diff --git a/oldrunner.c b/oldrunner.c
new file mode 100644
index 0000000..135cce0
--- /dev/null
+++ b/oldrunner.c
@@ -0,0 +1,86 @@
+/* $Id: oldrunner.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "oldrunner.h"
+
+/*
+ * Oldrunner is a remake of the Loadrunner game from Broderbund, and one of the
+ * first computer games my father offered me. I wrote this in memory of him.
+ *
+ * Jean-Francois Culot
+ * 1952-Sep-30 - 2009-Oct-20
+ */
+int
+main (int argc, char **argv)
+{
+ const char *errstr;
+ int ch, startlvl;
+
+ startlvl = 0;
+ while ((ch = getopt (argc, argv, "l:v")) != -1)
+ {
+ switch (ch)
+ {
+ case 'l':
+ startlvl = (int)strtonum (optarg, 0, INT_MAX, &errstr) - 1;
+ if (errstr)
+ {
+ fprintf (stderr, "Bad level number: %s\n", errstr);
+ return 1;
+ }
+ break;
+ case 'v':
+ fputs ("oldrunner-" VERSION "\n", stdout);
+ return 0;
+ default:
+ goto err;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc >= 1)
+ {
+ err:
+ fputs ("usage: oldrunner [-v] [-l<num>]\n", stderr);
+ return 0;
+ }
+
+ game_init (startlvl);
+ usr_input ();
+ game_end ();
+
+ return 0;
+}
diff --git a/oldrunner.h b/oldrunner.h
new file mode 100644
index 0000000..5e32306
--- /dev/null
+++ b/oldrunner.h
@@ -0,0 +1,282 @@
+/* $Id: oldrunner.h,v 1.2 2012/01/06 10:11:30 culot Exp $ */
+
+/*
+ * Copyright (c) 2010, 2012 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OLDRUNNER_H
+#define OLDRUNNER_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "compat.h"
+#include "cfg.h"
+
+/* Option to set auto-center mode on/off */
+#define AUTO_CENTER_MODE 0
+
+/* Game level screen properties. */
+#define LEVEL_DEFAULT_WIDTH 26
+#define LEVEL_DEFAULT_HEIGHT 16
+#define LEVEL_MAX_WIDTH 128
+#define LEVEL_MAX_HEIGHT 128
+#define VIEWPORT_WIDTH 80
+#define VIEWPORT_HEIGHT 24
+
+/* Possible characters states. */
+#define STATE_ALIVE 0x01
+#define STATE_FALLING 0x02
+#define STATE_DIGGING 0x04
+#define STATE_TRAPPED 0x08
+
+/* Game sprites. */
+enum sprite {
+ /* Sprites used to draw a level. */
+ SP_NONE,
+ SP_BRICK,
+ SP_BRICK_SCRACK,
+ SP_BRICK_LCRACK,
+ SP_BRICK_BROKEN,
+ SP_CIMENT,
+ SP_FAKE_BRICK,
+ SP_LADDER,
+ SP_ROPE,
+ SP_ESCAPE_LADDER,
+
+ /* Sprites used for objects. */
+ SP_MONEY,
+
+ /* Sprites used to draw characters. */
+ SP_HERO,
+ SP_FOE,
+ SP_INVALID,
+ SPRITES
+};
+
+enum move {
+ MOV_UP,
+ MOV_DOWN,
+ MOV_LEFT,
+ MOV_RIGHT,
+ MOV_FALL,
+ MOV_NONE,
+ MOVES
+};
+
+struct size {
+ unsigned h; /* height */
+ unsigned w; /* width */
+};
+
+struct coord {
+ int y; /* Position on the vertical axis. */
+ int x; /* Position on the horizontal axis. */
+};
+
+struct timer {
+ double time; /* time in usec. */
+ double elapsed;
+};
+
+/* Structure defining all possible user inputs. */
+struct usr_input {
+ int key;
+};
+
+struct game_info {
+#define NO_CHANGE 0x0
+#define LEVEL_CHANGE 0x1
+#define SCORE_CHANGE 0x2
+#define LIVES_CHANGE 0x4
+ int state;
+
+ unsigned level;
+ unsigned score;
+ unsigned lives;
+};
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define __FILE_POS__ __FILE__ ":" TOSTRING(__LINE__)
+
+#define ERROR_MSG(...) do { \
+ char msg[BUFSIZ]; \
+ int len; \
+ \
+ len = snprintf (msg, BUFSIZ, "%s: %d: ", __FILE__, __LINE__); \
+ (void)snprintf (msg + len, BUFSIZ - len, __VA_ARGS__); \
+ (void)fprintf (stderr, "%s\n", msg); \
+} while (0)
+
+#define EXIT(...) do { \
+ ERROR_MSG(__VA_ARGS__); \
+ exit (1); \
+} while (0)
+
+#define EXIT_IF(cond, ...) do { \
+ if ((cond)) \
+ EXIT(__VA_ARGS__); \
+} while (0)
+
+/* bricks.c */
+#define BRICK_COMEBACK_TIME (OLDRUNNER_TIMEOUT * 80)
+void bricks_init (void);
+void bricks_free (void);
+void bricks_break (const struct coord *);
+void bricks_draw (void);
+void bricks_update (void);
+unsigned bricks_broken_at (const struct coord *);
+
+/* coord.c */
+void coord_copy (const struct coord *, struct coord *);
+void coord_below (const struct coord *, struct coord *);
+void coord_above (const struct coord *, struct coord *);
+enum move coord_opposite_dir (enum move);
+void coord_compute (const struct coord *, enum move, struct coord *);
+void coord_set_yx (struct coord *, int, int);
+unsigned coord_equal (const struct coord *, const struct coord *);
+void coord_diff (const struct coord *, const struct coord *,
+ struct coord *);
+
+/* foes.c */
+void foes_init (void);
+void foes_free (void);
+void foes_add (const struct coord *);
+void foes_draw (void);
+unsigned foes_at_pos (const struct coord *);
+void foes_update_pos (void);
+unsigned foes_wallup_at (const struct coord *);
+
+/* game.c */
+void game_won (void);
+void game_init (int);
+void game_end (void);
+void game_update (void);
+unsigned game_load (const char *);
+void game_score_inc (void);
+int game_level_num (void);
+void game_level_inc (void);
+void game_level_dec (void);
+void game_lives_inc (void);
+void game_lives_dec (void);
+
+/* gfx.c */
+void gfx_init (void);
+void gfx_end (void);
+void gfx_alert (void);
+void gfx_center_at (struct coord *);
+void gfx_update (void);
+void gfx_get_input (struct usr_input *);
+void gfx_show_sprite (enum sprite, const struct coord *);
+void gfx_move_sprite (enum sprite, const struct coord *, const struct coord *);
+void gfx_update_info (const struct game_info *);
+void gfx_popup (const char *, const char *);
+void gfx_game_over (void);
+void gfx_game_won (void);
+
+/* hero.c */
+void hero_init (void);
+void hero_draw (void);
+void hero_set_pos (const struct coord *);
+void hero_set_initpos (const struct coord *);
+void hero_get_pos (struct coord *);
+void hero_get_initpos (struct coord *);
+unsigned hero_at_pos (const struct coord *);
+void hero_move (enum move);
+void hero_dig (enum move);
+void hero_dig_done (void);
+void hero_trapped (void);
+void hero_die (void);
+unsigned hero_wallup_at (const struct coord *);
+
+/* io.c */
+FILE *io_fopen (const char *);
+void io_fclose (FILE *);
+char *io_getln (FILE *);
+
+/* lvl.c */
+void lvl_started (void);
+enum sprite lvl_decor_at_pos (const struct coord *);
+void lvl_init (void);
+unsigned lvl_load (int);
+unsigned lvl_load_next (void);
+unsigned lvl_load_prev (void);
+void lvl_won (void);
+void lvl_lost (void);
+void lvl_draw_escape_ladder (void);
+unsigned lvl_set_name (const char *);
+unsigned lvl_set_author (const char *);
+unsigned lvl_set_size (char *);
+unsigned lvl_set_row (int, int, const char *);
+unsigned lvl_width (void);
+unsigned lvl_height (void);
+unsigned lvl_add_new (void);
+unsigned lvl_valid_move (const struct coord *, enum move, struct coord *,
+ enum sprite);
+unsigned lvl_valid_dig (const struct coord *);
+unsigned lvl_nothing_below (const struct coord *);
+unsigned lvl_obstacle_at (const struct coord *);
+void lvl_objects_update (void);
+unsigned lvl_got_hole_below (const struct coord *);
+enum move lvl_shortest_way (const struct coord *, enum move, enum move);
+int lvl_random_xpos (void);
+enum move lvl_random_hdir (void);
+
+/* mem.c */
+void *xmalloc (size_t);
+void *xcalloc (size_t, size_t);
+void *xrealloc (void *, size_t, size_t);
+char *xstrdup (const char *);
+void xfree (void *);
+
+/* money.c */
+void money_init (void);
+void money_free (void);
+void money_add (const struct coord *);
+void money_draw (void);
+void money_check_at (const struct coord *);
+unsigned money_all_collected (void);
+
+/* timer.c */
+void timer_get_time (struct timer *);
+void timer_start (struct timer *);
+void timer_stop (struct timer *);
+double timer_diff (const struct timer *, const struct timer *);
+double timer_elapsed (const struct timer *);
+void timer_set (const struct timer *, struct timer *);
+void timer_add (struct timer *, double);
+unsigned timer_delay_elapsed (struct timer *, double);
+
+/* usr.c */
+void usr_input (void);
+void usr_reset_input (void);
+
+#endif /* OLDRUNNER_H */
diff --git a/timer.c b/timer.c
new file mode 100644
index 0000000..b78c560
--- /dev/null
+++ b/timer.c
@@ -0,0 +1,95 @@
+/* $Id: timer.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+
+#include "oldrunner.h"
+
+#define SEC2USEC 1000000
+
+void
+timer_get_time (struct timer *now)
+{
+ struct timeval t;
+
+ (void)gettimeofday (&t, 0);
+ now->time = (double)t.tv_sec * SEC2USEC + t.tv_usec;
+}
+
+void
+timer_start (struct timer *t)
+{
+ timer_get_time (t);
+}
+
+void
+timer_stop (struct timer *t)
+{
+ struct timer now;
+
+ timer_get_time (&now);
+ t->elapsed = timer_diff (t, &now);
+ t->time = now.time;
+}
+
+double
+timer_diff (const struct timer *t1, const struct timer *t2)
+{
+ return t1->time - t2->time;
+}
+
+double
+timer_elapsed (const struct timer *t)
+{
+ return t->elapsed;
+}
+
+void
+timer_set (const struct timer *orig, struct timer *dest)
+{
+ dest->time = orig->time;
+}
+
+void
+timer_add (struct timer *t, double val)
+{
+ t->time += val;
+}
+
+unsigned
+timer_delay_elapsed (struct timer *t, double delay)
+{
+ struct timer now;
+
+ timer_get_time (&now);
+ return timer_diff (&now, t) > delay ? 1 : 0;
+}
diff --git a/usr.c b/usr.c
new file mode 100644
index 0000000..af359ac
--- /dev/null
+++ b/usr.c
@@ -0,0 +1,113 @@
+/* $Id: usr.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */
+
+/*
+ * Copyright (c) 2010 Frederic Culot <frederic@culot.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "oldrunner.h"
+
+#define ORKEY_NONE -1
+#define USER_DELAY OLDRUNNER_TIMEOUT
+
+static struct usr_input rec_input;
+
+void
+usr_reset_input (void)
+{
+ rec_input.key = ORKEY_NONE;
+}
+
+void
+usr_input (void)
+{
+ struct timer user_timer;
+
+ timer_get_time (&user_timer);
+ usr_reset_input ();
+ for (;;)
+ {
+ struct usr_input input;
+
+ game_update ();
+ gfx_get_input (&input);
+ if (!timer_delay_elapsed (&user_timer, USER_DELAY))
+ {
+ if (input.key != ORKEY_NONE)
+ rec_input.key = input.key;
+ continue;
+ }
+
+ switch (rec_input.key)
+ {
+ case ORKEY_EXIT:
+ return;
+
+ case ORKEY_MOVE_RIGHT:
+ hero_move (MOV_RIGHT);
+ break;
+ case ORKEY_MOVE_LEFT:
+ hero_move (MOV_LEFT);
+ break;
+ case ORKEY_MOVE_UP:
+ hero_move (MOV_UP);
+ break;
+ case ORKEY_MOVE_DOWN:
+ hero_move (MOV_DOWN);
+ break;
+
+ case ORKEY_DIG_LEFT:
+ hero_dig (MOV_LEFT);
+ break;
+ case ORKEY_DIG_RIGHT:
+ hero_dig (MOV_RIGHT);
+ break;
+
+ case ORKEY_LEVEL_NEXT:
+ lvl_load_next ();
+ break;
+ case ORKEY_LEVEL_PREV:
+ lvl_load_prev ();
+ break;
+
+ case ORKEY_SUICIDE:
+ hero_die ();
+ break;
+
+ default:
+ /*
+ * No action were performed by the user in the time interval.
+ * Simulate gravity by requiring a fall by default.
+ */
+ hero_move (MOV_FALL);
+ break;
+ }
+
+ timer_get_time (&user_timer);
+ }
+}
Un proyecto texto-plano.xyz