[icebreaker] 01/22: 1.21

Andreas Gnau rondom-guest at moszumanska.debian.org
Sat Sep 9 09:06:46 UTC 2017


This is an automated email from the git hooks/post-receive script.

rondom-guest pushed a commit to branch master
in repository icebreaker.

commit b75bc13d6d35d93a0145028c0331a641d182d299
Author: Matthew Miller <mattdm at mattdm.org>
Date:   Wed Sep 12 08:52:59 2007 -0600

    1.21
---
 ChangeLog             |  62 ++++
 INSTALL               |   8 +
 LICENSE               | 340 ++++++++++++++++++++
 Makefile              | 119 +++++++
 Makefile.w32          |  57 ++++
 README                | 156 ++++++++++
 TODO                  |  30 ++
 crash.wav             | Bin 0 -> 6463 bytes
 cursor.c              | 277 +++++++++++++++++
 cursor.h              |  25 ++
 dialog.c              | 840 ++++++++++++++++++++++++++++++++++++++++++++++++++
 dialog.h              |  39 +++
 fullscreen.c          |  73 +++++
 fullscreen.h          |  26 ++
 globals.h             |  28 ++
 grid.c                | 244 +++++++++++++++
 grid.h                |  31 ++
 hiscore.c             | 163 ++++++++++
 hiscore.h             |  31 ++
 icebreaker.c          | 225 ++++++++++++++
 icebreaker.desktop    |   7 +
 icebreaker.h          | 113 +++++++
 icebreaker.man.in     |  56 ++++
 icebreaker.spec       |  97 ++++++
 icebreaker_32.ico     | Bin 0 -> 6006 bytes
 icebreaker_48.bmp     | Bin 0 -> 6966 bytes
 intro.c               | 584 +++++++++++++++++++++++++++++++++++
 intro.h               |  23 ++
 laundry.c             |  59 ++++
 laundry.h             |  27 ++
 level.c               | 512 ++++++++++++++++++++++++++++++
 level.h               |  37 +++
 line.c                | 291 +++++++++++++++++
 line.h                |  44 +++
 options.c             | 173 +++++++++++
 options.h             |  46 +++
 ouch.wav              | Bin 0 -> 5886 bytes
 penguin.bmp           | Bin 0 -> 638 bytes
 penguin.c             | 204 ++++++++++++
 penguin.h             |  39 +++
 penguinicon_32.bmp    | Bin 0 -> 3126 bytes
 sound.c               |  82 +++++
 sound.h               |  29 ++
 status.c              | 113 +++++++
 status.h              |  38 +++
 text.c                |  90 ++++++
 text.h                |  31 ++
 transition.c          | 344 +++++++++++++++++++++
 transition.h          |  24 ++
 win32_compatibility.c |  44 +++
 win32_compatibility.h |  70 +++++
 win32_resources.rc    |   1 +
 52 files changed, 5952 insertions(+)

diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..29ed373
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,62 @@
+July 30, 2001: released v1.2.1
+  - fixed minor bug where highest-score line cut off letters that dip below
+    the baseline (gjpqy...). Thanks to Jonathan DePrizio for catching this.
+  - tiny little bugfixes, makefile cleanup
+  - switched to much more sensible linux-kernel-style numbering scheme.
+    (n.oddnumber.n for development releases, and n.evenumber.n for
+    stable "production" releases -- for example, 1.2.1 is a stable release,
+    so any excitement/surprises should come from the game, not from
+    bugs. 1.9.0 will be a devel release, and some features may not work
+    completely, or at all.)
+
+July 28, 2001: released v1.2
+  - added "score decay" timer, to discourage obsessive-compulsive types from
+    taking hours on one level. Sure, I want you to be obsessed with the
+    game, but have fun playing, not tediously waiting. :)
+  - added easy and hard difficulty settings
+  - added options for sound
+  - added option for auto pause (which makes the game stop when the window
+    loses focus -- note that it always pauses when minimized regardless of
+    this setting).
+  - now, when a line is stuck (against another line) for a long time,
+    the line completes instead of exploding. ("A long time" == approximately
+    5 seconds)
+  - merged in Enrico Tassi's win32 compatibility stuff -- win32 version
+    is now completely functional, except:
+  - added fullscreen option! (Unfortunately, still has problems in Win32,
+    so you'll have to edit the icebreaker.cfg manually if you want to enable
+    this feature on a MS Windows system. I'll get the problem figured out
+    for a future release.)
+  - fixed busy waits in dialog.c (thanks again to Enrico)
+  - code cleanup
+
+July 23, 2001: released v1.1
+  - added man page
+  - tiny change to error message when high score file can't be read
+
+July 18, 2001: released v1.09
+  - Gameplay change: changed behavior when a line hits another
+    partially-completed line -- now, instead of the line completing
+    successfully, it waits until the other completes or is destroyed.  In
+    the event that neither of those happens after a little while, new line
+    dies. (I've considered making it complete successfully in this case;
+    opinions, anyone?) This change makes the game much harder, in a good way.
+  - moved center of vertical cursor to proper location (oops)
+  - modified high score code to reread from disk, so that multiple players
+    on the same system don't cause confusion. A race condition still exists,
+    but it's much narrower. :) A future version will have proper locking.
+  - include fix for cmpscore bug thanks to Enrico Tassi
+    <f.tassi at mo.nettuno.it>
+
+October 5, 2000: released v1.0
+  - one-point-oh!
+
+October 3, 2000: released v0.995
+  - minor cosmetic fixes
+  - made 'make install' work; made it easier to redefine file locations
+  - made it so three-decimal-place version numbers work :)
+  - made level 100 loop forever instead of just ending the game there. 
+    not that level 100 is any fun, really -- too many penguins!
+
+October 2, 2000: released v0.98
+  - first public release
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..044d54a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,8 @@
+The easiest way to install this is via RPM. If the binary RPM doesn't work
+on your system, or you don't trust it, just download the src.rpm and rebuild
+it. (If you've never done that before, don't worry -- it's actually
+amazingly easy -- just do "rpm --rebuild icebreaker.src.rpm".)
+
+You can of course also install from Plain Old Source. You should be able to
+just do "make", and then as root, "make install". You'll need the SDL
+libraries from <http://www.libsdl.org/>, if you don't have them already.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a72e9ac
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,119 @@
+CC=gcc
+
+SDLCONFIG=sdl-config
+
+ifndef prefix
+  prefix=/usr/local
+  #prefix=/usr
+endif
+
+ifndef datadir
+  datadir=$(prefix)/share
+endif
+
+ifndef mandir
+  mandir=$(prefix)/share/man
+endif
+
+ifndef highscoredir
+  highscoredir=/var/local/lib/games
+  #highscoredir=/var/lib/games
+endif
+
+ifndef OPTIMIZE
+  OPTIMIZE=-O3
+endif
+
+CFLAGS=-Wall $(OPTIMIZE) $(SDL_CFLAGS) -DDATAPREFIX=\"$(datadir)/icebreaker\" -DHISCOREPREFIX=\"$(highscoredir)\"
+
+SRC=icebreaker.c cursor.c grid.c laundry.c line.c penguin.c sound.c \
+    level.c intro.c text.c status.c transition.c hiscore.c dialog.c \
+    options.c fullscreen.c
+
+SDL_MIXER=-lSDL_mixer
+SDL_LIB=$(SDL_LDFLAGS) $(SDL_MIXER) 
+SDL_CFLAGS := $(shell $(SDLCONFIG) --cflags)
+SDL_LDFLAGS := $(shell $(SDLCONFIG) --libs)
+VERSION := $(shell awk '/^\#define VERSION/ { print $$3 }' icebreaker.h)
+VERDATE := $(shell date -r icebreaker.h +"%d %B %Y")
+
+ifneq ($(VERSION),$(shell awk '/^Version:/ { print $$2 }' icebreaker.spec))
+  $(error "Version in spec file doesn't match version in icebreaker.h!")
+endif
+
+
+
+all:	icebreaker man
+
+clean:
+	rm -f icebreaker
+	rm -f icebreaker.6
+	rm -f *.o
+	rm -f *.d
+	rm -f *.tgz
+	rm -f *.zip
+	rm -f *.exe
+
+
+dist: clean ChangeLog
+	[ -d icebreaker-$(VERSION) ] && rm -rf icebreaker-$(VERSION) || true
+	mkdir icebreaker-$(VERSION)
+	cp -p * icebreaker-$(VERSION) || true
+	tar czf icebreaker-$(VERSION).tgz icebreaker-$(VERSION)
+	[ -d icebreaker-$(VERSION) ] && rm -rf icebreaker-$(VERSION) || true
+	tar tzf icebreaker-$(VERSION).tgz
+
+win32: icebreaker-$(VERSION).zip
+
+icebreaker.exe: icebreaker
+	[ -d win32.build ] && rm -rf win32.build || true
+	mkdir win32.build
+	cp -p * win32.build || true
+	(cd win32.build; make clean; make -f Makefile.w32; mv icebreaker.exe ..)
+	[ -d win32.build ] && rm -rf win32.build || true
+
+icebreaker-$(VERSION).zip: icebreaker.exe
+	[ -d icebreaker-$(VERSION) ] && rm -rf icebreaker-$(VERSION) || true
+	mkdir icebreaker-$(VERSION)
+	cp icebreaker.exe icebreaker-$(VERSION)
+	cp /usr/local/cross-tools/i386-mingw32msvc/lib/SDL.dll icebreaker-$(VERSION)
+	cp /usr/local/cross-tools/i386-mingw32msvc/lib/SDL_mixer.dll icebreaker-$(VERSION)
+	cp *.wav icebreaker-$(VERSION)
+	cp *.bmp icebreaker-$(VERSION)
+	unix2dos -n ChangeLog icebreaker-$(VERSION)/ChangeLog.txt
+	unix2dos -n LICENSE icebreaker-$(VERSION)/LICENSE.txt
+	unix2dos -n README icebreaker-$(VERSION)/README.txt
+	unix2dos -n TODO icebreaker-$(VERSION)/TODO.txt
+	zip -r icebreaker-$(VERSION).zip icebreaker-$(VERSION)
+	[ -d icebreaker-$(VERSION) ] && rm -rf icebreaker-$(VERSION) || true
+	unzip -t icebreaker-$(VERSION).zip
+
+%.d: %.c
+	set -e; $(CC) -M $(CFLAGS) $< \
+           | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+           [ -s $@ ] || rm -f $@
+
+icebreaker:	$(SRC:.c=.o)
+	$(CC) $(CFLAGS) $^ -o icebreaker $(SDL_LIB)
+
+man: icebreaker.6
+
+%.6: %.man.in
+	sed 's/\$$VERSION/$(VERSION)/' $< | \
+	   sed 's/\$$VERDATE/$(VERDATE)/' > $@
+
+install: all
+	mkdir -p $(prefix)/bin
+	mkdir -p $(prefix)/share/icebreaker
+	mkdir -p $(highscoredir)
+	mkdir -p $(mandir)/man6
+
+	install -m 644 *.wav *.bmp $(prefix)/share/icebreaker
+	install -g games -s -m 2755 icebreaker $(prefix)/bin
+	install -m 644 icebreaker.6 $(mandir)/man6
+	touch $(highscoredir)/icebreaker.scores
+	chown games:games $(highscoredir)/icebreaker.scores
+	chmod 664 $(highscoredir)/icebreaker.scores
+
+
+include $(SRC:.c=.d)
diff --git a/Makefile.w32 b/Makefile.w32
new file mode 100644
index 0000000..c8b5cf5
--- /dev/null
+++ b/Makefile.w32
@@ -0,0 +1,57 @@
+# standard path for mingw32 cross compiler
+# see <http://www.libsdl.org/Xmingw32/>
+CROSSTOOLSPATH=/usr/local/cross-tools
+MINGW32BIN=$(CROSSTOOLSPATH)/bin
+
+CC=$(MINGW32BIN)/i386-mingw32msvc-gcc
+WINDRES=$(MINGW32BIN)/i386-mingw32msvc-windres
+
+SDLCONFIG=$(CROSSTOOLSPATH)/i386-mingw32msvc/bin/sdl-config
+
+ifndef OPTIMIZE
+  OPTIMIZE=-O3
+endif
+
+CFLAGS=-Wall $(OPTIMIZE) $(SDL_CFLAGS) -DDATAPREFIX=\".\" -DHISCOREPREFIX=\".\" -DWIN32
+
+SRC=icebreaker.c cursor.c grid.c laundry.c line.c penguin.c sound.c \
+    level.c intro.c text.c status.c transition.c hiscore.c dialog.c \
+    options.c fullscreen.c win32_compatibility.c
+
+RES=win32_resources.rc
+
+SDL_MIXER=-lSDL_mixer
+SDL_LIB=$(SDL_LDFLAGS) $(SDL_MIXER) 
+SDL_CFLAGS := $(shell $(SDLCONFIG) --cflags)
+SDL_LDFLAGS := $(shell $(SDLCONFIG) --libs)
+
+
+all:	icebreaker.exe
+
+clean:
+	rm -f icebreaker
+	rm -f icebreaker.6
+	rm -f *.o
+	rm -f *.d
+	rm -f *.tgz
+	rm -f *.zip
+	rm -f *.exe
+
+%.d: %.c
+	set -e; $(CC) -M $(CFLAGS) $< \
+           | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+           [ -s $@ ] || rm -f $@
+
+%.o:%.rc
+	$(WINDRES) $< $(subst .rc,.o,$<)
+       
+%.o:%.c
+	$(CC) -c $< $(CPPFLAGS) $(CFLAGS)   
+
+
+icebreaker.exe:	$(SRC:.c=.o) $(RES:.rc=.o)
+	$(CC) $(CFLAGS) $^ -o $@ $(SDL_LIB)
+
+
+
+include $(SRC:.c=.d)
diff --git a/README b/README
new file mode 100644
index 0000000..8725305
--- /dev/null
+++ b/README
@@ -0,0 +1,156 @@
+WHAT:
+  
+  So, uh, there's a bunch of penguins on an iceberg in Antarctica. You have
+  been selected to catch them so they can be shipped to Finland, where they
+  are essential to a secret plot for world domination.
+
+  In order to trap the penguins, you'll need to break the iceberg into small
+  chunks. (They're afraid of water, for no apparent reason. Ah well. "The
+  Matrix" had more plot holes than this, and it still was a hit.) You do
+  this by melting lines in the ice with Special High-Tech GNU Tools.
+
+  If a penguin hits a line in progress, however, it vanishes with a loud
+  noise, and you lose a life. (Yes, a life. This story is really breaking
+  down, isn't it? But never fear -- I'll keep going until it's completely
+  dead.)
+
+  Once 80% or more of the iceberg is gone, the remaining chunks are small
+  enough for shipping. Of course, if you manage to get rid of more than
+  that, you'll save on postage, thus earning you exponential amounts of Geek
+  Cred (a.k.a. "score").
+
+  After you ship off one batch of penguins, it's time to move on to the
+  next. Each subsequent 'berg will have one more penguin, and you'll have
+  one more life. This will continue until you lose, or until you exceed
+  level one hundred or so, which Ain't Gonna Happen. 
+
+  Of course, this is an urgent mission, so you'll be penalized if you're
+  slow -- every second or so, your score drops down by one. But don't worry,
+  I'm not completely cruel, so any points you earn on one level are yours to
+  keep forever, no matter how long you take on subsequent icebergs.
+
+  As far as I can tell, this makes no narrative sense whatsoever, so at this
+  point, I declare the backstory / game metaphor completely collapsed. Just
+  go play.
+
+
+HOW:
+
+  The left mouse button starts drawing lines; the right (and/or middle)
+  button toggles between making vertical and horizontal lines.  Note that
+  left clicking actually starts *two* lines: either up and down or left and
+  right. (This will make plenty of sense when you're actually playing.) If
+  one of these lines is hit before it reaches the edge of the iceberg,
+  you'll lose a life. If both are hit, you'll lose two lives.
+
+  As a tiny bit of grace, if you click directly on a penguin, it'll say
+  "Ouch" and nothing else will happen.
+
+  Once a line is completed, any area containing no penguins is cleared.
+  Falls into the ocean, so to speak. Once 80% has been cleared, the level is
+  complete. However, you get an exponential bonus for every percentage point
+  above that, so you want to try to make your last line suddenly clear a
+  huge chunk of ice. (Again, this will make sense once you've played for a
+  while.) Oh, and you also get a (much smaller) bonus for having lives left
+  over at the end of a level.
+
+  Taking a long time on a level doesn't affect these bonuses, but it can
+  chip away at your score, so you have to balance the time it takes to set
+  up a situation where you can clear 99% of the iceberg against the bonus
+  you'll get for doing so.
+
+  Having trouble? A hint: it's useful to make traps by intentionally letting
+  some of your lines get broken. That way, you can create smaller areas in
+  which you can catch the pesky little things easily.
+
+
+WHY:
+
+  There's a game for MS Windows called "Jezzball". You may notice that this
+  one is extremely similar. There's a reason for that. See, our main
+  computer at home runs Linux most of the time, but it has Win95 set up to
+  dual-boot if need be. (Unfortunately, it's too slow to run VMware or Wine
+  well.) Ideally, of course, the machine stays in Linux, but my wife, Karen,
+  really likes puzzle sorts of games and became highly addicted to this
+  Jezzball thing. Well, we simply couldn't have the system wasting its life
+  in Windows all that time, so I took it upon myself to create a
+  sort-of-clone. (It's not a pure clone, because I like to think that I've
+  done many things in a far superior way.) So this game can be thought of,
+  in a simultaneously dangerously geeky and dangerously mushy way, as sort
+  of a dual love-letter, to both Karen and Linux. :)
+
+  It's therefore somewhat ironic that IceBreaker now exists in a MS 
+  Windows version. Ah well. I know not all of you have been converted yet,
+  and you might as well enjoy the game too.
+
+  Oh, and to answer another "Why" question, especially for my friend Lars:
+  why is this program written in C and yet uses C++ style comments? Because
+  I like C++ style comments, that's why.
+
+WHO:
+
+  This game was written by Matthew Miller <mattdm at mattdm.org>.
+
+  Recent versions have benefited immensely from the help of Enrico Tassi
+  <gareuselesinge at infinito.it>. He's responsible for getting the Win32 port
+  to work so nicely, and for a lot of fancy new features. Enrico doesn't
+  live here in Boston, but he's a huge fan of Boston band Letters To Cleo,
+  so that counts for something.
+
+  Much thanks to Karen for everything. In fact, if you really love this
+  game, check out Ten Thousand Villages <http://www.tenthousandvillages.org>,
+  the non-profit organization for which she works. And if you live near
+  Boston, MA, stop in to the store in Coolidge Corner (Brookline) and say
+  "Hi" and perhaps buy something -- they have cool stuff and it's a really
+  great organization.
+
+  Thanks also to Tae-Jin, for helping me squash a nasty bug, and to Paul for
+  testing and suggestions and proofreading this document. And to the folks
+  at the helpdesk downstairs for playing this game instead of working.
+
+  The sounds are borrowed (and modified slightly) from other GPL'd games. 
+  Specifically, the Ouch sound is from Bill Kendrick's Bug Squish
+  <http://www.newbreedsoftware.com/bugsquish/>. (Update: Bill tells me that
+  he got the sound from xboing, which says it got it from sounds.sdus.edu,
+  which doesn't seem to exist. Huh. Anyway, I also got a lot of help by
+  looking at the source for Bill's games, so he still gets credit for that.)
+  The Crash sound is from gnibbles (which ships with GNOME). I'd like to
+  someday have completely original sounds -- if someone would like to make
+  some, that'd be cool.
+
+  The penguin image is mostly my own work, but is based on a graphic
+  from Pingus <http://dark.x.dtu.dk/~grumbel/pingus/>.
+
+  Actually, I'm quite open to accepting any help anyone wants to give.
+
+
+WHEN:
+
+  A week or two in September, 2000, and then some more time in July 2001.
+
+
+WHERE:
+
+  Get it from: <http://www.mattdm.org/icebreaker/>
+  
+  Report bugs: <mattdm at mattdm.org>
+
+
+WHICH:
+
+  (As in, "On which libraries does icebreaker depend?")
+  
+  libSDL and libSDL_mixer. <http://www.libsdl.org/>
+
+
+WHITHER:
+
+  I'm now actively working on IceBreaker, and a few other people have been
+  too (most notably, Enrico Tassi). If you want to help, or are just
+  interested in what's going on, check out the development section of the
+  IceBreaker website at <http://www.mattdm.org/icebreaker/development.shtml>.
+
+
+------------------------------------------------------------------------------
+Copyright (C) 2000-2001 Matthew Miller and released under
+the terms of the GNU General Public License.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..c691165
--- /dev/null
+++ b/TODO
@@ -0,0 +1,30 @@
+Some of this is work in progress, and some it is just stuff I'd like to see.
+Check out <http://www.mattdm.org/icebreaker/development.shtml> for details.
+
+* innumerable sections of the code are marked with "FIX", in places where I
+  know I did something messy, foolish, or inefficient.
+* there are likely other bits of messiness, foolishness, and inefficiency
+  which I haven't realized are there
+* this is part of the above, but bears mentioning separately: some of the
+  code is the product of late-night hacking and, while it works fine,
+  desperately needs cleaning up
+
+* clean up fullscreen mode in win32
+* need titlebar-equivalent in fullscreen mode, so one can see the current
+  level.
+* the sounds are totally borrowed from other people. need original ones.
+* add command line options
+* add keyboard support
+* option to turn off scrolling level-end text
+* make GNOME/KDE versions?
+* the animation is really jerky with some refresh rates. what to do about
+  this? last time I wrote a game was under DOS, and you could easily
+  sync to the vertical refresh.....
+* check for high scores on 'quit'
+* fix race condition in readhiscore()/checkhiscore()/addhiscore() -- 
+  add lock file
+* there is a little bug where in certain situations you can start an
+  opposing line directly in the path of an oncoming line, causing lines 
+  which are essentially on top of each other. Not a terribly fatal flaw,
+  but I'm going to fix it sometime. :)
+* skins -- FreeBSD, etc.
diff --git a/crash.wav b/crash.wav
new file mode 100644
index 0000000..cb3e2b1
Binary files /dev/null and b/crash.wav differ
diff --git a/cursor.c b/cursor.c
new file mode 100644
index 0000000..84fb856
--- /dev/null
+++ b/cursor.c
@@ -0,0 +1,277 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+* except the init_system_cursor function, which was lovingly stolen from
+* the SDL documentation
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+
+#include <SDL.h>
+#include "cursor.h"
+#include "icebreaker.h"
+
+static SDL_Cursor *init_system_cursor(const char *image[]);
+
+/* XPM */
+static const char *cursorarrow[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        3            1",
+/* colors */
+"X c #000000",
+". c #ffffff",
+"  c None",
+/* pixels */
+"X                               ",
+"XX                              ",
+"X.X                             ",
+"X..X                            ",
+"X...X                           ",
+"X....X                          ",
+"X.....X                         ",
+"X......X                        ",
+"X.......X                       ",
+"X........X                      ",
+"X.....XXXXX                     ",
+"X..X..X                         ",
+"X.X X..X                        ",
+"XX  X..X                        ",
+"X    X..X                       ",
+"     X..X                       ",
+"      X..X                      ",
+"      X..X                      ",
+"       XX                       ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"0,0"
+};
+
+
+/* XPM */
+static const char *cursorhorizontal[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        3            1",
+/* colors */
+"X c #000000",
+". c #ffffff",
+"  c None",
+/* pixels */
+"        X X                     ",
+"       XX XX                    ",
+"      X.X X.X                   ",
+"     X..X X..X                  ",
+"    X...X X...X                 ",
+"   X....X X....X                ",
+"  X.....XXX.....X               ",
+" X...............X              ",
+"X.................X             ",
+" X...............X              ",
+"  X.....XXX.....X               ",
+"   X....X X....X                ",
+"    X...X X...X                 ",
+"     X..X X..X                  ",
+"      X.X X.X                   ",
+"       XX XX                    ",
+"        X X                     ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"9,8"
+};
+
+/* XPM */
+static const char *cursorvertical[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        3            1",
+/* colors */
+"X c #000000",
+". c #ffffff",
+"  c None",
+/* pixels */
+"        X                       ",
+"       X.X                      ",
+"      X...X                     ",
+"     X.....X                    ",
+"    X.......X                   ",
+"   X.........X                  ",
+"  X...........X                 ",
+" X.............X                ",
+"XXXXXXX...XXXXXXX               ",
+"      X...X                     ",
+"XXXXXXX...XXXXXXX               ",
+" X.............X                ",
+"  X...........X                 ",
+"   X.........X                  ",
+"    X.......X                   ",
+"     X.....X                    ",
+"      X...X                     ",
+"       X.X                      ",
+"        X                       ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"8,9"
+};
+
+/* XPM */
+static const char *cursorclick[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        3            1",
+/* colors */
+"X c #000000",
+". c #ffffff",
+"  c None",
+/* pixels */
+" XXXX  XXX   XXX  XXXX  XXX  XX ",
+"X....X X.X   X.X X....X X.X X.X ",
+"X.XXX  X.X   X.X X.XXX  X.XX.X  ",
+"X.X    X.X   X.X X.X    X...X   ",
+"X.X    X.X   X.X X.X    X.XX.X  ",
+"X.XXX  X.XXX X.X X.XXX  X.X X.X ",
+"X....X X...X X.X X....X X.X X.X ",
+" XXXX  XXXXX XXX  XXXX  XXX XXX ",
+"                                ",
+"                                ",
+"        XXXXXXX  XXXXX          ",
+"        X.....X X.....X         ",
+"        XXX.XXX X.XXX.X         ",
+"          X.X   X.X X.X         ",
+"          X.X   X.X X.X         ",
+"          X.X   X.XXX.X         ",
+"          X.X   X.....X         ",
+"          XXX    XXXXX          ",
+"                                ",
+"                                ",
+" XXXX  XXXXXX  X    XXXX  XXXXXX",
+"X....X X....X X.X   X...X X....X",
+"X.XXX  XX.XXX X..X  X.XX.X X.XXX",
+"X....X  X.X  X.XX.X X...X  X.X  ",
+" XXX.X  X.X X.....X X.X.X  X.X  ",
+" XXX.X  X.X X.XXX.X X.XX.X X.X  ",
+"X....X  X.X X.X X.X X.XX.X X.X  ",
+" XXXX   XXX XXX XXX XXX XX XXX  ",
+"                                ",
+"                                ",
+"                                ",
+"                                ",
+"15,15"
+};
+
+
+static SDL_Cursor *init_system_cursor(const char *image[])
+{
+	int i, row, col;
+	Uint8 data[4*32];
+	Uint8 mask[4*32];
+	int hot_x, hot_y;
+
+	i = -1;
+	for ( row=0; row<32; ++row )
+	{
+		for ( col=0; col<32; ++col ) 
+		{
+			if ( col % 8 ) 
+			{
+		        	data[i] <<= 1;
+				mask[i] <<= 1;
+			} 
+			else
+			{
+				++i;
+				data[i] = mask[i] = 0;
+			}
+			switch (image[4+row][col])
+			{
+				case '.':
+					data[i] |= 0x01;
+					mask[i] |= 0x01;
+				break;
+				case 'X':
+					mask[i] |= 0x01;
+				break;
+				case ' ':
+				break;
+			}
+		}
+	}
+	sscanf(image[4+row], "%d,%d", &hot_x, &hot_y);
+	return SDL_CreateCursor(data, mask, 32, 32, hot_x, hot_y);
+}
+
+void setcursor(CursorType c)
+{
+
+	// FIX -- store cursors rather than converting each time!!!
+	
+	static CursorType current=CURSORDEFAULT;
+	if (c != current)
+	{
+		switch (c)
+		{
+			case CURSORDEFAULT: //falls through
+			case CURSORARROW:
+				SDL_SetCursor(init_system_cursor(cursorarrow));
+			break;
+			case CURSORHORIZONTAL:
+				SDL_SetCursor(init_system_cursor(cursorhorizontal));
+			break;
+			case CURSORVERTICAL:
+				SDL_SetCursor(init_system_cursor(cursorvertical));
+			break;
+			case CURSORCLICK:
+				SDL_SetCursor(init_system_cursor(cursorclick));
+			break;
+		}
+		current=c;
+	}
+	
+	
+}
diff --git a/cursor.h b/cursor.h
new file mode 100644
index 0000000..65fda3e
--- /dev/null
+++ b/cursor.h
@@ -0,0 +1,25 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*  http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+typedef enum { CURSORDEFAULT, CURSORCLICK, CURSORARROW, CURSORHORIZONTAL, CURSORVERTICAL } CursorType; 
+
+extern void setcursor(CursorType c);
+
diff --git a/dialog.c b/dialog.c
new file mode 100644
index 0000000..5fa3ab5
--- /dev/null
+++ b/dialog.c
@@ -0,0 +1,840 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> and
+*   Enrico Tassi <f.tassi at mo.nettuno.it>
+*
+* <http://www.mattdm.org/icebreaker/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <string.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "text.h"
+#include "laundry.h"
+#include "dialog.h"
+#include "sound.h"
+#include "hiscore.h"
+#include "options.h"
+#include "fullscreen.h"
+
+static int menuhandler(SDL_Rect menurect, int menulength, char ** menuitems, int (**menufunctions)(char *), int menuvaluetextwidth );
+
+static int menuitem_newgame(char * notused);
+static int menuitem_options(char * notused);
+static int menuitem_highscores(char * notused);
+static int menuitem_help(char * notused);
+static int menuitem_quit(char * notused);
+
+static int menuitem_sound(char * val);
+static int menuitem_autopause(char * val);
+static int menuitem_fullscreen(char * val);
+static int menuitem_difficulty(char * val);
+static int menuitem_theme(char * val);
+
+
+#define MAXMENUITEMS 10
+#define MAXMENUVALUELENGTH 10
+
+int gethighusername(int highest)
+{
+	SDL_Rect tmprect,namerect,okayrect;
+	SDL_Event event;
+	int done=false;
+	int quit=false;
+	int okayglow=false;
+	int okaypressed=false;
+	int clearname=true;
+	
+	char keypressed;
+	int insertionpoint=0;
+	
+	// save behind
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+	
+	tmprect.w=282;
+	tmprect.h=92;
+	tmprect.x=(WIDTH/2)-(tmprect.w/2)-1;
+	tmprect.y=(HEIGHT/2)+31;
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0));
+
+	tmprect.w-=2; tmprect.h-=2;
+	tmprect.x++; tmprect.y++;
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+
+	if (highest)
+		puttext(tmprect.x+7,tmprect.y+7,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"NEW TOP SCORE!");
+	else
+		puttext(tmprect.x+7,tmprect.y+7,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"NEW HIGH SCORE.");
+	puttext(tmprect.x+7,tmprect.y+7+16,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"ENTER YOUR NAME:");
+	
+	namerect.w=268;
+	namerect.h=29;
+	namerect.x=tmprect.x+6;
+	namerect.y=tmprect.y+7+32;
+	
+	SDL_FillRect(screen,&namerect,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
+	puttext(namerect.x+4,namerect.y+5,4,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),username);
+
+	okayrect.x=tmprect.x+tmprect.w-32;
+	okayrect.y=tmprect.y+7+64;
+	okayrect.h=CHARHEIGHT*2+3;
+	okayrect.w=CHARWIDTH*2*2+1;
+
+	//SDL_FillRect(screen,&okayrect,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
+	puttext(okayrect.x+3,okayrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"OK");
+
+
+	SDL_UpdateRect(screen,0,0,0,0);	
+
+
+	SDL_EnableUNICODE(1);
+	
+	clean();
+	do
+	{
+		SDL_WaitEvent(NULL); // no new CPU cooler needed. :)
+		while (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_QUIT)
+			{
+				done=true;
+				quit=true;
+			}
+			else if (event.type == SDL_MOUSEBUTTONDOWN)
+			{  // fix -- make this left button only
+				if (event.button.x>=okayrect.x
+				 && event.button.y>=okayrect.y
+				 && event.button.x<okayrect.x+okayrect.w
+				 && event.button.y<okayrect.y+okayrect.h)
+				okaypressed=true;
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				if (okaypressed
+				 && event.button.x>=okayrect.x
+				 && event.button.y>=okayrect.y
+				 && event.button.x<okayrect.x+okayrect.w
+				 && event.button.y<okayrect.y+okayrect.h)
+				{
+					if (username[0]!='\0')
+					{
+						done=true;
+					}
+					//FIX: else beep
+				}
+				else if (okayglow)
+				{
+					okayglow=false;
+					SDL_FillRect(screen,&okayrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+					puttext(okayrect.x+3,okayrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"OK");
+					soil(okayrect);
+				}
+				okaypressed=false;
+			}
+			else if (event.type == SDL_MOUSEMOTION)
+			{
+				if (event.motion.x>=okayrect.x
+				 && event.motion.y>=okayrect.y
+				 && event.motion.x<okayrect.x+okayrect.w
+				 && event.motion.y<okayrect.y+okayrect.h)
+				 {
+					if (!okayglow)
+					{
+						okayglow=true;
+						SDL_FillRect(screen,&okayrect,SDL_MapRGB(screen->format, 0xF0, 0xF0, 0xF0));
+						puttext(okayrect.x+3,okayrect.y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),"OK");
+						soil(okayrect);
+					}
+					
+				}
+				else
+				{
+					if (okayglow && !okaypressed)
+					{
+						okayglow=false;
+						SDL_FillRect(screen,&okayrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+						puttext(okayrect.x+3,okayrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"OK");
+						soil(okayrect);
+					}
+				}
+			
+			}
+			else if (event.type==SDL_KEYDOWN)
+			{
+
+				if (event.key.keysym.sym==SDLK_BACKSPACE ||
+				    event.key.keysym.sym==SDLK_DELETE ||
+				    event.key.keysym.sym==SDLK_LEFT)
+				{
+					if (clearname)
+					{
+						insertionpoint=0;
+						username[0]='\0'; // null out username
+					}
+					else if (insertionpoint>0)
+					{
+						insertionpoint--;	
+						username[insertionpoint]='\0';
+					}
+					//FIX: else beep
+					clearname=false;
+				}	
+				else if (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER)
+				{
+					if (username[0]!='\0')
+					{
+						done=true;
+					}
+					//FIX: else beep
+					clearname=false;
+				}
+				else if (event.key.keysym.sym==SDLK_ESCAPE || event.key.keysym.sym==SDLK_CLEAR)
+				{
+					insertionpoint=0;
+					username[0]='\0'; // null out username
+					clearname=false;
+				}
+				else if ((event.key.keysym.unicode & 0xFF80) == 0) // make sure it's ascii
+				{
+					keypressed=event.key.keysym.unicode & 0x7F;
+					if (keypressed==32) keypressed=95;
+					if (keypressed>32 && keypressed<127)
+					{
+						if (clearname)
+						{
+							insertionpoint=0;
+							clearname=false;
+						}
+						if (insertionpoint<12)
+						{
+							username[insertionpoint]=keypressed;
+							username[insertionpoint+1]='\0';
+							insertionpoint++;
+						}
+						//FIX: else beep
+					}			
+				}
+				SDL_FillRect(screen,&namerect,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
+				puttext(namerect.x+4,namerect.y+5,4,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),username);
+				soil(namerect);	
+			}
+		}
+		clean();
+	} while (!done);
+
+	// and restore the background
+	SDL_BlitSurface(screensave, NULL, screen, NULL);
+	SDL_UpdateRect(screen,0,0,0,0);	
+	
+	SDL_EnableUNICODE(0);	
+	return(quit);
+}
+
+#define MAINMENULENGTH 5
+int popupmenu()
+{
+	SDL_Rect menurect;
+
+	char * mainmenu[MAINMENULENGTH] = { "NEW GAME", "OPTIONS", "HIGH SCORES", "HELP","QUIT" };
+	int (*mainmenufunctions[MAINMENULENGTH])(char *) = { &menuitem_newgame, &menuitem_options, &menuitem_highscores, &menuitem_help, &menuitem_quit };
+	
+	menurect.w=126;
+	menurect.h=5+(MAINMENULENGTH*(CHARHEIGHT*2+3));
+	menurect.x=BORDERRIGHT-menurect.w+5;
+	menurect.y=BORDERBOTTOM-menurect.h+9;
+
+	return menuhandler(menurect, MAINMENULENGTH, mainmenu, mainmenufunctions, 0);
+
+}
+
+int menuitem_newgame(char * notused)
+{
+	return POPUPMENUNEWGAME;
+}
+
+
+int menuitem_options(char * notused)
+{
+	SDL_Event event;
+	
+	int rc=popupoptionsmenu();
+
+	if (rc!=POPUPMENUEXITMENU)
+	{
+		return rc;
+	}
+	else
+	{
+		// add a fake event so "Options" gets un-highlighted if need be.
+		SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
+		event.type = SDL_MOUSEMOTION;
+		SDL_PushEvent(&event);
+		return POPUPMENUDONOTHING;
+	}
+}
+
+
+int menuitem_highscores(char * notused)
+{
+	int rc;
+	SDL_Event event;
+	rc=popuphighscores();
+	// add a fake event so menuitem gets un-highlighted if need be.
+	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
+	event.type = SDL_MOUSEMOTION;
+	SDL_PushEvent(&event);
+	return rc;
+}
+
+
+int menuitem_help(char * notused)
+{
+	int rc;
+	SDL_Event event;
+	rc=popuphelp();
+	// add a fake event so menuitem gets un-highlighted if need be.
+	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
+	event.type = SDL_MOUSEMOTION;
+	SDL_PushEvent(&event);
+
+	return rc;
+}
+
+
+int menuitem_quit(char * notused)
+{
+	return POPUPMENUQUITGAME;
+}
+
+#ifndef HIDEFULLSCREEN // FIX -- put back fullscreen
+  #define OPTIONSMENULENGTH 4
+#else
+  #define OPTIONSMENULENGTH 3
+#endif
+
+int popupoptionsmenu()
+{
+	SDL_Rect menurect;
+	GameDifficultyType originaldifficulty=options.difficulty;
+	int rc;
+
+	// FIX -- Themes!
+ 	//char * optionsmenu[OPTIONSMENULENGTH] = { "SOUND", "AUTO PAUSE", "FULL SCREEN", "DIFFICULTY", "THEME" };
+	//int (*optionsmenufunctions[OPTIONSMENULENGTH])(char *) = { &menuitem_sound, &menuitem_autopause, &menuitem_fullscreen, &menuitem_difficulty, &menuitem_theme };
+	
+#ifndef HIDEFULLSCREEN // FIX -- put back fullscreen
+	char * optionsmenu[OPTIONSMENULENGTH] = { "SOUND", "AUTO PAUSE", "FULL SCREEN", "DIFFICULTY" };
+	int (*optionsmenufunctions[OPTIONSMENULENGTH])(char *) = { &menuitem_sound, &menuitem_autopause, &menuitem_fullscreen, &menuitem_difficulty };
+#else	
+	char * optionsmenu[OPTIONSMENULENGTH] = { "SOUND", "AUTO PAUSE", "DIFFICULTY" };
+	int (*optionsmenufunctions[OPTIONSMENULENGTH])(char *) = { &menuitem_sound, &menuitem_autopause, &menuitem_difficulty };
+#endif
+	
+	menurect.w=212;
+	menurect.h=5+(OPTIONSMENULENGTH*(CHARHEIGHT*2+3));
+	menurect.x=BORDERRIGHT-menurect.w+10;
+	menurect.y=BORDERBOTTOM-menurect.h+9-((CHARHEIGHT*2+4)*4)-2;
+
+	
+	rc=menuhandler(menurect, OPTIONSMENULENGTH, optionsmenu, optionsmenufunctions, 69);
+	
+	// FIX -- prompt if user really wants to do this mid-game
+	if (rc==POPUPMENUEXITMENU && options.difficulty != originaldifficulty) rc=POPUPMENUNEWGAME;
+
+	//writeoptions(); // probably no need to do this until exit
+	
+	return rc;
+}
+
+
+int menuitem_sound(char * val)
+{
+	if (strlen(val)==0)
+	{
+		if (soundsystemworks)
+		{
+			if (options.sound==SOUNDON)
+				strncpy(val,"on",MAXMENUVALUELENGTH);
+			else
+				strncpy(val,"off",MAXMENUVALUELENGTH);
+		}
+		else
+		{
+			strncpy(val,"n/a",MAXMENUVALUELENGTH);
+		}
+		return POPUPMENUDONOTHING;
+	}
+	else
+	{
+		if (!soundsystemworks) return POPUPMENUDONOTHING;
+		if (options.sound==SOUNDON)
+		{
+			options.sound=SOUNDOFF;
+			strncpy(val,"off",MAXMENUVALUELENGTH);
+		}
+		else
+		{
+			options.sound=SOUNDON;	
+			strncpy(val,"on",MAXMENUVALUELENGTH);
+		}
+		return POPUPMENUREDRAWME;
+	}
+}
+
+int menuitem_autopause(char * val)
+{
+	if (strlen(val)==0)
+	{
+		if (options.autopause==AUTOPAUSEON)
+			strncpy(val,"on",MAXMENUVALUELENGTH);
+		else
+			strncpy(val,"off",MAXMENUVALUELENGTH);
+		return POPUPMENUDONOTHING;
+	}
+	else
+	{
+		if (options.autopause==AUTOPAUSEON)
+		{
+			options.autopause=AUTOPAUSEOFF;
+			strncpy(val,"off",MAXMENUVALUELENGTH);
+		}
+		else
+		{
+			options.autopause=AUTOPAUSEON;	
+			strncpy(val,"on",MAXMENUVALUELENGTH);
+		}
+		return POPUPMENUREDRAWME;
+	}
+}
+
+int menuitem_fullscreen(char * val)
+{
+	if (strlen(val)==0)
+	{
+		switch (options.fullscreen)
+		{
+			case FULLSCREENOFF:
+				strncpy(val,"off",MAXMENUVALUELENGTH);
+			break;
+			case FULLSCREENON:
+				strncpy(val,"on",MAXMENUVALUELENGTH);
+			break;
+			case FULLSCREENALWAYS:
+				strncpy(val,"always",MAXMENUVALUELENGTH);
+			break;
+		}
+		return POPUPMENUDONOTHING;
+	}
+	else
+	{
+		switch (options.fullscreen)
+		{
+			case FULLSCREENOFF:
+				options.fullscreen=FULLSCREENON;
+				strncpy(val,"on",MAXMENUVALUELENGTH);
+				makefullscreen();
+			break;
+			case FULLSCREENON:
+				options.fullscreen=FULLSCREENALWAYS;
+				strncpy(val,"always",MAXMENUVALUELENGTH);
+			break;
+			case FULLSCREENALWAYS:
+				options.fullscreen=FULLSCREENOFF;
+				strncpy(val,"off",MAXMENUVALUELENGTH);
+				makewindowed();
+			break;
+		}
+		return POPUPMENUREDRAWME;
+	}
+}
+
+
+int menuitem_difficulty(char * val)
+{
+	if (strlen(val)==0)
+	{
+		switch (options.difficulty)
+		{
+			case NORMAL:
+				strncpy(val,"normal",MAXMENUVALUELENGTH);
+			break;
+			case EASY:
+				strncpy(val,"easy",MAXMENUVALUELENGTH);
+			break;
+			case HARD:
+				strncpy(val,"hard",MAXMENUVALUELENGTH);
+			break;
+		}
+		return POPUPMENUDONOTHING;
+	}
+	else
+	{
+		switch (options.difficulty)
+		{
+			case NORMAL:
+				options.difficulty=EASY;
+				strncpy(val,"easy",MAXMENUVALUELENGTH);
+			break;
+			case EASY:
+				options.difficulty=HARD;
+				strncpy(val,"hard",MAXMENUVALUELENGTH);
+			break;
+			case HARD:
+				options.difficulty=NORMAL;
+				strncpy(val,"normal",MAXMENUVALUELENGTH);
+			break;
+		}
+		return POPUPMENUREDRAWME;
+	}
+}
+
+int menuitem_theme(char * val)
+{
+	if (strlen(val)==0)
+		strncpy(val,"linux",MAXMENUVALUELENGTH);
+
+
+	return POPUPMENUDONOTHING;
+}
+
+
+int popuphighscores()
+{
+	SDL_Rect scorelistrect,borderrect;
+	SDL_Surface * scorelistsave;
+	int quit=POPUPMENUDONOTHING;
+	int i;
+	char buf[30]; // plenty big. :)
+
+	scorelistrect.w=PLAYWIDTH-(BLOCKWIDTH*11);
+	scorelistrect.h=PLAYHEIGHT-(BLOCKHEIGHT*4);
+	scorelistrect.x=BORDERLEFT+PLAYWIDTH/2-scorelistrect.w/2+BLOCKWIDTH*4;
+	scorelistrect.y=BORDERTOP+PLAYHEIGHT/2-scorelistrect.h/2+BLOCKHEIGHT/2;
+	
+	borderrect.w=scorelistrect.w+2;
+	borderrect.h=scorelistrect.h+2;
+	borderrect.x=scorelistrect.x-1;
+	borderrect.y=scorelistrect.y-1;
+
+	scorelistsave = SDL_CreateRGBSurface(SDL_SWSURFACE,borderrect.w,borderrect.h,32,0,0,0,0);
+	SDL_BlitSurface(screen, &borderrect, scorelistsave, NULL);
+
+	SDL_FillRect(screen,&borderrect,SDL_MapRGB(screen->format,  0xC0, 0xC0, 0xC0));
+	SDL_FillRect(screen,&scorelistrect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+
+	puttext(scorelistrect.x+(scorelistrect.w/2-(CHARWIDTH*2*9)),scorelistrect.y+BLOCKHEIGHT,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x00),"HIGH SCORES");
+
+	// just in case they've changed...
+	readhiscores();
+
+	for (i=0;i<HISCORENUM;i++)
+	{
+		snprintf(buf,4,"%d.",i+1);
+		puttext(scorelistrect.x+BLOCKWIDTH,scorelistrect.y+45+i*(CHARHEIGHT*2+5),2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),buf);		
+		puttext(scorelistrect.x+BLOCKWIDTH*4,scorelistrect.y+45+i*(CHARHEIGHT*2+5),2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),hiscorename[i]);		
+		snprintf(buf,30,"%ld",hiscoreval[i]);		
+		puttext(scorelistrect.x+scorelistrect.w-(BLOCKWIDTH*5),scorelistrect.y+45+i*(CHARHEIGHT*2+5),2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),buf);
+	}
+	
+	soil(borderrect);	
+
+	clean();
+		
+	if (waitforuser()) quit=POPUPMENUQUITGAME;
+
+	SDL_BlitSurface(scorelistsave, NULL, screen, &borderrect);
+	soil(borderrect);
+	clean();
+
+	SDL_FreeSurface(scorelistsave);	 	
+
+	return(quit);
+}
+
+int popuphelp()
+{
+	SDL_Rect helprect,borderrect;
+	SDL_Surface * helpsave;
+	int quit=POPUPMENUDONOTHING;
+	int i=0;
+	char buf[80];
+
+	char helptext[13][50]={
+	     "Ok, so there's a bunch of penguins on an",
+	     "iceberg in Antarctica. You must catch them",
+	     "so they can be shipped to Finland. The",
+	     "smaller the area in which they're caught,",
+	     "the lower the shipping fees and the higher",
+	     "your score - but don't take too long: the",
+	     "clock is ticking. Once 80% of the 'berg is",
+	     "cleared, it's on to the next shipment.",
+	     "",
+	     "The left mouse button starts lines; right",
+	     "button toggles direction. You'll catch on.",
+	     "",
+	     "Check the README file for more info."
+	      };
+
+	helprect.w=PLAYWIDTH-(BLOCKWIDTH*2)+2;
+	helprect.h=PLAYHEIGHT-(BLOCKHEIGHT*3);
+	helprect.x=BORDERLEFT+PLAYWIDTH/2-helprect.w/2;
+	helprect.y=BORDERTOP+PLAYHEIGHT/2-helprect.h/2;
+	
+	borderrect.w=helprect.w+2;
+	borderrect.h=helprect.h+2;
+	borderrect.x=helprect.x-1;
+	borderrect.y=helprect.y-1;
+
+	helpsave = SDL_CreateRGBSurface(SDL_SWSURFACE,borderrect.w,borderrect.h,32,0,0,0,0);
+	SDL_BlitSurface(screen, &borderrect, helpsave, NULL);
+
+	SDL_FillRect(screen,&borderrect,SDL_MapRGB(screen->format,  0xC0, 0xC0, 0xC0));
+	SDL_FillRect(screen,&helprect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	for (i=0;i<13;i++)
+	{
+		puttext(helprect.x+BLOCKWIDTH/2,helprect.y+BLOCKHEIGHT/2+i*(CHARHEIGHT*2+4),2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),helptext[i]);		
+	}
+	snprintf(buf,80,"v%d.%d.%d   %s",VERMAJOR,VERMINOR,VERSUB,"Copyright (c) 2000-2001 Matthew Miller. Released under the GPL.");
+	puttext(helprect.x+BLOCKWIDTH/2,helprect.y+helprect.h-CHARHEIGHT*3,1,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0),buf);		
+	puttext(helprect.x+BLOCKWIDTH/2,helprect.y+helprect.h-CHARHEIGHT*1-3,1,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0),"Thanks to my wonderful wife Karen for inspiration (and for patience)!");		
+	
+	soil(borderrect);	
+
+	clean();
+
+	if (waitforuser()) quit=POPUPMENUQUITGAME;
+
+	SDL_BlitSurface(helpsave, NULL, screen, &borderrect);
+	soil(borderrect);
+	clean();
+
+	SDL_FreeSurface(helpsave);	 	
+
+	return(quit);
+}
+
+
+/* Wait for the user to hit a key or button or quit; returns true if quit */
+int waitforuser()
+{
+	int done=false;
+	int quit=false;
+	SDL_Event event;
+	
+	do
+	{
+		SDL_WaitEvent(NULL);
+		while(SDL_PollEvent(&event))
+		{
+			if ( event.type == SDL_QUIT)
+			{
+				done=true;
+				quit=true;
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				done=true;
+			}
+			else if (event.type == SDL_KEYUP) // fix -- add keyboard support
+			{
+			}
+		}
+	} while (!done);
+	return(quit);		
+}
+
+
+
+
+/* displays a menu; takes a rect for position and size, the length of the
+ * menu, an array of menu items, an array of pointers to functions for
+ * each menu item (functions should return type MenuReturnType
+ * indicating what to do when the item is clicked) and a flag telling whether
+ * menu items are option/value pairs.
+ */
+int menuhandler(SDL_Rect menurect, int menulength, char ** menuitems, int (**menufunctions)(char *), int menuvaluetextwidth)
+{
+	SDL_Rect borderrect;
+	SDL_Rect menuitemrect[MAXMENUITEMS];
+	char menuvalues[MAXMENUITEMS][MAXMENUVALUELENGTH];
+	int menuitemglow=-1;
+	int menuitempressed=false;
+	SDL_Event event;
+	SDL_Surface * menusave;
+	int quit=POPUPMENUDONOTHING;
+
+	int i;
+	
+	borderrect.w=menurect.w+2;
+	borderrect.h=menurect.h+2;
+	borderrect.x=menurect.x-1;
+	borderrect.y=menurect.y-1;
+
+	menusave = SDL_CreateRGBSurface(SDL_SWSURFACE,borderrect.w,borderrect.h,32,0,0,0,0);
+	SDL_BlitSurface(screen, &borderrect, menusave, NULL);
+
+	SDL_FillRect(screen,&borderrect,SDL_MapRGB(screen->format,  0xC0, 0xC0, 0xC0));
+	SDL_FillRect(screen,&menurect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	for (i=0;i<menulength;i++)
+	{
+		menuitemrect[i].x=menurect.x;
+		menuitemrect[i].y=menurect.y+2+(i*(CHARHEIGHT*2+3));
+		menuitemrect[i].w=menurect.w;
+		menuitemrect[i].h=(CHARHEIGHT*2)+3;
+		puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuitems[i]);
+
+		strncpy(menuvalues[i],"",MAXMENUVALUELENGTH);
+		if (menuvaluetextwidth)
+		{
+			if (menufunctions!=NULL && menufunctions[i]!=NULL)
+				(*menufunctions[i])(menuvalues[i]);
+			puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuvalues[i]);
+		}
+	}		
+	
+	soil(borderrect);	
+	
+	clean();
+	
+	
+	// find options
+	
+	do
+	{
+		SDL_WaitEvent(NULL); // no new CPU cooler needed. :)
+		while (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_QUIT)
+			{
+				quit=POPUPMENUQUITGAME;
+			}
+			else if (event.type == SDL_MOUSEBUTTONDOWN)
+			{  // fix -- make this left button only
+				if (event.button.x>menurect.x &&
+				    event.button.y>menurect.y &&
+				    event.button.x<menurect.x + menurect.w &&
+				    event.button.y<menurect.y + menurect.h)
+				{
+					menuitempressed=true;
+				}
+				else
+				{
+					quit=POPUPMENUEXITMENU;
+				}
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				if (menuitempressed)
+				{
+					// in area, button was down
+					if (event.motion.x>menurect.x &&
+					    event.motion.y>(menurect.y + 2) &&
+					    event.motion.x<menurect.x + menurect.w &&
+					    event.motion.y<menurect.y + menurect.h - 2)
+					{
+						if (menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
+							quit=(*menufunctions[menuitemglow])(menuvalues[menuitemglow]);
+					}					
+					menuitempressed=false;
+				}
+			}
+			else if (event.type == SDL_MOUSEMOTION)
+			{
+				// are we in the menu area?
+				if (event.motion.x>menurect.x &&
+				    event.motion.y>(menurect.y + 2) &&
+				    event.motion.x<menurect.x + menurect.w &&
+				    event.motion.y<menurect.y + menurect.h - 2)
+				{
+					// FIX -- should check for overflow, just to be sure.
+					menuitemglow=(event.motion.y-(menurect.y+3))/(CHARHEIGHT*2+3);
+					// FIX -- this is inefficient.
+					SDL_FillRect(screen,&menurect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+					for (i=0;i<menulength;i++)
+					{
+						if (i == menuitemglow)
+						{
+							SDL_FillRect(screen,&menuitemrect[i],SDL_MapRGB(screen->format,  0xF0, 0xF0, 0xF0));
+							puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),menuitems[i]);
+							if (menuvaluetextwidth) puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),menuvalues[i]);
+						}
+						else
+						{
+							puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuitems[i]);
+							if (menuvaluetextwidth) puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuvalues[i]);
+						}
+					}		
+					soil(menurect);
+				}
+				else
+				{
+					if (menuitemglow != -1 && !menuitempressed)
+					{
+						menuitemglow=-1;
+						SDL_FillRect(screen,&menurect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+						for (i=0;i<menulength;i++)
+						{
+							puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuitems[i]);
+							if (menuvaluetextwidth) puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),menuvalues[i]);
+						}
+						soil(menurect);
+					}
+				}
+			
+			}
+			else if (event.type==SDL_KEYDOWN) // FIX -- add keyboard support
+			{
+			}
+		}
+		
+		if (quit==POPUPMENUREDRAWME)
+		{	
+			quit=POPUPMENUDONOTHING;
+			// add a fake event so "Options" gets un-highlighted if need be.
+			SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
+			event.type = SDL_MOUSEMOTION;
+			SDL_PushEvent(&event);
+		}
+		
+		clean();
+	} while (quit==POPUPMENUDONOTHING);
+
+
+	// and restore the background
+	if (quit != POPUPMENUQUITGAME) // of course, if we're quitting, don't waste time
+	{
+		SDL_BlitSurface(menusave, NULL, screen, &borderrect);
+		soil(borderrect);
+		clean();
+	}
+
+	SDL_FreeSurface(menusave);	
+	
+
+	// a fake event update things that depend on mouse position
+	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
+	event.type = SDL_MOUSEMOTION;
+	SDL_PushEvent(&event);
+
+	return(quit);
+
+}
diff --git a/dialog.h b/dialog.h
new file mode 100644
index 0000000..0c0f2b0
--- /dev/null
+++ b/dialog.h
@@ -0,0 +1,39 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+// FIX -- make this be enum MenuReturnType
+#define POPUPMENUDONOTHING 0
+#define POPUPMENUEXITMENU 1
+#define POPUPMENUQUITGAME 2
+#define POPUPMENUNEWGAME 3
+#define POPUPMENUREDRAWME 4
+
+
+extern int gethighusername(int highest);
+
+extern int popupmenu(void);
+extern int popuphelp(void);
+extern int popuphighscores(void);
+extern int popupoptionsmenu(void);
+
+extern int waitforuser(void);
+
+
diff --git a/fullscreen.c b/fullscreen.c
new file mode 100644
index 0000000..9df4fa5
--- /dev/null
+++ b/fullscreen.c
@@ -0,0 +1,73 @@
+/*
+* IceBreaker
+* Copyright (c) 2001 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+#include <SDL.h>
+#include <stdlib.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "laundry.h"
+
+
+int isfullscreen=false;
+
+int makefullscreen()
+{
+	SDL_Surface * fullscreensave=SDL_CreateRGBSurface(SDL_SWSURFACE,WIDTH,HEIGHT,32,0,0,0,0);
+
+	clean();
+	SDL_BlitSurface(screen, NULL, fullscreensave, NULL);
+	
+	//screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE | SDL_FULLSCREEN );
+	screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_FULLSCREEN );
+	if (screen == NULL)
+	{
+		fprintf(stderr, "Couldn't switch to full screen mode.\n"
+		                "SDL error: "
+		                "%s\n\n", SDL_GetError());
+		exit(1);
+	}	
+	
+	SDL_BlitSurface(fullscreensave, NULL, screen, NULL);
+	SDL_UpdateRect(screen,0,0,0,0);
+	SDL_FreeSurface(fullscreensave);
+	return 0;
+}
+
+int makewindowed()
+{
+	SDL_Surface * fullscreensave=SDL_CreateRGBSurface(SDL_SWSURFACE,WIDTH,HEIGHT,32,0,0,0,0);
+	clean();
+	SDL_BlitSurface(screen, NULL, fullscreensave, NULL);
+	
+	screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE);
+	if (screen == NULL)
+	{
+		fprintf(stderr, "Couldn't switch to windowed screen mode.\n"
+		                "SDL error: "
+		                "%s\n\n", SDL_GetError());
+		exit(1);
+	}	
+	
+	SDL_BlitSurface(fullscreensave, NULL, screen, NULL);
+	SDL_UpdateRect(screen,0,0,0,0);
+	SDL_FreeSurface(fullscreensave);
+	return 0;
+}
diff --git a/fullscreen.h b/fullscreen.h
new file mode 100644
index 0000000..22571e7
--- /dev/null
+++ b/fullscreen.h
@@ -0,0 +1,26 @@
+/*
+* IceBreaker
+* Copyright (c) 2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+extern int isfullscreen;
+
+extern int makefullscreen(void);
+extern int makewindowed(void);
diff --git a/globals.h b/globals.h
new file mode 100644
index 0000000..2d9c33b
--- /dev/null
+++ b/globals.h
@@ -0,0 +1,28 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern SDL_Surface * screen;
+extern SDL_Surface * screensave;
+extern SDL_Surface * penguinimage;
+
+extern char grid[WIDTH][HEIGHT];
+
+extern char username[50];
+extern char homedir[255];
diff --git a/grid.c b/grid.c
new file mode 100644
index 0000000..1caa303
--- /dev/null
+++ b/grid.c
@@ -0,0 +1,244 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <string.h>
+
+#include "icebreaker.h"
+#include "laundry.h"
+#include "grid.h"
+#include "penguin.h"
+#include "globals.h"
+
+static char maskgrid[WIDTH][HEIGHT];
+
+// kludge-o-rama
+static long rcount;
+#define MAXRCOUNT 80000
+
+
+
+void markgrid(int x, int y, int w, int h, char fillchar)
+{
+	int i;
+	for (i=x;i<x+w;i++)
+		memset(&grid[i][y],fillchar,h); // FIX -- do the pointer math ourselves; it's a teensy bit faster, and this function gets called *a lot*
+	
+	/*
+	int i, j;
+	for (j=y;j<y+h;j++)
+		for (i=x;i<x+w;i++)
+			grid[i][j]=fillchar;		
+	*/	
+}
+
+long countcleared()
+{
+	int i, j;
+	long c;
+	c=0;
+	for (i=BORDERLEFT;i<BORDERRIGHT;i++)
+		for (j=BORDERTOP;j<BORDERBOTTOM;j++)
+			if (grid[i][j] == ' ' || grid[i][j] == '*')
+				c++;
+	//return(100-(c*100/(PLAYWIDTH*PLAYHEIGHT)));
+	return(c);
+	
+}
+
+#ifdef DEBUG
+void printboard()
+{
+	int i, j;
+	
+	for (j=BLOCKWIDTH/2;j<HEIGHT;j+=BLOCKHEIGHT)
+	{
+		for (i=BLOCKWIDTH/2;i<WIDTH;i+=BLOCKWIDTH)
+		{
+			printf("%c ",grid[i][j]);
+		}
+		printf("\n");
+	}
+}
+#endif
+
+#ifdef DEBUG
+void printwholegrid()
+{
+	int i, j;
+	
+	printf ("grid:\n");
+	for (j=0;j<HEIGHT;j++)
+	{
+		for (i=0;i<WIDTH;i++)
+		{
+			printf("%c ",grid[i][j]);
+		}
+		printf("\n");
+	}
+}
+#endif
+
+#ifdef DEBUG
+void printwholemaskgrid()
+{
+	int i, j;
+	
+	printf ("maskgrid:\n");
+	for (j=0;j<HEIGHT;j++)
+	{
+		for (i=0;i<WIDTH;i++)
+		{
+			printf("%c ",maskgrid[i][j]);
+		}
+		printf("\n");
+	}
+}
+#endif
+
+void checkempty(int x, int y)
+{
+	//int i,j;
+	SDL_Rect tmprect;
+	
+
+	// if square isn't empty, just return....
+	if (grid[x][y]!=' ') {  return; }
+
+
+	// it'd be nice to find a way to keep this longer...
+	memcpy(maskgrid,grid,WIDTH*HEIGHT);
+	
+
+	// penguinsearch at that spot...
+	rcount=0;
+	if (!penguinsearch(x,y)) // area is clear!
+	{
+		//printwholemaskgrid();
+		
+
+		
+		//floodfill(x,y);
+		
+		// this makes sure x and y are the top left corners of blocks.
+		// since the area is empty of penguins, it should be completely
+		// safe to use this isntead of floodfill here. really. :)
+		squarefill( (((x-BORDERLEFT)/BLOCKWIDTH ) * BLOCKWIDTH ) +BORDERLEFT, (((y-BORDERTOP)/BLOCKHEIGHT) * BLOCKHEIGHT) +BORDERTOP);
+
+		tmprect.w=BLOCKWIDTH; tmprect.h=BLOCKHEIGHT;
+		for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
+			for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
+				if (grid[tmprect.x][tmprect.y]=='.') // clear it!)
+				{
+					SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+					soil(tmprect);
+				}
+		//printwholegrid();
+	}
+	/*
+	for (j=0;j<HEIGHT;j+=BLOCKHEIGHT)
+	{
+		for (i=0;i<WIDTH;i+=BLOCKWIDTH)
+		{
+			printf("%c ",maskgrid[i][j]);
+		}
+		printf("\n");
+	}
+	printf("\n");
+	*/
+}
+
+
+int penguinsearch(int i, int j)
+{
+	int searchval=0;
+
+	rcount++; 
+	// kludge! FIX! BAD!
+	if (rcount>MAXRCOUNT) // bail
+	{
+		fprintf(stderr,"Damn. Ran out of recursions.\n");
+		return(2);
+	}
+	
+	
+	// shouldn't need to check bounds because we're only painting in the
+	// middle. and we call this function so much that the time saved
+	// is worth it
+	//if (i<0 || j<0 || i>=WIDTH || j>=HEIGHT)
+	//{
+	//	fprintf(stderr,"That shouldn't have happened (penguinsearch)! (%d,%d)\n",i,j);
+	//	exit(1);
+	//}
+
+          
+	if (maskgrid[i][j]==' '
+	    || maskgrid[i][j]=='1' || maskgrid[i][j]=='2' || maskgrid[i][j]=='w')  // Ah ha! The nefarious "instant melting ice" bug solved!  NOTE: if more lines are added to the game, add them here too!
+	{
+		maskgrid[i][j]=',';
+		
+		searchval=penguinsearch(i+BLOCKWIDTH, j);
+		if (!searchval) searchval=penguinsearch(i-BLOCKWIDTH, j);
+		if (!searchval) searchval=penguinsearch(i, j-BLOCKHEIGHT);
+		if (!searchval) searchval=penguinsearch(i, j+BLOCKHEIGHT);
+		
+	}
+	else if (maskgrid[i][j]=='*') // found a penguin!
+	{
+		searchval=1;	
+	}
+	return(searchval);
+}
+
+
+void floodfill(int x, int y)
+{
+	// shouldn't need to check bounds because we're only painting in the
+	// middle.
+	//if (x<0 || y<0 || x>WIDTH || y>HEIGHT)
+	//{
+	//	fprintf(stderr,"That shouldn't have happened! (%d,%d)\n",x,y);
+	//	exit(1);
+	//}
+	if (grid[x][y]==' ' || grid[x][y]=='1' || grid[x][y]=='2' || grid[x][y]=='w')
+	{
+		grid[x][y]='.';
+		floodfill(x+1, y);
+		floodfill(x-1, y);
+		floodfill(x, y+1);
+		floodfill(x, y-1);
+	}
+}
+
+void squarefill(int x, int y)
+{
+	// x and y must be the top left corner of a square, or else this
+	// will look silly. and there's no bounds checking!
+
+	if (grid[x][y]==' ' || grid[x][y]=='1' || grid[x][y]=='2' || grid[x][y]=='w')
+	{
+		markgrid(x,y,BLOCKWIDTH,BLOCKHEIGHT,'.');
+		squarefill(x+BLOCKWIDTH, y);
+		squarefill(x-BLOCKWIDTH, y);
+		squarefill(x, y+BLOCKHEIGHT);
+		squarefill(x, y-BLOCKHEIGHT);
+	}
+}
+
diff --git a/grid.h b/grid.h
new file mode 100644
index 0000000..ed3bec0
--- /dev/null
+++ b/grid.h
@@ -0,0 +1,31 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern void printboard(void);
+extern void printwholegrid(void);
+extern void printwholemaskgrid();
+
+extern void markgrid(int x, int y, int w, int h, char fillchar);
+extern long countcleared(void);
+extern void checkempty(int x, int y);
+extern int penguinsearch(int i, int j);
+extern void floodfill(int x, int y);
+extern void squarefill(int x, int y);
+
diff --git a/hiscore.c b/hiscore.c
new file mode 100644
index 0000000..02fa188
--- /dev/null
+++ b/hiscore.c
@@ -0,0 +1,163 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "hiscore.h"
+
+
+char hiscorename[HISCORENUM][50];
+long hiscoreval[HISCORENUM];
+
+static char temphiscorename[HISCORENUM+1][50]; //used for sorting
+static long temphiscoreval[HISCORENUM+1];
+
+static int cmpscore(int * a, int * b);
+
+void readhiscores()
+{
+	FILE *hiscorefile;
+	char linebuf[50];
+
+	int arrayindex[HISCORENUM];
+	int i;
+
+	// fill the "helper" array. 
+	for (i=0;i<HISCORENUM;i++)
+		arrayindex[i]=i;
+		
+
+
+	// make sure all entries are zeroed out to start.
+	for (i=0;i<HISCORENUM;i++)
+	{
+		snprintf(temphiscorename[i],7,"Nobody");
+		temphiscoreval[i]=100; //100 is better than 0. :)
+	}
+
+	hiscorefile=fopen(HISCOREPREFIX "/" HISCOREFILE,"r");
+	if (hiscorefile==NULL)
+	{
+		// It's writing we need to worry about, really, so don't
+		// complain here.
+		//fprintf(stderr,"Can't read high score file; continuing anyway.\nYou may want to ask your sysadmin to make sure this program can access\n " HISCOREPREFIX "/" HISCOREFILE "\n");
+	}
+	else
+	{
+		for (i=0;i<HISCORENUM;i++)
+		{
+			if (fgets(linebuf,50,hiscorefile))
+			{
+				sscanf(linebuf,"%12s %30ld",temphiscorename[i],&temphiscoreval[i]);
+			}
+		}
+		fclose(hiscorefile);
+		
+		// sort arrayindex based on the corresponding hiscoreval
+		// really, the array should already be sorted. but you never know.	
+		qsort(arrayindex, HISCORENUM, sizeof(int), (int (*)(const void*,const void*))cmpscore);
+
+	}
+	
+	// ok, so now, we can copy things over in the proper sorted order
+	for (i=0;i<HISCORENUM;i++)
+	{
+		snprintf(hiscorename[i],50,temphiscorename[arrayindex[i]]);
+		hiscoreval[i]=temphiscoreval[arrayindex[i]];
+	}
+
+}
+
+
+int checkhiscore(long score)
+{
+	// need to re-read from disk in case another user has obtained
+	// a better score in the meantime...
+	readhiscores();
+	// check to see if score is better than the lowest high score
+	return (score>hiscoreval[HISCORENUM-1]);
+}
+
+void addhiscore(char * username, long score)
+{
+	int arrayindex[HISCORENUM+1]; // note the +1 -- we're including the new score
+	FILE *hiscorefile;
+	int i;
+
+
+	// make sure the temp array contains the right data
+	for (i=0;i<HISCORENUM;i++)
+	{
+		snprintf(temphiscorename[i],50,hiscorename[i]);
+		temphiscoreval[i]=hiscoreval[i];
+	}
+	
+	// and toss in the new data 
+	//(this is why these arrays are size HISCORENUM+1)
+	snprintf(temphiscorename[HISCORENUM],50,username);
+	temphiscoreval[HISCORENUM]=score;
+
+	// fill the "helper" array. 
+	for (i=0;i<HISCORENUM+1;i++)
+		arrayindex[i]=i;
+
+	
+	// ok, now sort those 
+	qsort(arrayindex, HISCORENUM+1, sizeof(int), (int (*)(const void*,const void*))cmpscore);
+
+	// and take the top ones back.
+	for (i=0;i<HISCORENUM;i++)
+	{
+		snprintf(hiscorename[i],50,temphiscorename[arrayindex[i]]); 
+		hiscoreval[i]=temphiscoreval[arrayindex[i]];
+	}
+
+	// writehiscores:
+
+	hiscorefile=fopen(HISCOREPREFIX "/" HISCOREFILE,"w");
+	if (hiscorefile==NULL)
+	{
+		fprintf(stderr,"Can't save high scores.\n");
+		fprintf(stderr,"You may want to ask your sysadmin to make sure this program can write to\n<" HISCOREPREFIX "/" HISCOREFILE ">.\n");
+	}
+	else
+	{
+		// FIX -- make this go. :)
+		//for (i=0;hiscorename[i]!='\0';i++)
+		//	if (hiscorename[i]==' ') hiscorename[i]='_';
+			
+		for (i=0;i<HISCORENUM;i++)
+		{
+			fprintf(hiscorefile,"%s %ld\n",hiscorename[i],hiscoreval[i]);
+		}
+		fclose(hiscorefile);
+	}
+}
+
+int cmpscore(int * a, int * b)
+{
+	return(temphiscoreval[*b] - temphiscoreval[*a]);
+}
+
+
diff --git a/hiscore.h b/hiscore.h
new file mode 100644
index 0000000..d9ed790
--- /dev/null
+++ b/hiscore.h
@@ -0,0 +1,31 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern void readhiscores(void);
+extern void addhiscore(char * username, long score);
+extern int checkhiscore(long score);
+
+#define HISCORENUM 10
+
+
+extern char hiscorename[HISCORENUM][50];
+extern long hiscoreval[HISCORENUM];
+
diff --git a/icebreaker.c b/icebreaker.c
new file mode 100644
index 0000000..3f9c29a
--- /dev/null
+++ b/icebreaker.c
@@ -0,0 +1,225 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#ifndef WIN32
+	#include <pwd.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+              
+
+#include "icebreaker.h"
+#include "penguin.h"
+#include "line.h"
+#include "grid.h"
+#include "sound.h"
+#include "globals.h"
+#include "level.h"
+#include "intro.h"
+#include "text.h"
+#include "transition.h"
+#include "hiscore.h"
+#include "dialog.h"
+#include "options.h"
+#include "fullscreen.h"
+#include "cursor.h"
+
+// global
+SDL_Surface * screen;
+SDL_Surface * screensave;
+SDL_Surface * penguinimage;
+
+char grid[WIDTH][HEIGHT];
+
+char username[50]; // FIX -- move this into the options struct?
+char homedir[255];
+
+SDL_Surface * penguinicon;
+
+// functions
+
+int setup(void);
+void cleanup(void);
+
+/************************************************************************/
+
+int setup(void)
+{
+	struct passwd * userinfo;
+	int newuser=false;
+	
+	srandom(time(NULL));	
+	
+	
+	
+	//stupid buffers
+	setvbuf(stdout,(char *)NULL, _IOLBF, 0);
+	
+	userinfo = getpwuid(getuid()); // FIX -- make this part of the options struct; and maybe save in options file
+	strncpy(username,userinfo->pw_name,50); // not like it's gonna be fifty characters. but y'know.
+	strncpy(homedir,userinfo->pw_dir,255);
+
+	readhiscores();
+	newuser=readoptions();		
+
+	if (SDL_Init(SDL_INIT_VIDEO))
+	{
+		fprintf(stderr, "Hey. We're gonna need some graphics.\n"
+		                "SDL error: " 
+		                "%s\n\n", SDL_GetError());
+		exit(1);
+	}
+	
+	
+	//atexit(SDL_Quit);
+	atexit(cleanup);
+
+	penguinicon = SDL_LoadBMP(DATAPREFIX "/" PENGUINICONFILE);
+	if (penguinicon==NULL) fprintf(stderr, "Icon not loaded!\n");
+	SDL_WM_SetIcon(penguinicon,NULL);
+	
+	SDL_WM_SetCaption("IceBreaker","IceBreaker");
+	
+	if (options.fullscreen!=FULLSCREENOFF)
+	{
+		screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_FULLSCREEN);	
+	}
+	else
+	{
+		screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE);
+	}
+	if (screen == NULL)
+	{
+		fprintf(stderr, "Help! Couldn't get a window.\n"
+		                "SDL error: " 
+		                "%s\n\n", SDL_GetError());
+		exit(1);
+	}
+
+	
+	screensave = SDL_CreateRGBSurface(SDL_SWSURFACE,screen->w,screen->h,32,0,0,0,0);
+
+	// FIX -- need "initpenguin" routine. and some error checking!
+	penguinimage = SDL_LoadBMP(DATAPREFIX "/" PENGUINBMPFILE);
+	SDL_SetColorKey(penguinimage, SDL_SRCCOLORKEY, SDL_MapRGB(penguinimage->format, 0xFF, 0x00, 0x00));	
+
+	// FIX -- need preference.
+	initsound();
+
+	inittext();
+
+
+	return newuser;
+}
+
+void cleanup()
+{
+	//writehiscores(); // now written only when hi score is actually achieved
+	quitsound();
+	SDL_Quit();
+	writeoptions();
+}
+
+
+
+int main(int argc,char *argv[])
+{
+	int done = false;
+	int level=0;
+	ScoreSheet levelscore;
+	long totalscore=0;
+	char windowtitle[35];
+	LevelExitType levelresult;
+	int newuser=false;
+	
+	
+	newuser=setup();
+
+	done=intro();	
+
+
+	if (!done && newuser)
+	{ // no options file; using the default
+		setcursor(CURSORCLICK);
+		popuphelp();	
+		setcursor(CURSORARROW);
+	}
+	
+		
+ 	while(!done)
+	{
+		level++;
+		if (level>=MAXPENGUINS) level=MAXPENGUINS-1;
+
+		switch (options.difficulty)
+		{
+			case NORMAL:
+				snprintf(windowtitle,35,"IceBreaker -- Level %d",level);
+			break;
+			case HARD:
+				snprintf(windowtitle,35,"IceBreaker -- Level %d (Hard)",level);
+			break;
+			case EASY:
+				snprintf(windowtitle,35,"IceBreaker -- Level %d (Easy)",level);
+			break;
+		}			
+		SDL_WM_SetCaption(windowtitle,"IceBreaker");
+		
+		levelresult=playlevel(level,totalscore,&levelscore);
+		
+  		SDL_WM_SetCaption("IceBreaker","IceBreaker");
+		
+		totalscore+= levelscore.basescore + levelscore.clearbonus + levelscore.lifebonus;
+		
+		if (levelresult == QUIT)
+		{
+			done=true;
+		}
+		else if (levelresult == DEAD)
+		{
+			done=gameover(totalscore);
+						
+			// hooray! modifying the index variable in the loop!
+			// good coding practice at its finest!
+			level=0; 
+			totalscore=0; 
+		}
+		else if (levelresult == ERROR)
+		{
+			fprintf(stderr,"Level error -- this should never happen.\n");
+		}
+		else
+		{
+			// level completed successfully
+			done=intermission(&levelscore,level+1);
+		}
+
+	}
+	//printf("===========================================================\n");
+	//printf("\nFinal Score: %ld\n",totalscore);	
+	
+	return(0);
+}
diff --git a/icebreaker.desktop b/icebreaker.desktop
new file mode 100644
index 0000000..911bb67
--- /dev/null
+++ b/icebreaker.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=IceBreaker
+Type=Application
+Comment=%{Summary}
+Exec=icebreaker
+Icon=/usr/share/icebreaker/icebreaker_48.bmp
+Terminal=0
diff --git a/icebreaker.h b/icebreaker.h
new file mode 100644
index 0000000..fb2cd93
--- /dev/null
+++ b/icebreaker.h
@@ -0,0 +1,113 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#define VERSION 1.2.1
+#define VERMAJOR 1
+#define VERMINOR 2
+#define VERSUB 1
+
+
+#ifndef HISCOREPREFIX
+#define HISCOREPREFIX "/var/lib/games"
+#endif
+
+#define HISCOREFILE "icebreaker.scores"
+
+#ifndef DATAPREFIX 
+#define DATAPREFIX "/usr/local/share/icebreaker"
+#endif
+
+#ifndef OPTIONFILE
+  #ifdef WIN32
+    #define OPTIONFILE "icebreaker.cfg"
+  #else
+    #define OPTIONFILE ".icebreaker"
+  #endif
+#endif  
+
+#define SNDFILEOUCH "ouch.wav"
+#define SNDFILEBREAK "crash.wav"
+#define PENGUINBMPFILE "penguin.bmp"
+
+#ifdef WIN32
+  #define PENGUINICONFILE "penguinicon_32.bmp"
+#else
+  #define PENGUINICONFILE "icebreaker_48.bmp"
+#endif
+
+#define BLOCKWIDTH 14
+#define BLOCKHEIGHT 14
+
+#define COLS 32
+#define ROWS 20
+
+#define PLAYWIDTH (COLS*BLOCKWIDTH)
+#define PLAYHEIGHT (ROWS*BLOCKHEIGHT)
+
+#define MARGINTOP 39
+#define MARGINBOTTOM 38
+#define MARGINLEFT 26
+#define MARGINRIGHT 26
+
+/* Centered in 640x480: 
+// #define MARGINTOP 100
+// #define MARGINBOTTOM 100
+// #define MARGINLEFT  96
+// #define MARGINRIGHT 96 
+*/
+
+#define WIDTH (MARGINLEFT+PLAYWIDTH+MARGINRIGHT)
+#define HEIGHT (MARGINTOP+PLAYHEIGHT+MARGINBOTTOM)
+
+#define BORDERTOP    MARGINTOP
+#define BORDERBOTTOM (MARGINTOP+PLAYHEIGHT)
+#define BORDERLEFT   MARGINLEFT
+#define BORDERRIGHT  (MARGINLEFT+PLAYWIDTH)
+
+
+#define MAXPENGUINS 100
+
+#define PENGUINSPEED 2
+
+#define LINESPEED 2
+
+#define LINEMAXSTUCK 750
+
+#define PERCENTREQUIRED 80
+#define PERCENTBONUS 80
+#define PERCENTEXTRABONUS 85
+
+#ifndef true
+#define true -1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+#ifdef WIN32
+	#include "win32_compatibility.h"
+#endif
+
+#ifdef WIN32
+	#define HIDEFULLSCREEN
+#endif
+
diff --git a/icebreaker.man.in b/icebreaker.man.in
new file mode 100644
index 0000000..b2c3ccf
--- /dev/null
+++ b/icebreaker.man.in
@@ -0,0 +1,56 @@
+.de Y
+.ft CW
+.in +4n
+.nf
+\&\\$1
+.ft
+.in
+.fi
+..
+.TH icebreaker 6 "v$VERSION: $VERDATE"
+.SH NAME
+icebreaker - An addictive action-puzzle game for X.
+.SH SYNOPSIS
+.B icebreaker
+.SH DESCRIPTION
+So, uh, there's a bunch of penguins on an iceberg in Antarctica. You
+have been selected to catch them so they can be shipped to Finland, where
+they are essential to a secret plot for world domination.
+.PP
+In order to trap the penguins, you'll need to break the iceberg into small
+chunks by melting lines without hitting any of the birds. Once 80% or more
+of the 'berg is gone, you advance to the next level.
+.PP
+Use the left mouse button to start lines, and the right (and/or middle)
+button to toggle between horizontal and vertical. Beyond that, it's probably
+easier for you go figure out the game by playing than by reading. So go.
+.PP
+Go!
+.SH OPTIONS
+None in current version; in the future there will probably be some. See
+.SM
+.BR BUGS .
+
+.SH FILES
+.TP 
+.I /var/lib/games/icebreaker.scores
+The system-wide list of high scores.
+.TP
+.I ~/.icebreaker
+The per-user options file; see comments in the file itself for more info.
+.SH BUGS
+See the included TODO file. And I'm sure there's a few that have slipped in
+without my knowledge. Please report anything you find to
+.IR mattdm at mattdm.org .
+
+.SH SEE ALSO
+There's an included README file. It's very clever. (I know because I wrote
+it.) And there's a web site at
+.IR http://www.mattdm.org/icebreaker/ .
+
+.SH COPYRIGHT
+icebreaker is Copyright (C) 2000-2001 Matthew Miller and released under the
+terms of the GNU General Public License.  See the documentation included with
+the program for more details.
+.SH AUTHOR
+Matthew Miller (mattdm at mattdm.org)
diff --git a/icebreaker.spec b/icebreaker.spec
new file mode 100644
index 0000000..c0dfab8
--- /dev/null
+++ b/icebreaker.spec
@@ -0,0 +1,97 @@
+Summary:	An addictive action-puzzle game involving bouncing penguins
+Name:		icebreaker
+Version:	1.2.1
+Release:	1
+Epoch:		3
+Copyright:	GPL
+Group:		Amusements/Games
+Source: 	icebreaker-%{version}.tgz
+URL:		http://www.mattdm.org/icebreaker/
+Prefix:		%{_prefix}
+Vendor: 	Matthew Miller <mattdm at mattdm.org>
+Packager:	Matthew Miller <mattdm at mattdm.org>
+BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildRequires:  SDL-devel, SDL_mixer-devel, /bin/awk
+
+%description
+So, uh, there's a bunch of penguins on an iceberg in Antarctica. You have
+been selected to catch them so they can be shipped to Finland, where they
+are essential to a secret plot for world domination.
+
+%prep
+%setup -q
+
+%build
+make OPTIMIZE="$RPM_OPT_FLAGS -finline-functions" highscoredir=/var/lib/games prefix=/usr
+
+%install
+rm -rf $RPM_BUILD_ROOT
+
+mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
+mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/icebreaker
+mkdir -p ${RPM_BUILD_ROOT}%{_var}/lib/games
+mkdir -p ${RPM_BUILD_ROOT}/etc/X11/applnk/Games
+mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man6
+
+install -m 644 *.wav *.bmp ${RPM_BUILD_ROOT}%{_datadir}/icebreaker
+install -m 644 icebreaker.desktop ${RPM_BUILD_ROOT}/etc/X11/applnk/Games
+install -s -m 755 icebreaker ${RPM_BUILD_ROOT}%{_bindir}
+install -m 644 icebreaker.6  ${RPM_BUILD_ROOT}%{_mandir}/man6
+
+touch ${RPM_BUILD_ROOT}%{_var}/lib/games/icebreaker.scores
+
+%post
+touch %{_var}/lib/games/icebreaker.scores
+chown games:games %{_var}/lib/games/icebreaker.scores
+chmod 0664 %{_var}/lib/games/icebreaker.scores
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr (-,root,root)
+%doc README TODO LICENSE ChangeLog
+%attr(2755,root,games) %{_bindir}/icebreaker
+/etc/X11/applnk/Games/icebreaker.desktop
+%{_datadir}/icebreaker
+%{_mandir}/man6/*
+%attr(664,games,games) %ghost %{_var}/lib/games/icebreaker.scores
+
+%changelog
+* Sat Jul 28 2001 Matthew Miller <mattdm at mattdm.org>
+- 1.2
+
+* Tue Jul 24 2001 Matthew Miller <mattdm at mattdm.org>
+- move man page section 6
+
+* Sun Jul 22 2001 Matthew Miller <mattdm at mattdm.org>
+- 1.1
+
+* Fri Jul 20 2001 Matthew Miller <mattdm at mattdm.org>
+- borrowed idea of using post-script to create high score file
+  from Mandrake RPM. That way, it doesn't have to be marked as a config
+  file, and yet won't get zapped on upgrade.
+- also, modified Makefile to cope with RPM_OPT_FLAGS, again as per
+  Mandrake.
+
+* Thu Jul 19 2001 Matthew Miller <mattdm at mattdm.org>
+- added man page
+
+* Tue Jul 18 2001 Matthew Miller <mattdm at mattdm.org>
+- updated to 1.09
+
+* Thu Oct 5 2000 Matthew Miller <mattdm at mattdm.org>
+- looks good to me. one-point-oh
+
+* Tue Oct 3 2000 Matthew Miller <mattdm at mattdm.org>
+- updated to 0.995 
+- better make process
+
+* Mon Oct 2 2000 Matthew Miller <mattdm at mattdm.org>
+- updated to 0.99 :)
+
+* Mon Oct 2 2000 Matthew Miller <mattdm at mattdm.org>
+- updated to 0.98
+
+* Fri Sep 15 2000 Matthew Miller <mattdm at mattdm.org>
+- first package
diff --git a/icebreaker_32.ico b/icebreaker_32.ico
new file mode 100644
index 0000000..eef9e4f
Binary files /dev/null and b/icebreaker_32.ico differ
diff --git a/icebreaker_48.bmp b/icebreaker_48.bmp
new file mode 100644
index 0000000..e1e64cb
Binary files /dev/null and b/icebreaker_48.bmp differ
diff --git a/intro.c b/intro.c
new file mode 100644
index 0000000..3b500e4
--- /dev/null
+++ b/intro.c
@@ -0,0 +1,584 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "icebreaker.h"
+#include "cursor.h"
+#include "penguin.h"
+#include "line.h"
+#include "grid.h"
+#include "sound.h"
+#include "laundry.h"
+#include "globals.h"
+#include "level.h"
+#include "status.h"
+#include "text.h"
+#include "hiscore.h"
+
+#define LXPOS(x) (BORDERLEFT+(BLOCKWIDTH*(x)))
+#define LYPOS(y) (BORDERTOP+(BLOCKHEIGHT*(y)))
+
+static void setupintro(void);
+
+void setupintro()
+{
+	int x,y;
+	int c;
+	SDL_Rect tmprect;
+
+	setcursor(CURSORARROW);
+	SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+	
+	tmprect.x=BORDERLEFT; tmprect.y=BORDERTOP;
+	tmprect.w=PLAYWIDTH; tmprect.h=PLAYHEIGHT;
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0));
+
+	tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
+	for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
+		for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
+			{
+				c = (random() % 32)+224;
+				SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, c, c, c));
+			}
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+
+
+	SDL_UpdateRect(screen,0,0,0,0);
+	
+	for (x=0;x<WIDTH;x++)
+		for (y=0;y<HEIGHT;y++)
+		{
+			if (x<BORDERLEFT || x>=BORDERRIGHT || y <BORDERTOP || y>=BORDERBOTTOM) 	
+				grid[x][y]='X';
+			else
+				grid[x][y]='w';
+		}
+	
+	/// Here's the fun part where we set up the letters.
+	// I
+	markgrid(LXPOS(1),LYPOS(2),BLOCKWIDTH*3,BLOCKHEIGHT  ,' ');
+	markgrid(LXPOS(1),LYPOS(7),BLOCKWIDTH*3,BLOCKHEIGHT  ,' ');
+	markgrid(LXPOS(2),LYPOS(2),BLOCKWIDTH  ,BLOCKHEIGHT*6,' ');
+	
+	//C
+	markgrid(LXPOS(5),LYPOS(2),BLOCKWIDTH*4,BLOCKHEIGHT  ,' ');
+	markgrid(LXPOS(5),LYPOS(3),BLOCKWIDTH  ,BLOCKHEIGHT*5,' ');	
+	markgrid(LXPOS(6),LYPOS(7),BLOCKWIDTH*3,BLOCKHEIGHT,  ' ');
+	
+	//E
+	markgrid(LXPOS(10),LYPOS(2),BLOCKWIDTH*4,BLOCKHEIGHT  ,' ');
+	markgrid(LXPOS(10),LYPOS(3),BLOCKWIDTH  ,BLOCKHEIGHT*5,' ');	
+	markgrid(LXPOS(11),LYPOS(7),BLOCKWIDTH*3,BLOCKHEIGHT,  ' ');
+	markgrid(LXPOS(11),LYPOS(4),BLOCKWIDTH*2,BLOCKHEIGHT  ,' ');
+	
+}
+
+
+
+int intro(void)
+{
+	// FIX -- hey, here's an idea. how about moving some of this crap
+	// to separate functions?
+
+
+	int penguincount=0;
+	int frozen=true;
+	int i;
+	int x,y;
+	int letterstep=0;
+	int hiscoreindex=0; int hiscorescroll=0;
+	int hiscorestep=false;
+	int linedone1=false; int linedone2=false;
+
+	char scoretext[40];
+	SDL_Rect labelrect;
+	SDL_Rect scrollrect;
+	SDL_Rect bigrect;
+	SDL_Rect rightmarginrect;
+	SDL_Rect leftmarginrect;
+	
+	int done = false;
+	
+	Penguin flock[100];
+	Penguin tux;
+	
+	SDL_Event event;
+
+	setupintro();
+	
+	
+	labelrect.x=BORDERLEFT;
+	labelrect.y=BORDERTOP-(4*CHARHEIGHT);
+	labelrect.h=CHARHEIGHT*2;
+	labelrect.w=CHARWIDTH*21;
+			
+	scrollrect.x=BORDERLEFT+CHARWIDTH*21;
+	scrollrect.y=labelrect.y;
+	scrollrect.w=BORDERRIGHT-(BORDERLEFT+CHARWIDTH*21);
+	scrollrect.h=labelrect.h;
+
+	rightmarginrect.x=BORDERRIGHT;
+	rightmarginrect.y=labelrect.y;
+	rightmarginrect.w=MARGINRIGHT;
+	rightmarginrect.h=labelrect.h;
+	
+	leftmarginrect.x=0;
+	leftmarginrect.y=labelrect.y;
+	leftmarginrect.w=BORDERLEFT;
+	leftmarginrect.h=labelrect.h;
+	
+	bigrect.x=labelrect.x;
+	bigrect.y=labelrect.y;
+	bigrect.w=WIDTH-(BORDERLEFT);
+	bigrect.h=labelrect.h;
+
+	hiscoreindex=HISCORENUM-1; hiscorescroll=200;
+
+	puttext(labelrect.x,labelrect.y,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),"HIGH SCORES:");
+	soil(labelrect);
+
+
+	line1=createline('1',0x00, 0x00, 0x00);
+	line2=createline('2',0xC0, 0x00, 0x40);
+
+	tux = createpenguin();
+	
+	do 
+	{
+		while (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_QUIT)
+			{
+				return(true);
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				done=true;
+			}
+			//FIX -- add keyboard support
+		}
+		if (letterstep < 10)
+		{	
+			switch (letterstep)
+			{
+				// I
+				case 0:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(2),LYPOS(2));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(2),LYPOS(2));
+				break;
+				case 1:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(2),LYPOS(7));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(2),LYPOS(7));
+				break;
+				case 2:
+					if (!linedone1 && !line1.on) startline(&line1,UP,LXPOS(2),LYPOS(5));
+					if (!linedone2 && !line2.on) startline(&line2,DOWN,LXPOS(2),LYPOS(5));
+				break;
+				// C
+				case 3:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(7),LYPOS(2));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(7),LYPOS(2));
+				break;
+				case 4:
+					if (!linedone1 && !line1.on) startline(&line1,UP,LXPOS(5),LYPOS(5));
+					if (!linedone2 && !line2.on) startline(&line2,DOWN,LXPOS(5),LYPOS(5));
+				break;
+				case 5:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(7),LYPOS(7));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(7),LYPOS(7));
+				break;
+				// E
+				case 6:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(11),LYPOS(2));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(11),LYPOS(2));
+				break;
+				case 7:
+					if (!linedone1 && !line1.on) startline(&line1,UP,LXPOS(10),LYPOS(5));
+					if (!linedone2 && !line2.on) startline(&line2,DOWN,LXPOS(10),LYPOS(5));
+				break;
+				case 8:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(13),LYPOS(7));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(13),LYPOS(7));
+				break;
+				case 9:
+					if (!linedone1 && !line1.on) startline(&line1,LEFT,LXPOS(12),LYPOS(4));
+					if (!linedone2 && !line2.on) startline(&line2,RIGHT,LXPOS(12),LYPOS(4));
+				break;
+			}
+				
+		}
+		else if (letterstep==10)
+		{
+			for (x=0;x<WIDTH;x++)
+				for (y=0;y<HEIGHT;y++)
+					if (grid[x][y]=='w')
+					{
+						grid[x][y]=' ';
+					}
+					// FIX: known bug -- if a line stops partway through a grid cell,
+					// the space left over is not cleared properly later. this isn't 
+					// an issue in the game, as lines aways stop on cell boundaries, but
+					// sometimes shows up in the intro. this is a kludge
+					// which should fix it.
+					else if (((x-BORDERLEFT) % BLOCKWIDTH)==0 && ((y-BORDERTOP) % BLOCKHEIGHT)==0)
+					{
+						if (grid[x+BLOCKWIDTH-1][y+BLOCKHEIGHT-1]==' ')
+							grid[x][y]=' ';
+					}
+			letterstep++;
+		}
+		else if (letterstep==11)
+		{
+			//B
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(12)); penguincount++; 
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(0),LYPOS(16)); penguincount++;
+
+			flock[penguincount]=createpenguinxy(LXPOS(1),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(2),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(1),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(2),LYPOS(13)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(1),LYPOS(16)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(2),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(3),LYPOS(12)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(3),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(3),LYPOS(15)); penguincount++;
+			
+			//R
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(5),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(6),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(7),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(6),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(7),LYPOS(13)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(8),LYPOS(12)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(8),LYPOS(14)); penguincount++;
+ 			flock[penguincount]=createpenguinxy(LXPOS(8),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(8),LYPOS(16)); penguincount++;
+			
+			//E
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(10),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(11),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(12),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(11),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(12),LYPOS(13)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(11),LYPOS(16)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(12),LYPOS(16)); penguincount++;
+			
+			//A
+			flock[penguincount]=createpenguinxy(LXPOS(14),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(14),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(14),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(14),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(14),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(17),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(17),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(17),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(17),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(17),LYPOS(16)); penguincount++;
+
+			flock[penguincount]=createpenguinxy(LXPOS(15),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(16),LYPOS(11)); penguincount++;
+
+			flock[penguincount]=createpenguinxy(LXPOS(15),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(16),LYPOS(13)); penguincount++;
+
+			//K
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(19),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(20),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(21),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(22),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(21),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(22),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(22),LYPOS(16)); penguincount++;
+
+			//E
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(24),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(25),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(26),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(25),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(26),LYPOS(13)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(25),LYPOS(16)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(26),LYPOS(16)); penguincount++;
+
+			//R
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(12)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(14)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(28),LYPOS(16)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(29),LYPOS(11)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(30),LYPOS(11)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(29),LYPOS(13)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(30),LYPOS(13)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(31),LYPOS(12)); penguincount++;
+			
+			flock[penguincount]=createpenguinxy(LXPOS(31),LYPOS(14)); penguincount++;
+ 			flock[penguincount]=createpenguinxy(LXPOS(31),LYPOS(15)); penguincount++;
+			flock[penguincount]=createpenguinxy(LXPOS(31),LYPOS(16)); penguincount++;
+
+			if (penguincount>=MAXPENGUINS) { fprintf(stderr,"Too many penguins!\n"); }
+
+			for (i=0;i<penguincount;i++)
+			{
+				savebehindpenguin(&flock[i]);
+				markgrid(flock[i].geom.x,flock[i].geom.y,BLOCKWIDTH,BLOCKHEIGHT,'*');	
+				drawpenguin(&flock[i]);
+				soil(flock[i].geom);
+			}
+			
+			
+			letterstep++;
+		}
+		else if (letterstep<300)
+		{
+			letterstep++;
+		}
+		else if (letterstep==300)
+		{
+			frozen=false;
+			for (i=0;i<penguincount;i++)
+			{
+				markgrid(flock[i].geom.x,flock[i].geom.y,BLOCKWIDTH,BLOCKHEIGHT,' ');
+				erasepenguin(&flock[i]);
+				soil(flock[i].geom);
+			}
+			letterstep++;
+			setcursor(CURSORCLICK);
+		}
+		else if (letterstep<400)
+		{
+			letterstep++;
+		}
+		else if (letterstep==400)
+		{
+			if (penguincount)
+			{
+				penguincount--;
+				markgrid(flock[penguincount].geom.x,flock[penguincount].geom.y,BLOCKWIDTH,BLOCKHEIGHT,' ');
+				erasepenguin(&flock[penguincount]);
+				soil(flock[penguincount].geom);
+			}
+			else
+			{
+				letterstep++;
+			}
+		}
+		else if (letterstep<800)
+		{
+			if (!line1.on && !line2.on)
+			{
+				x=LXPOS(random() % 32);
+				y=LYPOS(random() % 20);
+				if (random()%2)
+				{
+					startline(&line1,UP,x,y);
+					startline(&line2,DOWN,x,y);
+				}
+				else
+				{
+					startline(&line1,LEFT,x,y);
+					startline(&line2,RIGHT,x,y);
+				}
+
+			}			
+		}
+		//else if (letterstep<2000)
+		//{
+		//	letterstep++;
+		//}
+		//else
+		//{
+		//	done=true;
+		//}
+
+		// high score stuff
+		// FIX: it'd be *much* more efficient to draw the text to
+		// surfaces and then scroll the surfaces, since the text-draw
+		// routine is so slow.
+		
+		if (letterstep>0) // that's a bit kludgy...
+		{
+			SDL_FillRect(screen,&bigrect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+
+			// 1
+			snprintf(scoretext,40,"#%d. %s: %ld",hiscoreindex+1,hiscorename[hiscoreindex],hiscoreval[hiscoreindex]);
+			puttext(scrollrect.x-hiscorescroll,scrollrect.y,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF), scoretext);
+	
+			// 2			
+			snprintf(scoretext,40,"#%d. %s: %ld",((hiscoreindex+1)%HISCORENUM)+1,hiscorename[(hiscoreindex+1)%HISCORENUM],hiscoreval[(hiscoreindex+1)%HISCORENUM]);
+			puttext(scrollrect.x-hiscorescroll+250,scrollrect.y,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF), scoretext);
+						
+			// 3!
+			snprintf(scoretext,40,"#%d. %s: %ld",((hiscoreindex+2)%HISCORENUM)+1,hiscorename[(hiscoreindex+2)%HISCORENUM],hiscoreval[(hiscoreindex+2)%HISCORENUM]);
+			puttext(scrollrect.x-hiscorescroll+500,scrollrect.y,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF), scoretext);
+				
+			// blank left margin
+			SDL_FillRect(screen,&leftmarginrect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+
+
+			// label
+			SDL_FillRect(screen,&labelrect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+			puttext(labelrect.x,labelrect.y,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),"HIGH SCORES:");	
+				
+			// blank right margin
+			SDL_FillRect(screen,&rightmarginrect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+
+			soil(bigrect);
+	
+			if (hiscorestep) hiscorescroll++;
+			hiscorestep=!hiscorestep;
+			if (hiscorescroll>=250)
+			{
+				hiscorescroll=0;
+				hiscoreindex=(hiscoreindex+1)%HISCORENUM;
+			}
+		}	
+		
+		
+		// move split-lines
+		if (line1.on) 
+		{
+			if (moveline(&line1))
+			{
+				linedone1=true;
+			}
+			if (line1.dead) // need a second check because moveline could change this
+			{
+				//no sound in intro?
+				//playsound(SNDBREAK);
+				killline(&line1);
+				linedone1=false;
+			}
+		}
+		if (line2.on)
+		{
+		
+			if (moveline(&line2))
+			{
+				linedone2=true;
+				
+			}
+			if (line2.dead)
+			{ 
+				// no sound in intro?
+				//playsound(SNDBREAK);
+				killline(&line2);
+				linedone2=false;
+			}
+		}
+		if (linedone1 && linedone2) { letterstep++; linedone1=false; linedone2=false; }
+		
+	
+		// move (and get old background)
+		
+		if (!frozen)
+		{
+			for (i=0;i<penguincount;i+=2)
+			{
+				soil(flock[i].geom); // mark the penguin's old position as dirty
+				movepenguin(&flock[i]);
+				soil(flock[i].geom); // mark the penguin's new position as dirty too (it will be soon...)
+				savebehindpenguin(&flock[i]);
+			}
+		}
+		soil(tux.geom); // mark the penguin's old position as dirty
+		movepenguin(&tux);
+		soil(tux.geom); // mark the penguin's new position as dirty too (it will be soon...)
+		savebehindpenguin(&tux);
+		
+		// actually draw
+		if (!frozen)
+		{
+			for (i=0;i<penguincount;i+=2)
+			{
+				drawpenguin(&flock[i]);
+			}
+		}
+		drawpenguin(&tux);
+		
+		// update screen
+		clean();
+
+		// clear for next update
+		if (!frozen)
+		{
+			for (i=0;i<penguincount;i+=2)
+			{
+				erasepenguin(&flock[i]);
+			}
+		}
+		erasepenguin(&tux);
+		
+		SDL_Delay(10);
+		
+	} while (!done);
+
+	clean();
+	return(false);
+}
+
diff --git a/intro.h b/intro.h
new file mode 100644
index 0000000..508275c
--- /dev/null
+++ b/intro.h
@@ -0,0 +1,23 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern int intro(void);
+
diff --git a/laundry.c b/laundry.c
new file mode 100644
index 0000000..3bcca43
--- /dev/null
+++ b/laundry.c
@@ -0,0 +1,59 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+#include <SDL.h>
+#include <stdlib.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "laundry.h"
+
+static SDL_Rect laundrylist[MAXDIRTY];
+static int laundrycount;
+
+void initlaundry()
+{
+	laundrycount=0;
+}
+
+
+void soil(SDL_Rect r)
+{ // makes stuff dirty, of course.
+	if (laundrycount<MAXDIRTY) // it's good to have this check here, but
+	{                          // since this is the most-used function in
+	                           // the whole program, it might be worth removing
+	                           // for production builds...
+		laundrylist[laundrycount] = r;
+		laundrycount++;
+	}
+	else
+	{
+		fprintf(stderr, "Too much dirty laundry!\n");
+		exit(1);
+	}
+}
+
+void clean()
+{
+	SDL_UpdateRects(screen, laundrycount, laundrylist);
+	//SDL_UpdateRect(screen,0,0,0,0);
+	laundrycount=0;
+	
+}
diff --git a/laundry.h b/laundry.h
new file mode 100644
index 0000000..11aa938
--- /dev/null
+++ b/laundry.h
@@ -0,0 +1,27 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern void soil(SDL_Rect r);
+extern void clean(void);
+extern void initlaundry(void);
+
+#define MAXDIRTY 2000
+
diff --git a/level.c b/level.c
new file mode 100644
index 0000000..873ba91
--- /dev/null
+++ b/level.c
@@ -0,0 +1,512 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "icebreaker.h"
+#include "cursor.h"
+#include "penguin.h"
+#include "line.h"
+#include "grid.h"
+#include "laundry.h"
+#include "sound.h"
+#include "globals.h"
+#include "level.h"
+#include "status.h"
+#include "text.h"
+#include "dialog.h"
+#include "options.h"
+
+Line line1;
+Line line2;
+
+static void setuplevel(void);
+
+void setuplevel()
+{
+	int x,y;
+	int c;
+	SDL_Rect tmprect;
+
+	setcursor(CURSORARROW);
+	SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+	
+	tmprect.x=BORDERLEFT; tmprect.y=BORDERTOP;
+	tmprect.w=PLAYWIDTH; tmprect.h=PLAYHEIGHT;
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0));
+
+	//tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
+	//for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
+	//	for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
+	//		SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
+
+	tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
+	for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
+		for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
+			{
+				c = (random() % 32)+224;
+				SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, c, c, c));
+			}
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+
+
+	
+	SDL_UpdateRect(screen,0,0,0,0);
+
+	for (x=0;x<WIDTH;x++)
+		for (y=0;y<HEIGHT;y++)
+		{
+			if (x<BORDERLEFT || x>=BORDERRIGHT || y <BORDERTOP || y>=BORDERBOTTOM) 	
+				grid[x][y]='X';
+			else
+				grid[x][y]=' ';
+		}
+	
+
+}
+
+
+
+LevelExitType playlevel(int level, long oldscore, ScoreSheet * levelscore)
+{
+	int penguincount=level+1;
+	int lives=level+1;
+
+	LevelExitType returncode=ERROR;
+	int i,x,y,xdif,ydif;
+
+	SDL_Rect menubuttonrect;
+	int menubuttonglow=false;
+	int menubuttonpressed=false;
+	int paused=false;
+
+	int clear=0;
+	int linedoneflag=false;
+	LineType linetype;
+	float scoremod=1;
+	float bonusmod=1;
+	
+	int tick=0;
+	int timepenalty=0;
+	int timepenaltyinterval=0;
+	
+	int domenuflag = false;
+	
+	int done = false;
+	
+	// FIX -- this is a good candidate for dynamic memory allocation...
+	//Penguin flock[penguincount];
+	Penguin flock[MAXPENGUINS];
+	
+	SDL_Event event;
+
+	switch(options.difficulty)
+	{
+		case NORMAL:
+			scoremod=(level+1)/2.0;
+			bonusmod=(level+1)/2.0;
+			timepenaltyinterval=100;
+		break;
+		case EASY:
+			scoremod=(level+1)/5.0;
+			bonusmod=(level+1)/7.0;
+			timepenaltyinterval=200;
+		break;
+		case HARD:
+			scoremod=(level+1)/1.75;
+			bonusmod=(level+1)/1.5;
+			timepenaltyinterval=75;
+		break;
+		default:
+			fprintf(stderr,"Unknown difficulty -- that can't happen!\n");
+		break;
+	}
+
+	levelscore->basescore=0;
+	levelscore->clearbonus=0;
+	levelscore->lifebonus=0;
+	
+	setuplevel();
+	
+	setcursor(CURSORVERTICAL); linetype=VERTICAL; 
+
+/*	printf("===========================================================\n"
+	       "Starting level %d.\n"
+	       "Lives: %d\n",
+	       level,lives);
+*/	       
+
+	menubuttonrect.x=WIDTH-(CHARWIDTH*2*4)-MARGINRIGHT-4;
+	menubuttonrect.y=BOTTOMSTATUSY;
+	menubuttonrect.w=CHARWIDTH*2*4+3;
+	menubuttonrect.h=CHARHEIGHT*2+3;
+	puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
+	soil(menubuttonrect);	
+
+	line1=createline('1',0x00, 0x00, 0x00);
+	//line1=createline('1',0x00, 0x40, 0x80);
+	line2=createline('2',0xC0, 0x00, 0x40);
+
+	for (i=0;i<penguincount;i++)
+	{
+		flock[i] = createpenguin();
+	}
+
+	updatestatuslives(lives);
+	updatestatuscleared(clear);
+	updatestatusscore(oldscore);
+	
+	updatehiscorebox();	
+	clean();
+	
+	do 
+	{
+		// FIX -- this is way too messy. time to split it up into
+		// neat little functions or something. Especially the menubutton stuff.
+		while (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_QUIT)
+			{
+				lives=0; // is this the right way?
+				done = true;
+				return QUIT;
+			}
+			else if (event.type == SDL_MOUSEMOTION)
+			{
+				//if (grid[event.motion.x][event.motion.y] == ' ' || grid[event.motion.x][event.motion.y] == '*')
+				if (event.motion.x>BORDERLEFT && event.motion.x<BORDERRIGHT && event.motion.y>BORDERTOP && event.motion.y<BORDERBOTTOM)	
+				{
+					switch (linetype)
+					{
+						case HORIZONTAL:
+							setcursor(CURSORHORIZONTAL);
+						break;
+						case VERTICAL:
+							setcursor(CURSORVERTICAL);
+						break;
+					}
+					
+				}			
+				else  // we're somewhere outside of the playing area
+				{
+					setcursor(CURSORARROW);
+				}
+				
+				if (event.motion.x>=menubuttonrect.x && event.motion.y>=menubuttonrect.y && event.motion.x<menubuttonrect.x+menubuttonrect.w && event.motion.y<menubuttonrect.y+menubuttonrect.h)
+				{ // over the menu button
+					if (!menubuttonglow)
+					{
+						menubuttonglow=true;
+						SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0xF0, 0xF0, 0xF0));
+						puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),"MENU");
+					}
+
+				}
+				else 
+				{
+					if (menubuttonglow && !menubuttonpressed)
+					{
+						menubuttonglow=false;
+						SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+						puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
+					}
+				
+				}
+				soil(menubuttonrect);	
+			}
+			else if (event.type == SDL_MOUSEBUTTONDOWN)
+			{
+				if (event.button.button==1) //left
+				{
+					// in game area?
+					if (event.button.x>BORDERLEFT && event.button.x<BORDERRIGHT && event.button.y>BORDERTOP && event.button.y<BORDERBOTTOM)
+					{
+						x=(((event.button.x-BORDERLEFT)/BLOCKWIDTH ) * BLOCKWIDTH ) +BORDERLEFT;
+				  		y=(((event.button.y-BORDERTOP)/BLOCKHEIGHT) * BLOCKHEIGHT) +BORDERTOP;
+			  			xdif=event.button.x-x; ydif=event.button.y-y;
+
+  						if (grid[x][y] == '*' || grid[event.button.x][event.button.y] == '*') 
+						{ // a little bit of grace if the player clicks directly on the penguin
+							playsound(SNDOUCH);
+						}
+						else if (grid[x][y] == ' ')
+						{
+
+							switch (linetype)
+							{
+								case VERTICAL:
+									if (!line1.on) (ydif<BLOCKHEIGHT/2) ? startline(&line1,UP,x,y) : startline(&line1,UP,x,y+BLOCKHEIGHT);
+									if (!line2.on) (ydif<BLOCKHEIGHT/2) ? startline(&line2,DOWN,x,y) : startline(&line2,DOWN,x,y+BLOCKHEIGHT);
+								break;
+								case HORIZONTAL:
+									if (!line1.on) (xdif<BLOCKWIDTH/2) ? startline(&line1,LEFT,x,y) : startline(&line1,LEFT,x+BLOCKWIDTH,y);
+									if (!line2.on) (xdif<BLOCKWIDTH/2) ? startline(&line2,RIGHT,x,y) : startline(&line2,RIGHT,x+BLOCKWIDTH,y);
+								break;
+							}
+						
+  						}
+					}
+					else if (event.button.x>=menubuttonrect.x && event.button.y>=menubuttonrect.y && event.button.x<menubuttonrect.x+menubuttonrect.w && event.button.y<menubuttonrect.y+menubuttonrect.h)
+					{
+						menubuttonpressed=true;
+					}
+					         
+				}
+				//else if (event.button.button==3) // for testing!
+				//{
+				//	printwholegrid();  				
+  				//}
+  				else //middle or right
+  				{
+  					switch (linetype)
+					{
+						case VERTICAL:
+							linetype=HORIZONTAL;
+							setcursor(CURSORHORIZONTAL); 
+						break;
+						case HORIZONTAL:
+							linetype=VERTICAL;
+							setcursor(CURSORVERTICAL);
+						break;
+					}
+				}
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				if (menubuttonpressed && event.button.x>=menubuttonrect.x && event.button.y>=menubuttonrect.y && event.button.x<menubuttonrect.x+menubuttonrect.w && event.button.y<menubuttonrect.y+menubuttonrect.h)
+				{
+					menubuttonglow=true;
+					
+					SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0xF0, 0xF0, 0xF0));
+					puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),"MENU");
+					soil(menubuttonrect);
+
+					domenuflag=true;
+				}
+				else if (menubuttonglow && menubuttonpressed)
+				{
+					menubuttonglow=false;
+					SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
+					puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
+					soil(menubuttonrect);	
+				}
+				menubuttonpressed=false;
+			}
+			else if (event.type == SDL_ACTIVEEVENT && ((options.autopause == AUTOPAUSEON) || (event.active.state & SDL_APPACTIVE)))
+			{   
+				if (event.active.gain==0)
+				{ // iconified / lost focus
+					paused=true;
+				}
+				else // event.active.gain==1
+				{ // restored /got focus
+					paused=false;
+				}
+			}
+			// FIX -- add keyboard support, handle other events.
+		}
+		if (paused) 
+		{
+			SDL_WaitEvent(NULL);
+			continue;
+		}
+		
+		
+		
+		// move split-lines
+		if (line1.on)
+		{
+			// kludgy crap to implement speed = 1 1/2
+			linedoneflag=moveline(&line1);
+			if (!linedoneflag && line1.speedslower)
+			{
+				line1.speedslower=false;
+				linedoneflag=moveline(&line1);
+			}
+			else
+			{
+				line1.speedslower=true;
+			}
+				
+			if (linedoneflag)
+			{
+				clear=(100-(countcleared()*100/(PLAYWIDTH*PLAYHEIGHT)));
+				levelscore->basescore=(int)(clear*scoremod)-timepenalty;
+				tick=0; // reset this to keep score from seeming to flicker around a lot. and to be nice. :)
+				
+				updatestatuscleared(clear);
+				updatestatusscore(oldscore+levelscore->basescore);
+				//printf("Cleared: %d%%\n",clear);				
+			}
+
+			if (line1.dead) 
+			{
+				playsound(SNDBREAK);
+				killline(&line1);
+				lives--;
+				if (lives<0) lives=0;
+				updatestatuslives(lives);
+				//printf("Lives: %d\n",lives); 
+			}
+		}
+		if (line2.on)
+		{
+			linedoneflag=moveline(&line2);
+			if (!linedoneflag && line2.speedslower)
+			{
+				line2.speedslower=false;
+				linedoneflag=moveline(&line2);
+			}
+			else
+			{
+				line2.speedslower=true;
+			}
+
+			if (linedoneflag)
+			{
+				clear=(100-(countcleared()*100/(PLAYWIDTH*PLAYHEIGHT)));
+				levelscore->basescore=(int)(clear*scoremod)-timepenalty;
+				tick=0; // reset this to keep score from seeming to flicker around a lot. and to be nice. :)
+
+				updatestatuscleared(clear);
+				updatestatusscore(oldscore+levelscore->basescore);
+				//printf("Cleared: %d%%\n",clear);
+			}
+
+			if (line2.dead)
+			{ 
+				playsound(SNDBREAK);
+				killline(&line2);
+				lives--;
+				if (lives<0) lives=0;
+				updatestatuslives(lives);
+				//printf("Lives: %d\n",lives);
+				
+			}
+		}
+		
+	
+		// move (and get old background)
+		for (i=0;i<penguincount;i++)
+		{
+			
+			soil(flock[i].geom); // mark the penguin's old position as dirty
+			movepenguin(&flock[i]);
+		
+			soil(flock[i].geom); // mark the penguin's new position as dirty too (it will be soon...)
+			savebehindpenguin(&flock[i]);
+		}
+		
+
+		// actually draw
+		for (i=0;i<penguincount;i++)
+		{
+			drawpenguin(&flock[i]);
+		}
+
+		if (domenuflag)
+		{
+			switch (popupmenu())
+			{
+				case POPUPMENUQUITGAME:
+					lives=0; // is this the right way?
+					done = true;
+					return QUIT;
+				break;
+				case POPUPMENUNEWGAME:
+					// hmmm... maybe this could be done better
+					done = true;
+					returncode=DEAD;
+				break;
+			}
+			
+			domenuflag=false;
+		}
+
+		
+		// update clock
+		tick++;
+		if (tick>timepenaltyinterval)
+		{
+			tick=0;
+			if (levelscore->basescore>0)
+			{
+				timepenalty++;
+				levelscore->basescore--;
+				updatestatusscore(oldscore+levelscore->basescore);
+			}
+		}
+		
+		// update screen
+		clean();
+
+		// clear for next update
+		for (i=0;i<penguincount;i++)
+		{
+			erasepenguin(&flock[i]);
+		}
+		
+		if (lives<=0) // game over
+		{
+			done = true;
+			returncode=DEAD;
+		} 
+		else if (!line1.on && !line2.on && clear>=PERCENTREQUIRED) // success!
+		{ 
+			done = true;
+			levelscore->basescore=(int)(clear*scoremod)-timepenalty;
+			returncode=PASS;
+
+
+			levelscore->clearbonus=0;
+			// bonuses for clearing lots
+			if (clear>PERCENTBONUS)
+				levelscore->clearbonus+=(int)((clear-PERCENTBONUS)*bonusmod);
+			if (clear>PERCENTEXTRABONUS)
+				levelscore->clearbonus+=(int)((clear-PERCENTEXTRABONUS)*(clear-PERCENTEXTRABONUS)*bonusmod);
+				
+			// bonuses for leftover lives
+			levelscore->lifebonus=(int)((lives-1)*3*bonusmod);
+		} 
+
+		//printboard();
+		
+		// oh, if only we could sleep for less than 10ms on 
+		// intel. too bad alpha systems suck so much in other
+		// ways -- they can sleep with 1ms resolution.
+		// (we could on intel with nanosleep, if we were suid root...)
+		SDL_Delay(10);
+		
+	} while (!done);
+
+
+	// make sure visible penguins are actually in the screen memory.
+	for (i=0;i<penguincount;i++)
+	{
+		drawpenguin(&flock[i]);
+	}
+
+	clean();
+	return returncode;
+}
+
diff --git a/level.h b/level.h
new file mode 100644
index 0000000..4aa3aea
--- /dev/null
+++ b/level.h
@@ -0,0 +1,37 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+typedef enum { ERROR, PASS, DEAD, QUIT } LevelExitType;
+
+typedef struct
+{
+	int basescore;
+	int clearbonus;
+	int lifebonus;
+} ScoreSheet;
+
+
+extern LevelExitType playlevel(int level, long oldscore, ScoreSheet * score);
+
+
+extern Line line1;
+extern Line line2;
+
diff --git a/line.c b/line.c
new file mode 100644
index 0000000..2a42304
--- /dev/null
+++ b/line.c
@@ -0,0 +1,291 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+#include <SDL.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "line.h"
+#include "laundry.h"
+#include "grid.h"
+
+Line createline(char i, Uint8 r, Uint8 g, Uint8 b)
+{
+	Line l;
+
+	
+	l.id=i;
+	l.on=false;
+	l.color=SDL_MapRGB(screen->format,  r, g, b);
+	l.dir=UP;
+	l.geom.x=0;
+	l.geom.y=0;
+	l.geom.w=BLOCKWIDTH;
+	l.geom.h=BLOCKHEIGHT;
+	l.mark=l.geom;
+	l.dead=false;
+	l.speedslower=false;
+	l.stuckcount=0;
+	return(l);
+}
+
+void startline(Line * l, LineDir d, int x, int y)
+{
+	l->on=true;
+	l->dir=d;
+	l->stuckcount=0;
+
+	switch (d)
+	{
+		case UP: 
+			l->geom.w=BLOCKWIDTH;
+			l->geom.h=1;
+			l->geom.x=x;
+			l->geom.y=y-1; 
+		break;
+		case DOWN:
+			l->geom.w=BLOCKWIDTH;
+			l->geom.h=1;
+			l->geom.x=x;
+			l->geom.y=y; 
+		break;
+		case LEFT: 
+			l->geom.w=1;
+			l->geom.h=BLOCKHEIGHT;
+			l->geom.x=x-1;
+			l->geom.y=y;			
+		break;
+		case RIGHT:
+			l->geom.w=1;
+			l->geom.h=BLOCKHEIGHT;
+			l->geom.x=x;
+			l->geom.y=y;
+		break;
+	}
+	l->mark=l->geom;
+}
+
+
+int moveline(Line * l)
+{
+	int finish=false;
+	char check1;
+	char check2;
+
+	markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
+	SDL_FillRect(screen,&(l->mark),l->color);
+	soil(l->mark);
+
+	switch (l->dir)
+	{
+		case UP:
+			check1=grid[l->geom.x][l->geom.y-1];
+			check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y-1];
+		break;
+		case DOWN:
+			check1=grid[l->geom.x][l->geom.y+l->geom.h];
+			check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y+l->geom.h];
+		break;
+		case LEFT:
+			check1=grid[l->geom.x-1][l->geom.y];
+			check2=grid[l->geom.x-1][l->geom.y+BLOCKHEIGHT-1];
+		break;
+		case RIGHT:
+			check1=grid[l->geom.x+l->geom.w][l->geom.y];
+			check2=grid[l->geom.x+l->geom.w][l->geom.y+BLOCKHEIGHT-1];
+		break;
+		default: // this will never happen. really.
+			fprintf(stderr,"Line has no direction. That shouldn't have happened.\n");
+			check1='!';
+			check2='!';
+		break;
+	}
+	
+
+	if (check1 == ' ' && check2 == ' ')
+	{ // next space is empty
+		switch (l->dir)
+		{
+			case UP:
+				l->geom.y--;
+				l->geom.h++;
+				l->mark.y--;
+				l->mark.h=1;
+			break;
+			case DOWN:
+				l->geom.h++; // increase length of line -- top stays same 
+				l->mark.y+=l->mark.h;
+				l->mark.h=1;
+			break;
+			case LEFT:
+				l->geom.x--;
+				l->geom.w++;
+				l->mark.x--;
+				l->mark.w=1;
+			break;
+			case RIGHT:
+				l->geom.w++; // increase width of line -- left side stays same 
+				l->mark.x+=l->mark.w;
+				l->mark.w=1;
+			break;
+		}
+	}
+	else if (check1 == '*' || check2 == '*')
+	{ // hit a penguin. kills line.
+		l->dead=true;
+	}
+	else if (check1 == '1' || check2 == '1' || check1 == '2' || check2 == '2')
+	{
+		if (l->stuckcount>LINEMAXSTUCK)
+		{
+			finish=true;
+		}
+		else
+		{
+			l->stuckcount++;
+			
+			// FIX: kludge-o-rama!!
+			// this could work around the irratating thing where
+			// a line gets started 'on top' of another line. but it
+			// is totally repairing the symptom, not the bug. *sigh*
+			//if (l->geom.w==1 || l->geom.h==1) finish=true;
+		}
+	}
+	else
+	{ // hit something else
+		finish=true;
+	}
+	
+	if (finish)
+	{
+		markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
+		SDL_FillRect(screen,&(l->mark),l->color);
+		soil(l->mark);
+		finishline(l);
+		return(1);
+	}
+	
+	return(0);
+}
+
+void finishline(Line * l)
+{
+	int i;
+	int quick1=false;
+	int quick2=false;
+	
+	l->on=false;	
+	
+	//printwholegrid();
+	
+	switch (l->dir)
+  	{
+  		case DOWN:
+  		// falls through.
+  		case UP:
+  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'|');
+  			SDL_FillRect(screen,&l->geom,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+  			soil(l->geom);		
+  				
+  			// scan along edges to quickly determine if this
+  			// is going to be complicated.
+  			quick1=true; quick2=true;
+  			for (i=l->geom.y+BLOCKHEIGHT/2;i<l->geom.y+l->geom.h;i++)
+  			{
+  				if (grid[l->geom.x-1][i] != ' ' && grid[l->geom.x-1][i] != '*') quick1=false;
+  				if (grid[l->geom.x+BLOCKWIDTH][i] != ' ' && grid[l->geom.x+BLOCKWIDTH][i] != '*') quick2=false;
+  			}
+  				
+  			//printf("Quick %d %d\n",quick1,quick2);
+  				
+  			checkempty(l->geom.x-BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT/2);
+  			checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2/2,l->geom.y+BLOCKHEIGHT/2);
+  		
+  			if (!quick1)
+  				for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
+  					checkempty(l->geom.x-BLOCKWIDTH/2,i);
+  			if (!quick2)
+  				for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
+  					checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2,i);
+  		break;
+  		case RIGHT:
+  		// falls through
+  		case LEFT:
+  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'-');
+  			SDL_FillRect(screen,&l->geom,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+  			soil(l->geom);		
+	
+  			// scan along edges to quickly determine if this
+  			// is going to be complicated.
+  			quick1=true; quick2=true;
+  			for (i=l->geom.x+BLOCKWIDTH/2;i<l->geom.x+l->geom.w;i++)
+  			{
+  				if (grid[i][l->geom.y-1] != ' ' && grid[i][l->geom.y-1] != '*') quick1=false;
+  				if (grid[i][l->geom.y+BLOCKHEIGHT] != ' ' && grid[i][l->geom.y+BLOCKHEIGHT] != '*') quick2=false;
+  			}
+  				
+  			//printf("Quick %d %d\n",quick1,quick2);
+	  			
+	  		checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y-BLOCKHEIGHT/2);
+	  		checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
+	  			
+	  		if (!quick1)
+	  			for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
+		  			checkempty(i,l->geom.y-BLOCKHEIGHT/2);
+	  			
+	  		if (!quick2)
+	  			for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
+		  			checkempty(i,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
+	  		
+		break;
+	}
+	
+}
+
+
+void killline(Line * l)
+{
+		
+	l->on=false;
+	l->dead=false;
+	
+	// FIX:  Make bang noise here?
+	
+	switch (l->dir)
+  	{
+  		case DOWN:
+		// falls through.
+  		case UP:
+  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
+  			//SDL_FillRect(screen,&l->geom,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF));
+  			SDL_BlitSurface(screensave,&l->geom, screen, &l->geom);
+  			soil(l->geom);		
+  		break;
+  		case RIGHT:
+  		// falls through
+  		case LEFT:
+  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
+  			//SDL_FillRect(screen,&l->geom,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF));
+  			SDL_BlitSurface(screensave,&l->geom, screen, &l->geom);
+  			soil(l->geom);		
+	  	break;
+	}
+}
diff --git a/line.h b/line.h
new file mode 100644
index 0000000..1d40f00
--- /dev/null
+++ b/line.h
@@ -0,0 +1,44 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+typedef enum { UP, DOWN, LEFT, RIGHT } LineDir;	
+typedef enum { HORIZONTAL, VERTICAL } LineType;
+
+typedef struct
+{
+	int on;
+	SDL_Rect geom;
+	SDL_Rect mark;
+	LineDir dir;
+	Uint32 color;
+	char id;
+	int dead;
+	int speedslower;
+	int stuckcount;
+} Line;
+
+
+extern Line createline(char i, Uint8 r, Uint8 g, Uint8 b);
+extern void startline(Line * l, LineDir d, int x, int y);
+extern int moveline(Line * l);
+extern void finishline(Line * l);
+extern void killline(Line * l);
+
diff --git a/options.c b/options.c
new file mode 100644
index 0000000..89f931c
--- /dev/null
+++ b/options.c
@@ -0,0 +1,173 @@
+/*
+* IceBreaker
+* Copyright (c) 2001 Matthew Miller <mattdm at mattdm.org> and
+*   Enrico Tassi <f.tassi at mo.nettuno.it>
+*
+* <http://www.mattdm.org/icebreaker/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "icebreaker.h"
+#include "options.h"
+
+GameOptionsType options;
+
+
+void setdefaultoptions(void)
+{
+        options.sound=SOUNDON;
+	options.autopause=AUTOPAUSEOFF;	
+        options.difficulty=NORMAL;
+        options.fullscreen=FULLSCREENOFF;
+        strncpy(options.theme,"linux",MAXTHEMELENGTH);
+}
+
+
+int readoptions(void)
+{
+	FILE * optionfile;
+	char linebuf[50];
+	char filename[255];
+	char optbuf[20];
+	char valbuf[10];
+	int i;
+
+	setdefaultoptions();
+	
+	snprintf(filename,255,"%s/%s",homedir,OPTIONFILE);
+	
+	optionfile=fopen(filename,"r");
+	if (optionfile==NULL)
+	{
+		fprintf(stderr, OPTIONFILE " doesn't exist.\nWelcome to IceBreaker.\n");
+		return true;
+	}
+	
+	while(fgets(linebuf,50,optionfile))
+	{
+		for (i=0;i<50;i++)
+		{
+			if (linebuf[i]=='\0') break;
+			linebuf[i]=tolower(linebuf[i]);
+		}
+			
+		if (sscanf(linebuf,"%20s %10s",optbuf,valbuf)==2)
+		{
+			if (!strcmp(optbuf,"sound"))
+			{
+				if (!strcmp(valbuf,"on"))
+					options.sound=SOUNDON;
+				else if (!strcmp(valbuf,"off"))
+					options.sound=SOUNDOFF;
+			}
+			else if (!strcmp(optbuf,"autopause"))
+			{
+				if (!strcmp(valbuf,"on"))
+					options.autopause=AUTOPAUSEON;
+				else if (!strcmp(valbuf,"off"))
+					options.autopause=AUTOPAUSEOFF;
+			}
+			else if (!strcmp(optbuf,"fullscreen"))
+			{
+				if (!strcmp(valbuf,"off"))
+					options.fullscreen=FULLSCREENOFF;
+				else if (!strcmp(valbuf,"on"))
+					options.fullscreen=FULLSCREENON;
+				else if (!strcmp(valbuf,"always"))
+					options.fullscreen=FULLSCREENALWAYS;
+			}
+			else if (!strcmp(optbuf,"difficulty"))
+			{
+				if (!strcmp(valbuf,"normal"))
+					options.difficulty=NORMAL;
+				else if (!strcmp(valbuf,"hard"))
+					options.difficulty=HARD;
+				else if (!strcmp(valbuf,"easy"))
+					options.difficulty=EASY;
+			}
+			// FIX: add username
+		}
+	}
+	
+	fclose(optionfile);
+
+	return false;
+}
+
+int writeoptions(void)
+{
+	FILE * optionfile;
+	char filename[255];
+	snprintf(filename,255,"%s/%s",homedir,OPTIONFILE);
+	
+	optionfile=fopen(filename,"w");
+	if (optionfile==NULL)
+	{
+		fprintf(stderr, "Can't write to " OPTIONFILE ".\n");
+		return true;
+	}
+	
+	fprintf(optionfile,"# Icebreaker config file 1.0\n#\n");
+	fprintf(optionfile,"# Separate keywords from values by whitespace. Not case sensitive.\n#\n");
+	fprintf(optionfile,"# %s/" OPTIONFILE " will be overwritten automatically.\n#\n",homedir);
+	
+	fprintf(optionfile,"\n# Change this if the crashing noise annoys your neighbors.\n");
+	if (options.sound==SOUNDON)
+		fprintf(optionfile,"Sound On\n");
+	else if (options.sound==SOUNDOFF)
+		fprintf(optionfile,"Sound Off\n");
+		
+	fprintf(optionfile,"\n# AutoPause makes the game pause when the window is out of focus.\n");
+	if (options.autopause==AUTOPAUSEON)
+		fprintf(optionfile,"AutoPause On\n");
+	else if (options.autopause==AUTOPAUSEOFF)
+		fprintf(optionfile,"AutoPause Off\n");
+
+	fprintf(optionfile,"\n# Set FullScreen to Always if you want it that way every time.\n");
+	fprintf(optionfile,"# On will use full screen mode once, but then change back to Off.\n");
+#ifdef HIDEFULLSCREEN // FIX -- put back fullscreen
+	fprintf(optionfile,"# This is experimental here, so you have to change it here -- there's nothing\n");
+	fprintf(optionfile,"# on the options menu. A future version will have complete fullscreen support.\n");
+#endif
+	if (options.fullscreen==FULLSCREENOFF || options.fullscreen==FULLSCREENON)
+		fprintf(optionfile,"FullScreen Off\n");
+	else if (options.fullscreen==FULLSCREENALWAYS)
+		fprintf(optionfile,"FullScreen Always\n");
+
+	fprintf(optionfile,"\n# Normal is the best way to play. Easy is okay to get started,\n");
+	fprintf(optionfile,"# but you won't get very high scores. Hard is for those who really\n");
+	fprintf(optionfile,"# want a challenge, but scores only slightly higher than normal.\n");
+	
+
+	if (options.difficulty==NORMAL)
+		fprintf(optionfile,"Difficulty Normal\n");
+	else if (options.difficulty==HARD)
+		fprintf(optionfile,"Difficulty Hard\n");
+	else if (options.difficulty==EASY)
+		fprintf(optionfile,"Difficulty Easy\n");
+
+	
+	fclose(optionfile);
+	
+	return false;
+}
diff --git a/options.h b/options.h
new file mode 100644
index 0000000..054a813
--- /dev/null
+++ b/options.h
@@ -0,0 +1,46 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> and
+*   Enrico Tassi <f.tassi at mo.nettuno.it>
+*
+* <http://www.mattdm.org/icebreaker/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+typedef enum { SOUNDON,SOUNDOFF } SoundSettingType;
+typedef enum { AUTOPAUSEON,AUTOPAUSEOFF } AutoPauseType;
+typedef enum { NORMAL, EASY, HARD } GameDifficultyType;
+typedef enum { FULLSCREENOFF, FULLSCREENON, FULLSCREENALWAYS } FullscreenSettingType;
+
+#define MAXTHEMELENGTH 10
+
+typedef struct
+{
+	SoundSettingType sound;
+	AutoPauseType autopause;
+	GameDifficultyType difficulty;
+	FullscreenSettingType fullscreen;
+        char theme[MAXTHEMELENGTH];
+} GameOptionsType;
+
+extern GameOptionsType options;
+
+void setdefaultoptions(void);
+extern int readoptions(void);
+extern int writeoptions(void);
+
diff --git a/ouch.wav b/ouch.wav
new file mode 100644
index 0000000..79f6cf5
Binary files /dev/null and b/ouch.wav differ
diff --git a/penguin.bmp b/penguin.bmp
new file mode 100644
index 0000000..cb903f7
Binary files /dev/null and b/penguin.bmp differ
diff --git a/penguin.c b/penguin.c
new file mode 100644
index 0000000..97af9f5
--- /dev/null
+++ b/penguin.c
@@ -0,0 +1,204 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <stdlib.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "penguin.h"
+#include "grid.h"
+#include "line.h"
+#include "level.h"
+#include "options.h" 
+
+Penguin createpenguin()
+{
+	return(createpenguinxy(BORDERLEFT + (random() % (PLAYWIDTH-BLOCKWIDTH)),BORDERTOP + (random() % (PLAYHEIGHT-BLOCKWIDTH))));
+}
+
+Penguin createpenguinxy(int x, int y)
+{
+	Penguin p;
+	//double h;
+	p.image = penguinimage;
+	
+	
+	/*
+	h = ((random()/(double)RAND_MAX)*3.1415926536*2);
+	
+	p.xdelta= (int)rint(cos(h) * PENGUINSPEED);
+	p.ydelta= (int)rint(sin(h) * PENGUINSPEED);
+	if (p.xdelta==0) // no straight lines. too easy!
+	{
+		if (random()%2) { p.xdelta=-1; } else { p.xdelta=1; }
+	}
+	if (p.ydelta==0)
+	{
+		if (random()%2) { p.ydelta=-1; } else { p.ydelta=1; }
+	}
+	*/
+	
+	// FIX -- PENGUINSPEED should be variable, not a define. (set in preferences, of course) 
+	switch (random() % 4)
+	{
+		case 0:
+			p.xdelta= PENGUINSPEED;p.ydelta= PENGUINSPEED;
+		break;
+		case 1:
+			p.xdelta= PENGUINSPEED;p.ydelta=-PENGUINSPEED;
+		break;
+		case 2:
+			p.xdelta=-PENGUINSPEED;p.ydelta= PENGUINSPEED;
+		break;
+		case 3:
+			p.xdelta=-PENGUINSPEED;p.ydelta=-PENGUINSPEED;
+		break;
+	}
+	
+	// For debugging only, of course.
+	//p.xdelta=0; p.ydelta=0;
+	
+	p.speedslower=0;
+			
+	p.geom.w=p.image->w;
+	p.geom.h=p.image->h;	
+			
+	//p.geom.x=BORDERLEFT + (PLAYWIDTH +BLOCKWIDTH )/2;
+	//p.geom.y=BORDERTOP  + (PLAYHEIGHT+BLOCKHEIGHT)/2;
+			
+	p.geom.x=x;
+	p.geom.y=y;
+
+		
+	p.bgsave = SDL_CreateRGBSurface(SDL_HWSURFACE,p.geom.w,p.geom.h,32,0,0,0,0);
+
+	return(p);
+}
+
+
+void savebehindpenguin(Penguin * p)
+{
+	SDL_BlitSurface(screen, &(p->geom), p->bgsave, NULL);
+}	
+
+void drawpenguin(Penguin * p)
+{
+	SDL_BlitSurface(p->image, NULL, screen, &(p->geom));
+}
+
+void erasepenguin(Penguin * p)
+{
+	SDL_BlitSurface(p->bgsave, NULL, screen, &(p->geom));
+}
+
+void movepenguin(Penguin * p)
+{
+	int newx, newy;
+	int checkx,checky;
+	int movex=0,movey=0;
+
+	switch (options.difficulty)
+	{
+		case NORMAL:
+			if (p->speedslower)
+				{ movex=p->xdelta/2; movey=p->ydelta/2; }
+			else
+				{ movex=p->xdelta; movey=p->ydelta; }
+			p->speedslower=!p->speedslower;
+		break;
+		case HARD:
+			movex=p->xdelta; movey=p->ydelta;
+		break;
+		case EASY:
+			movex=p->xdelta/2; movey=p->ydelta/2;
+		break;
+	}
+		
+	newx=p->geom.x+movex;
+	newy=p->geom.y+movey;
+
+	
+	markgrid(p->geom.x,p->geom.y,BLOCKWIDTH,BLOCKHEIGHT,' ');
+	//markgrid(p->geom.x+1,p->geom.y+1,BLOCKWIDTH-1,BLOCKHEIGHT-1,' ');
+	
+	if (movex>0) checkx = newx+BLOCKWIDTH;
+	else checkx = newx;
+
+	if (grid[checkx][p->geom.y]==' ' && grid[checkx][p->geom.y+BLOCKHEIGHT-1]==' ')
+	{
+		p->geom.x+=movex;
+	}
+	else if (grid[checkx][p->geom.y]=='1' || grid[checkx][p->geom.y+BLOCKHEIGHT-1]=='1')
+	{
+		line1.dead=true;
+		p->geom.x+=movex;	
+	}
+	else if (grid[checkx][p->geom.y]=='2' || grid[checkx][p->geom.y+BLOCKHEIGHT-1]=='2')
+	{
+		line2.dead=true;
+		p->geom.x+=movex;	
+	}
+	else if ((grid[checkx][p->geom.y]=='w' || grid[checkx][p->geom.y]==' ' ) 
+	      && (grid[checkx][p->geom.y+BLOCKHEIGHT-1]=='w' || grid[checkx][p->geom.y+BLOCKHEIGHT-1]==' '))
+	{
+		// this is used in the intro. maybe some place else too in the future.
+		// should it be merged into the first line above? maybe.
+		p->geom.x+=movex;
+	}
+	else
+	{
+		p->xdelta=-p->xdelta;
+	}
+
+	if (movey>0) checky = newy+BLOCKHEIGHT;
+	else checky = newy;
+	
+	if (grid[p->geom.x][checky]==' ' && grid[p->geom.x+BLOCKWIDTH-1][checky]==' ')
+	{
+		p->geom.y+=movey;
+	}
+	else if (grid[p->geom.x][checky]=='1' || grid[p->geom.x+BLOCKWIDTH-1][checky]=='1')
+	{
+		//printf("Hit 1\n");
+		line1.dead=true;
+		p->geom.y+=movey;		
+	}
+	else if (grid[p->geom.x][checky]=='2' || grid[p->geom.x+BLOCKWIDTH-1][checky]=='2')
+	{
+		//printf("Hit 2\n");
+		line2.dead=true;
+		p->geom.y+=movey;		
+	}
+	else if ((grid[p->geom.x][checky]=='w' || grid[p->geom.x][checky]==' ') 
+	      && (grid[p->geom.x+BLOCKWIDTH-1][checky]=='w' || grid[p->geom.x+BLOCKWIDTH-1][checky]==' '))
+	{
+		// this is used in the intro. maybe some place else too in the future.
+		// should it be merged into the first line above? maybe.
+		p->geom.y+=movey;
+	}
+
+	else
+	{
+		p->ydelta=-p->ydelta;
+	}
+
+	markgrid(p->geom.x,p->geom.y,BLOCKWIDTH,BLOCKHEIGHT,'*');
+	//markgrid(p->geom.x+1,p->geom.y+1,BLOCKWIDTH-1,BLOCKHEIGHT-1,'*');
+}
diff --git a/penguin.h b/penguin.h
new file mode 100644
index 0000000..0ec3e61
--- /dev/null
+++ b/penguin.h
@@ -0,0 +1,39 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+typedef struct
+{
+	SDL_Surface *image;
+	SDL_Surface *bgsave;
+	SDL_Rect geom;
+	int xdelta;
+	int ydelta;
+	int speedslower;
+} Penguin;
+
+
+
+extern Penguin createpenguin();
+extern Penguin createpenguinxy(int x, int y);
+extern void savebehindpenguin(Penguin * p);
+extern void drawpenguin(Penguin * p);
+extern void erasepenguin(Penguin * p);
+extern void movepenguin(Penguin * p);
+
diff --git a/penguinicon_32.bmp b/penguinicon_32.bmp
new file mode 100644
index 0000000..76355c8
Binary files /dev/null and b/penguinicon_32.bmp differ
diff --git a/sound.c b/sound.c
new file mode 100644
index 0000000..771cb24
--- /dev/null
+++ b/sound.c
@@ -0,0 +1,82 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include <SDL_mixer.h>
+#include "icebreaker.h"
+#include "sound.h"
+#include "options.h"
+
+int soundsystemworks=false;
+
+static Mix_Chunk *sndouch = NULL;
+static Mix_Chunk *sndbreak = NULL;
+
+
+void initsound()
+{
+	if (SDL_InitSubSystem(SDL_INIT_AUDIO))
+	{	
+		soundsystemworks=false;
+		fprintf(stderr, "Can't start sound subsystem: %s\nContinuing without it.\n", SDL_GetError());
+	}	
+	else if  (Mix_OpenAudio(11025, (Uint16)AUDIO_U8, 2, 256))
+	{
+		soundsystemworks=false;
+		fprintf(stderr, "Can't open audio: %s\nContinuing without it.\n", SDL_GetError());
+	}
+	else
+	{
+		soundsystemworks=true;
+		if ( (sndouch=Mix_LoadWAV(DATAPREFIX "/" SNDFILEOUCH)) == NULL)
+			fprintf(stderr, "Error loading " DATAPREFIX "/" SNDFILEOUCH "\n%s\n", SDL_GetError());
+		if ( (sndbreak=Mix_LoadWAV(DATAPREFIX "/" SNDFILEBREAK)) == NULL)
+			fprintf(stderr, "Error loading " DATAPREFIX "/" SNDFILEBREAK "\n%s\n", SDL_GetError());
+	}
+}
+
+
+void quitsound()
+{
+	while (Mix_Playing(-1)); 
+	
+	if (sndouch) { Mix_FreeChunk(sndouch); sndouch = NULL; }
+	if (sndbreak) { Mix_FreeChunk(sndbreak); sndbreak = NULL; }
+	
+	if (soundsystemworks) Mix_CloseAudio();	
+}
+
+
+void playsound(SoundSample s)
+{
+	if (soundsystemworks && options.sound==SOUNDON)
+	{
+		switch (s)
+		{
+			case SNDOUCH:
+				Mix_PlayChannel(-1, sndouch, 0);	
+			break;
+			case SNDBREAK:
+				Mix_PlayChannel(-1, sndbreak, 0);	
+			break;
+		}
+	}
+}
diff --git a/sound.h b/sound.h
new file mode 100644
index 0000000..d142c6e
--- /dev/null
+++ b/sound.h
@@ -0,0 +1,29 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+typedef enum { SNDOUCH, SNDBREAK } SoundSample;
+
+extern int soundsystemworks;
+
+extern void initsound(void);
+extern void quitsound(void);
+extern void playsound(SoundSample s);
+
diff --git a/status.c b/status.c
new file mode 100644
index 0000000..60fd40a
--- /dev/null
+++ b/status.c
@@ -0,0 +1,113 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> 
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+
+#include "icebreaker.h"
+#include "text.h"
+#include "globals.h"
+#include "hiscore.h"
+#include "laundry.h"
+#include "status.h"
+
+
+void updatestatuslives(int lives)
+{
+	//FIX == shouldn't need to recalc color every time.
+
+	SDL_Rect tmprect;
+	char tmptext[30]; // should be plenty big.
+	
+	//lives=99; //debug
+	
+	tmprect.h=CHARHEIGHT*2; tmprect.w=LIVESW;
+	tmprect.x=LIVESX; tmprect.y=STATUSY;
+	
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	snprintf(tmptext,30,"LIVES: %d",lives);
+	puttext(LIVESX,STATUSY,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),tmptext);
+	
+	soil(tmprect);
+
+}
+
+void updatestatuscleared(int cleared)
+{
+	//FIX == shouldn't need to recalc color every time.
+
+	SDL_Rect tmprect;
+	char tmptext[30]; // should be plenty big.
+	
+	//cleared=99; // debug
+	
+	tmprect.h=CHARHEIGHT*2; tmprect.w=CLEAREDW;
+	tmprect.x=CLEAREDX; tmprect.y=STATUSY;
+	
+	
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	snprintf(tmptext,30, "CLEARED: %d%%",cleared);
+	puttext(CLEAREDX,STATUSY,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),tmptext);
+	
+	soil(tmprect);
+
+}
+
+void updatestatusscore(long score)
+{
+	//FIX == shouldn't need to recalc color every time.
+
+	SDL_Rect tmprect;
+	char tmptext[30]; // should be plenty big.
+	
+	//score=99999; // debug
+	
+	tmprect.h=CHARHEIGHT*2; tmprect.w=SCOREW;
+	tmprect.x=SCOREX; tmprect.y=STATUSY;
+	
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	snprintf(tmptext,30, "SCORE: %ld",score);
+	puttext(SCOREX,STATUSY,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),tmptext);
+
+	soil(tmprect);
+}
+
+
+
+extern void updatehiscorebox()
+{ // FIX -- this might belong in hiscore.c, but maybe not
+	SDL_Rect tmprect;
+	
+	char tmptext[40]; // should be plenty big.
+	
+	tmprect.x=LIVESX; tmprect.y=BOTTOMSTATUSY;
+	tmprect.h=CHARHEIGHT*3;; tmprect.w=WIDTH-(CHARWIDTH*2*4)-MARGINRIGHT-4-LIVESX-2;
+	
+	
+	SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format,  0x00, 0x40, 0x80));
+	
+	snprintf(tmptext,40,"HIGH SCORE: %ld (%s)",hiscoreval[0],hiscorename[0]);
+	puttext(tmprect.x,tmprect.y+3,2,SDL_MapRGB(screen->format,  0xFF, 0xFF, 0xFF),tmptext);	
+	
+	soil(tmprect);
+}
diff --git a/status.h b/status.h
new file mode 100644
index 0000000..e194ee6
--- /dev/null
+++ b/status.h
@@ -0,0 +1,38 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern void updatestatuslives(int lives);
+extern void updatestatuscleared(int cleared);
+extern void updatestatusscore(long score);
+
+extern void updatehiscorebox();
+
+#define STATUSY (BORDERTOP-(4*CHARHEIGHT))
+
+#define LIVESX   (BORDERLEFT)
+#define CLEAREDX (LIVESX+165)
+#define SCOREX   (BORDERRIGHT-120)
+
+#define LIVESW (CLEAREDX - LIVESX)
+#define CLEAREDW (SCOREX - CLEAREDX)
+#define SCOREW  (WIDTH - SCOREX)
+
+#define BOTTOMSTATUSY (MARGINTOP+PLAYHEIGHT+CHARHEIGHT*2)
diff --git a/text.c b/text.c
new file mode 100644
index 0000000..29591a3
--- /dev/null
+++ b/text.c
@@ -0,0 +1,90 @@
+/*
+* IceBreaker
+* Copyright (c) 2000 Matthew Miller <mattdm at mattdm.org> http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include "icebreaker.h"
+#include "text.h"
+#include "string.h"
+#include "globals.h"
+
+static char * letterindex;
+static char * letterdata[6];
+
+
+void inittext()
+{
+	letterindex = " AAAAA BBBBB CCCCC DDDDD EEEEE FFFFF GGGGG HHHHH III JJJJJ KKKK LLLLL MMMMM NNNNN OOOOO PPPPP QQQQQ RRRRR SSSSS TTTTT UUUUU VVVVV WWWWW XXXXX YYYYY ZZZZZ aaaaa bbbbb cccc ddddd eeeee fffff ggggg hhhhh i jjjj kkkk lll mmmmm nnnnn ooooo ppppp qqqqq rrrr sssss tttt uuuuu vvvvv wwwww xxxx yyyyy zzzz 00000 11 22222 33333 44444 55555 66666 77777 88888 99999 ~~~~~~    ``     !    @@@@   #####  $$$$   %%%%%  ^^^^^  &&&&&  *****    ((   ))    _____  -----  +++++  =====   {{{     [ [...]
+	letterdata[0]="   #   ####   ###  ####  ##### #####  #### #   # ###   ### #  # #     #   # #   #  ###  ####   ###  ####   #### ##### #   # #   # #   # #   # #   # #####       #              #         ###       #     #    # #    ##                                            #                                      ###   # ####  ####     ## #####  ###  #####  ###   ###    #       #      #     ##     # #    ###   ##  #    #     ##      #       #   #                     #              #     # [...]
+	letterdata[1]="  # #  #   # #   # #   # #     #     #     #   #  #      # # #  #     ## ## ##  # #   # #   # #   # #   # #       #   #   # #   # # # #  # #   # #     #   #### ####   ###  ####  ###   #     #### ####         # ##  #  ## #  # ##   ###  ####   #### # ##  #### #### #   # #   # #   # #  # #   # #### #   # ##     #     #   # # #     #         # #   # #   #  # # #     #     #    # ##   #####  # #    ## #    # #   #      # # #    #     #                    #    #####    #      # [...]
+	letterdata[2]=" #   # ####  #     #   # ####  ####  #  ## #####  #      # ##   #     # # # # # # #   # ####  #   # ####   ###    #   #   #  # #  # # #   #     #     #   #   # #   # #    #   # ## ## ####  #   # #   # #    # ##    #  # # # ##  # #   # #   # #   # ##   ###    #   #   #  # #  # # #  ##  #   #   #  #   #  #  ###   ###   #  # ####  ####     #   ###   ####     #            #    # ##    # #    ###     #    #   #   ## #   ###     #     #           #####  #####          ##      # [...]
+	letterdata[3]=" ##### #   # #   # #   # #     #     #   # #   #  #  #   # # #  #     # # # #  ## #   # #     #   # #  #      #   #   #   #  # #  ## ##  # #    #    #    #  ## #   # #    #   # ###    #     #### #   # #    # # #   #  # # # #   # #   # #   # #   # #      ###  #   #  ##  # #  # # #  ##   ####  #   #   #  # #         # #####     # #   #   #   #   #     #                       #      #####    # #   # ##         #  #   # # #    #     #                    #    #####    #      # [...]
+	letterdata[4]=" #   # ####   ###  ####  ##### #      #### #   # ###  ###  #  # ##### #   # #   #  ###  #      ###  #   # ####    #    ###    #   #   # #   #   #   #####  ## # ####   ###  ####  ###   #        # #   # # #  # #  # ### #   # #   #  ###  ####   #### #    ####    ##  ## #   #    # #  #  #     # ####  ###   # ##### ####      # ####   ###   #     ###   ###                   #     ##     # #    ###   #  ##          ## #    #       #   #                     #              #     # [...]
+        letterdata[5]="                                                                                                 ##                                                                                           ###           ##                             #         #                                         ###                                                                                                                                                    #####                           [...]
+}
+
+
+// FIX -- should return actual width of box
+void puttext(int x, int y, int size, Uint32 color, char * text)
+{
+
+	SDL_Rect tmprect;
+	unsigned int l;
+	int i,j;
+	char * indexpointer;
+	unsigned char c;
+	int w,startx;
+	
+	if (size>1)
+	{
+		tmprect.h=size/2;
+		tmprect.w=size/2;
+	}
+	else
+	{
+		tmprect.h=1; tmprect.w=1;
+	}
+	startx=x;
+		
+	for (l=0; l<strlen(text); l++)
+	{
+		c=*(text+l);
+		indexpointer=index(letterindex,c);
+		if (indexpointer!=NULL)
+		{
+			w=0;
+			for (i=indexpointer-letterindex; *(letterindex+i)==c; i++)
+			{ // scan through index for location of letter.
+			 // FIX -- deal with spaces properly
+				for (j=0;j<CHARHEIGHT;j++)
+				{
+					if (*(letterdata[j]+i) != ' ')
+					{
+						tmprect.x=startx+w;
+						tmprect.y=y+j*size;
+						SDL_FillRect(screen,&tmprect,color);
+					}	
+				}
+				w+=size;
+			}
+			startx+=w+2;
+		}
+	}
+}
+
diff --git a/text.h b/text.h
new file mode 100644
index 0000000..630c17c
--- /dev/null
+++ b/text.h
@@ -0,0 +1,31 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#define CHARHEIGHT 6
+#define CHARWIDTH 6
+#define BIGCHARHEIGHT 25
+#define BIGCHARWIDTH 35
+
+// FIX -- need gettextwidth()
+
+extern void puttext(int x, int y, int size, Uint32 color, char * text);
+extern void inittext();
+
diff --git a/transition.c b/transition.c
new file mode 100644
index 0000000..0d7ef2a
--- /dev/null
+++ b/transition.c
@@ -0,0 +1,344 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <SDL.h>
+#include "icebreaker.h"
+#include "globals.h"
+#include "line.h"
+#include "level.h"
+#include "text.h"
+#include "cursor.h"
+#include "laundry.h"
+#include "hiscore.h"
+#include "dialog.h"
+
+// FIX -- it'd be better to draw text once and then scroll that graphic,
+// of course.
+
+static int scrolltext(char * firsttext, int firstx, Uint32 firstcolor, char * secondtext, int secondx, Uint32 secondcolor);
+
+int intermission(ScoreSheet * levelscore, int nextlevel)
+{
+	int done=false; int quit=false;
+	SDL_Event event;
+	SDL_Rect scorerect, bonusrect;
+	char scoretext[30];
+	char bonustext[30];
+
+	snprintf(scoretext,30,"SCORE: %d",levelscore->basescore);
+	snprintf(bonustext,30, "BONUS: %d",levelscore->clearbonus + levelscore->lifebonus);
+
+	// FIX -- play some truimphant sound.
+	
+	// clear any pending events
+	SDL_Delay(10); // needed? probably not.
+	while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) { done=true; quit=true; }
+
+	// get background
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+	
+	setcursor(CURSORCLICK);
+
+	scorerect.x=BORDERLEFT+PLAYWIDTH/2-80;
+	//scorerect.y=HEIGHT-CHARHEIGHT*4;
+	scorerect.y=HEIGHT-CHARHEIGHT*5;
+	scorerect.h=CHARHEIGHT*4;
+	scorerect.w=CHARWIDTH*4*12;
+	
+	bonusrect.x=BORDERLEFT+PLAYWIDTH/2-80;
+	bonusrect.y=HEIGHT-CHARHEIGHT*4;
+	bonusrect.h=CHARHEIGHT*4;
+	bonusrect.w=CHARWIDTH*4*12;
+	
+	// wait for click, scroll score
+	while (!done) 
+	{
+		while(SDL_PollEvent(&event));
+		{
+			if (event.type == SDL_QUIT)
+			{
+				done=true; quit=true;
+			}
+			else if (event.type==SDL_MOUSEBUTTONDOWN)
+			{
+				if (event.button.button==1)
+				{
+						done=true;
+						//printf("Click\n");
+				}
+			}
+		}
+		
+		
+		if (scorerect.y>(HEIGHT/2-30))
+		{
+			scorerect.y--; 
+			puttext(scorerect.x,scorerect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),scoretext);
+			soil(scorerect);
+			clean();		
+			SDL_BlitSurface(screensave,&scorerect, screen, &scorerect);
+			//soil(scorerect);
+		}
+		else if (scorerect.y==(HEIGHT/2-30))
+		{
+			// un-clean. :)
+			scorerect.y--; 
+			puttext(scorerect.x,scorerect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),scoretext);			
+			soil(scorerect);
+			clean();
+		}
+		else if (bonusrect.y>(HEIGHT/2))
+		{
+			bonusrect.y--;
+			puttext(bonusrect.x,bonusrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),bonustext);
+			soil(bonusrect);
+			clean();
+			SDL_BlitSurface(screensave,&bonusrect, screen, &bonusrect);
+			//soil(bonusrect);
+		}	
+		else if (bonusrect.y==(HEIGHT/2))
+		{
+			// un-clean
+			bonusrect.y--;
+			puttext(bonusrect.x,bonusrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),bonustext);
+			soil(bonusrect);
+			clean();
+		}	
+		else
+		{
+			clean();
+		}
+		
+		SDL_Delay(10);
+	}
+
+	// and clear any more events, for good luck.
+	while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) quit=true;
+			
+	//printf("Level %d completed. ",level);	
+	return(quit);
+}
+
+int gameover(long finalscore)
+{
+	int done=false; int quit=false;
+	SDL_Event event;
+	SDL_Rect loserrect, finalrect;
+
+	char finaltext[30];
+
+	// FIX -- play some truimphant sound.
+	
+	snprintf(finaltext,30,"FINAL SCORE: %ld",finalscore);
+
+
+	
+	// clear any pending events
+	SDL_Delay(10); // needed? probably not.
+	while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) { done=true; quit=true; }
+
+	// get background
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+	
+	if (!checkhiscore(finalscore))
+		setcursor(CURSORCLICK);
+	else 
+		setcursor(CURSORARROW);
+
+	loserrect.x=BORDERLEFT+PLAYWIDTH/2-85;
+	loserrect.y=HEIGHT-CHARHEIGHT*4;
+	loserrect.h=CHARHEIGHT*4;
+	loserrect.w=CHARWIDTH*4*12;
+	
+	finalrect.x=BORDERLEFT+PLAYWIDTH/2-130;
+	finalrect.y=HEIGHT-CHARHEIGHT*4;
+	finalrect.h=CHARHEIGHT*4;
+	finalrect.w=WIDTH-(BORDERLEFT+PLAYWIDTH/2-130);
+
+	// wait for click, scroll score
+	while (!done) 
+	{
+		while(SDL_PollEvent(&event));
+		{
+			if (event.type == SDL_QUIT)
+			{
+				done=true; quit=true;
+			}
+			else if (event.type==SDL_MOUSEBUTTONDOWN)
+			{
+				if (event.button.button==1)
+				{
+						done=true;
+				}
+			}
+		}
+		
+		if (loserrect.y>(HEIGHT/2-30))
+		{
+			loserrect.y--; 
+			puttext(loserrect.x,loserrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),"GAME OVER");
+			soil(loserrect);
+			clean();		
+			SDL_BlitSurface(screensave,&loserrect, screen, &loserrect);
+			//soil(loserrect);			
+		}
+		else if (loserrect.y==(HEIGHT/2-30))
+		{
+			// un-clean. :)
+			loserrect.y--; 
+			puttext(loserrect.x,loserrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),"GAME OVER");			
+			soil(loserrect);
+			clean();
+		}
+		else if (finalrect.y>(HEIGHT/2))
+		{
+			finalrect.y--;
+			puttext(finalrect.x,finalrect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),finaltext);
+			soil(finalrect);
+			clean();
+			SDL_BlitSurface(screensave,&finalrect, screen, &finalrect);
+			//soil(finalrect);
+		}
+		else if (finalrect.y==(HEIGHT/2))
+		{
+			// un-clean. :)
+			finalrect.y--;
+			puttext(finalrect.x,finalrect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),finaltext);
+			soil(finalrect);
+			if (checkhiscore(finalscore)) done=true;
+			clean();
+		}
+		else
+		{
+			clean();
+		}		
+		
+		SDL_Delay(10);
+	}
+		
+	if (checkhiscore(finalscore))
+	{
+		quit=gethighusername(finalscore>hiscoreval[0]);
+		addhiscore(username,finalscore);
+
+		// jump text to top
+		loserrect.y=(HEIGHT/2-31);
+		puttext(loserrect.x,loserrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),"GAME OVER");			
+		soil(loserrect);
+		finalrect.y=(HEIGHT/2);
+		puttext(finalrect.x,finalrect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),finaltext);
+		soil(loserrect);
+		clean();
+	}
+
+			
+	// and clear any more events, for good luck.
+	while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) quit=true;
+			
+	//printf("Game over.\n");	
+	return(quit);
+}
+
+
+int scrolltext(char * firsttext, int firstx, Uint32 firstcolor, char * secondtext, int secondx, Uint32 secondcolor)
+{
+	int quit=false;
+#if 0 /* FIX -- use this instead of the above two ugly functions */
+	int done=false;
+	SDL_Event event;
+	SDL_Rect firstrect, secondrect;
+
+	// get background
+	SDL_BlitSurface(screen, NULL, screensave, NULL);
+	
+	firstrect.x=firstx;
+	firstrect.y=HEIGHT-CHARHEIGHT*4;
+	firstrect.h=CHARHEIGHT*4;
+	firstrect.w=CHARWIDTH*4*12;
+	
+	secondrect.x=secondx;
+	secondrect.y=HEIGHT-CHARHEIGHT*4;
+	secondrect.h=CHARHEIGHT*4;
+	secondrect.w=WIDTH-(BORDERLEFT+PLAYWIDTH/2-130);
+
+	// wait for click, scroll score
+	while (!done) 
+	{
+		while(SDL_PollEvent(&event));
+		{
+			if (event.type == SDL_QUIT)
+			{
+				done=true; quit=true;
+			}
+			else if (event.type==SDL_MOUSEBUTTONDOWN)
+			{
+				if (event.button.button==1)
+				{
+						done=true;
+				}
+			}
+		}
+		
+		if (firstrect.y>(HEIGHT/2-30))
+		{
+			firstrect.y--; 
+			puttext(firstrect.x,firstrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),firsttext);
+			soil(firstrect);
+			clean();		
+			SDL_BlitSurface(screensave,&firstrect, screen, &firstrect);
+			//soil(firstrect);			
+		}
+		else if (firstrect.y==(HEIGHT/2-30))
+		{
+			// un-clean. :)
+			firstrect.y--; 
+			puttext(firstrect.x,firstrect.y,4,SDL_MapRGB(screen->format, 0xC0, 0x00, 0x40),firsttext);			
+			soil(firstrect);
+			clean();
+		}
+		else if (secondrect.y>(HEIGHT/2))
+		{
+			secondrect.y--;
+			puttext(secondrect.x,secondrect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),secondtext);
+			soil(secondrect);
+			clean();
+			SDL_BlitSurface(screensave,&secondrect, screen, &secondrect);
+			//soil(secondrect);
+		}
+		else if (secondrect.y==(HEIGHT/2))
+		{
+			// un-clean. :)
+			secondrect.y--;
+			puttext(secondrect.x,secondrect.y,4,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00),secondtext);
+			soil(secondrect);
+			clean();
+		}
+		else
+		{
+			done=true;
+			clean();
+		}		
+		
+		SDL_Delay(10);
+	}
+#endif /* FIX! */
+	return(quit);
+}
diff --git a/transition.h b/transition.h
new file mode 100644
index 0000000..fdee4ec
--- /dev/null
+++ b/transition.h
@@ -0,0 +1,24 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org>
+*   http://www.mattdm.org/
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+extern int intermission(ScoreSheet * levelscore, int nextlevel);
+extern int gameover(long finalscore);
+
diff --git a/win32_compatibility.c b/win32_compatibility.c
new file mode 100644
index 0000000..137afc1
--- /dev/null
+++ b/win32_compatibility.c
@@ -0,0 +1,44 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> and
+*   Enrico Tassi <f.tassi at mo.nettuno.it>
+* 
+* <http://www.mattdm.org/icebreaker>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+/************************************************************************/
+/* 
+*  This file contains varibles and functions to aid in win32 cross-compiling
+*  using mingw32 (based on gcc version 2.95.2 19991024 (release))
+*
+*  This is Enrico Tassi's <f.tassi at mo.nettuno.it> domain. :)
+*/
+ 
+#include "win32_compatibility.h"
+
+
+/* This is the structure that getpwuid returns - I dont think w9X has uids */
+struct passwd pwdwin32_nobody={"Nobody","*",1,1,"Win32 User",".","command.com"};
+
+/* string.h of mingw32 has no index(char*) prototype, and so no implementation */
+char *index(const char *s, int c)
+{
+	while( *s != '\0'&& *s != (char)c ) s++;
+	return((char*)s);
+}
diff --git a/win32_compatibility.h b/win32_compatibility.h
new file mode 100644
index 0000000..d995aa8
--- /dev/null
+++ b/win32_compatibility.h
@@ -0,0 +1,70 @@
+/*
+* IceBreaker
+* Copyright (c) 2000-2001 Matthew Miller <mattdm at mattdm.org> and
+*   Enrico Tassi <f.tassi at mo.nettuno.it>
+* 
+* <http://www.mattdm.org/icebreaker>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc., 59
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+
+/************************************************************************/
+/* 
+*  This file contains function prototypes, macros, etc. to aid in win32
+*  cross-compiling using mingw32 (based on gcc version 2.95.2 19991024
+*  (release))
+*
+*  This is Enrico Tassi's <f.tassi at mo.nettuno.it> domain. :)
+*/
+
+
+#ifndef WIN32_COMPATIBILITY_H
+#define WIN32_COMPATIBILITY_H
+
+/* mingw32 has _snprintf, not snprintf ??? */
+#define snprintf _snprintf
+
+/* mingw32 has no index(..) in string.h ??? */
+extern char *index(const char *s, int c);
+
+/* mingw32 has 'short' random functions */
+#define srandom(A) srand(A)
+#define random() rand()
+
+
+/* No pwd.h in mingw32 */
+#define uid_t int
+#define gid_t int
+	
+struct passwd{
+              char    *pw_name;       /* user name */
+              char    *pw_passwd;     /* user password */
+              uid_t   pw_uid;         /* user id */
+              gid_t   pw_gid;         /* group id */
+              char    *pw_gecos;      /* real name */
+              char    *pw_dir;        /* home directory */
+              char    *pw_shell;      /* shell program */
+      };
+
+/* a standard user -- see win32_compatibilty.c */
+extern struct passwd pwdwin32_nobody;
+
+/* No pwd.h -> no getpw... */	
+#define getuid() 0
+#define getpwuid(A) (&pwdwin32_nobody)
+
+#endif
diff --git a/win32_resources.rc b/win32_resources.rc
new file mode 100644
index 0000000..fe7782c
--- /dev/null
+++ b/win32_resources.rc
@@ -0,0 +1 @@
+1 ICON icebreaker_32.ico

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/icebreaker.git



More information about the Pkg-games-commits mailing list