summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBradley Smith2008-01-21 00:16:45 +0000
committerBradley Smith2008-01-21 00:16:45 +0000
commite6e7222d5a730368ed4e84c2e0f55427460e5230 (patch)
treee608410401099ccebe7ffa21de9336d78c78efc9
downloadgnurobots-e6e7222d5a730368ed4e84c2e0f55427460e5230.tar.gz
Imported GNU robots from CVS.
Signed-off-by: Bradley Smith <brad@brad-smith.co.uk>
-rw-r--r--AUTHORS9
-rw-r--r--COPYING351
-rw-r--r--ChangeLog269
-rw-r--r--Makefile.am23
-rw-r--r--NEWS59
-rw-r--r--README106
-rw-r--r--THANKS14
-rw-r--r--TODO18
-rwxr-xr-xbootstrap.sh6
-rw-r--r--configure.ac145
-rw-r--r--contrib/Makefile.am21
-rw-r--r--contrib/mapedit.c854
-rw-r--r--doc/Makefile.am23
-rw-r--r--doc/Robots-HOWTO241
-rw-r--r--doc/contrib20
-rw-r--r--doc/guile-proj.scm44
-rw-r--r--getopt/Makefile.am23
-rw-r--r--getopt/getopt.c683
-rw-r--r--getopt/getopt.h128
-rw-r--r--getopt/getopt1.c172
-rw-r--r--include/Makefile.am27
-rw-r--r--include/api.h43
-rw-r--r--include/configs.h63
-rw-r--r--include/grobot.h80
-rw-r--r--include/main.h10
-rw-r--r--include/map.h57
-rw-r--r--include/sign.h3
-rw-r--r--include/userinterface.h211
-rw-r--r--lib/Makefile.am48
-rw-r--r--lib/cursesplugin.c599
-rw-r--r--lib/cursesplugin.h69
-rw-r--r--lib/textplugin.c444
-rw-r--r--lib/textplugin.h63
-rw-r--r--lib/x11plugin.c840
-rw-r--r--lib/x11plugin.h102
-rw-r--r--lib/xpm/Makefile.am31
-rw-r--r--lib/xpm/baddie.xpm28
-rw-r--r--lib/xpm/food.xpm27
-rw-r--r--lib/xpm/prize.xpm31
-rw-r--r--lib/xpm/robot.xpm28
-rw-r--r--lib/xpm/robot_east.xpm28
-rw-r--r--lib/xpm/robot_north.xpm28
-rw-r--r--lib/xpm/robot_south.xpm28
-rw-r--r--lib/xpm/robot_west.xpm28
-rw-r--r--lib/xpm/space.xpm26
-rw-r--r--lib/xpm/statusbar.xpm58
-rw-r--r--lib/xpm/wall.xpm26
-rw-r--r--maps/Makefile.am30
-rw-r--r--maps/maze.map18
-rw-r--r--maps/pattern.map21
-rw-r--r--maps/small.map10
-rw-r--r--scheme/Makefile.am36
-rw-r--r--scheme/beep.scm30
-rw-r--r--scheme/greedy.scm112
-rw-r--r--scheme/mapper.scm827
-rw-r--r--scheme/simple.scm32
-rw-r--r--scheme/stop.scm16
-rw-r--r--scheme/zap.scm36
-rw-r--r--src/Makefile.am12
-rw-r--r--src/api.c160
-rw-r--r--src/grobot.c833
-rw-r--r--src/main.c565
-rw-r--r--src/map.c297
-rw-r--r--src/sign.c16
-rw-r--r--src/userinterface.c192
65 files changed, 9478 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..1c829e3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+
+Authors of GNU Robots
+=====================
+
+Daniel M. B. Fortes Manoel <dmbfm2@uol.com.br>
+James Hall <jhall@gnu.org>
+Tim Northover <tim@pnorthover.freeserve.co.uk>
+Zeeshan Ali Khattak <zeenix@gmail.com>
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f741673
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,351 @@
+
+ NOTE! This copyright does *not* cover user programs that run on top
+of GNU Robots - this is merely considered normal use of the game, and
+does *not* fall under the heading of "derived work". Also note that
+the GPL below is copyrighted by the Free Software Foundation, but the
+instance of code that it refers to (the GNU Robots game) is
+copyrighted by me and others who actually wrote it.
+
+ -Jim Hall <jhall1@isd.net>
+
+----------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, 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
+
+ Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..d824690
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,269 @@
+2005-09-06 Zeeshan Ali Khattak <zeenix@gmail.com>
+ * src/main.c src/api.c include/api.h include/main.h:
+ Converted to the newer scm_* API.
+
+2004-10-22 Zeeshan Ali Khattak <zeenix@gmail.com>
+ * lib/cures.c lib/x11.c lib/text.c
+ lib/curesplugin.c lib/x11plugin.c lib/textplugin.c
+ lib/curesplugin.h lib/x11plugin.h lib/textplugin.h lib/Makefile.am:
+ The plugins are also gobjectized now, at last. Had to rename
+ them and create header files for them.
+ * include/userinterface.h src/userinterface.c:
+ The userinterface module is no longer a modules loader but
+ an (gobject) interface that all display plugins MUST
+ implement.
+ * src/main.c:
+ The module loading/unloading has been moved to the main
+ module. Also needed to update the interaction with userinterface
+ module.
+ * configure.ac:
+ We needed properties in interfaces which was'nt supported
+ before glib <= 2.4.
+
+2004-10-1 Zeeshan Ali Khattak <zeenix@gmail.com>
+ * configure.ac include/userinterface.h src/userinterface.c:
+ replaced ltdl with gmodule. You have no idea how much I love
+ glib :)
+
+2004-09-29 Zeeshan Ali Khattak <zeenix@gmail.com>
+
+ * include/Makefile.am include/configs.h include/grobot.h
+ include/userinterface.h include/loadmap.h include/map.h
+ lib/curses.c lib/text.c lib/x11.c
+ src/Makefile.am src/grobot.c src/main.c src/userinterface.c
+ src/map.c:
+ GObjectized Map code too. Now remains the plugins, but who
+ will bell the cat? :)
+ * src/grobot.c:
+ Act appropriatelly on NULLs rather than g_return_if_fail in
+ _set_property.
+
+
+2004-09-24 Zeeshan Ali Khattak <zeenix@gmail.com>
+
+ * include/configs.h include/main.h src/grobot.c
+ src/main.c userinterface.c:
+ BUGFIX: a refcounting problem because of which the UI module
+ did'nt get the chance to destroy itself and you know damn well
+ what this would mean for the curses user. :)
+
+2004-09-10 Wojciech Polak
+
+ * src/main.c: Changed some printing style (help, version, and etc.).
+
+2004-08-26 Zeeshan Ali Khattak <zeenix@gmail.com>
+
+ * TODO: Removed things already solved/implemented.
+ * lib/curses.c lib/text.c lib/x11.c
+ src/userinterface.c src/main.c src/grobot.c include/userinterface.h:
+ Expanded the userinterface api to fix a problem I introduced in
+ the x11 plugin.
+
+2004-08-22 Wojciech Polak
+
+ * configure.ac: Added AC_PREREQ.
+ Require at least GNU Autoconf 2.59.
+ * Makefile.am: Added AUTOMAKE_OPTIONS.
+ Require at least GNU Automake 1.8.5.
+ * THANKS: Added new file.
+ * BUGS: Renamed to TODO.
+
+2004-08-22 Zeeshan Ali Khattak <zeenix@gmail.com>
+
+ * include/grobot.h include/robots.h src/grobot.c src/robots.c
+ include/Makefile.am src/Makefile.am
+ src/api.c src/loadmap.c src/main.c:
+ Renamed robots module to grobot to make it compatible with
+ the name of the object: GRobot.
+
+2004-08-21 Zeeshan Ali Khattak <zeenix@gmail.com>
+
+ Most of the modules have successfully be gobject-ized, except for the
+ Map loader and the plugins (which is a bit tricky).
+
+2004-07-27 Wojciech Polak
+
+ Now we can just use `make dist' to create the tarball.
+
+ * contrib/Makefile.am: Added new file.
+ * doc/Makefile.am: Likewise.
+ * getopt/Makefile.am: Likewise.
+ * include/Makefile.am: Likewise.
+ * lib/xpm/Makefile.am: Likewise.
+ * maps/Makefile.am: Added EXTRA_DIST.
+ * scheme/Makefile.am: Added EXTRA_DIST.
+ * lib/Makefile.am (SUBDIRS): Added xpm.
+ * Makefile.am (SUBDIRS): Added contrib, doc, getopt, and include.
+ * configure.ac (AC_CONFIG_FILES): Added new Makefiles.
+
+ * INSTALL: Moved it to the README file
+ (the specific installation issues).
+ * README: Updated.
+
+2004-07-25 Wojciech Polak
+
+ * configure.ac: Renamed from configure.in and slightly improved.
+ * Makefile.am (EXTRA_DIST): Added `build'.
+
+2004-07-24 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * include/userinterface.h src/userinterface.c:
+ Rename ui.* to userinterface.* to make it compatible with the
+ name change of the module (now an object) itself.
+
+2004-07-23 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * include/ui.h src/ui.c:
+ Some changes to the UI object.
+
+2004-07-20 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * configure.in:
+ First phase of OOPizing everything. We now require gobject
+ too.
+ * include/ui.h src/ui.c src/main.c src/api.c:
+ The UI module is now implemented as an object.
+
+2004-07-18 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * configure.in Makefile.am lib/Makefile.am:
+ Plugins are now compiled CONDITIONALLY.
+
+2004-07-17 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * configure.in src/Makefile.am:
+ We should rely on the guile provided autoconf macros rather
+ than our own tests
+
+2004-07-16 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * lib/curses.c lib/x11.c:
+ The robot should'nt just JUMP but move from one block to
+ another.
+ * src/main.c src/robots.c:
+ The list of robots is now implemented as a Doubly-Linked List
+ and not a static array.
+
+2004-07-15 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * lib/*.c src/main.c src/drawmap.c src/display.c
+ include/drawmap.h include/display.h
+ src/Makefile.am:
+ Removed drawmap module and shifted it's functionality into
+ the UI module. The previous change did'nt actually solved
+ the problem it was supposed to, but this one does.
+ Although this too does'nt solves the turning problem :(.
+ * lib/x11.c:
+ Solved the problem of turning not being animated in the x11
+ module.
+ * include/display.h include/ui.h
+ src/api.c src/main.c src/display.c src/ui.c
+ src/Makefile.am:
+ Changed the name of module 'display' to 'ui'.
+
+2004-07-13 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * lib/x11.c:
+ BUGFIX: zaping and grapping did'nt used to be animated before
+ the robot-moved. Robot turning has a simillar problem but I'll
+ have a look at it tomorrow.
+
+2004-07-12 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * maps/Makefile.am scheme/Makefile.am src/Makefile.am Makefile.am
+ configure.in include/configs.h :
+ Build-system install is now aware of data files
+ * bootstrap.sh:
+ bootstrap.sh now runs the configure script with no options
+
+2004-07-10 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * bootstrap.sh:
+ Simplied the bootstrap process by using: autoreconf -fisv
+ * src/drawmap.c:
+ BUGFIX: replaced hook_add_thing with newer display_add_thing.
+ display should really be changed to UI.
+
+2004-07-08 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * bootstrap.sh configure.in
+ include/hooks.h include/display.h include/api.h
+ src/Makefile.am src/api.c src/display.c src/main.c
+ lib/Makefile.am lib/text.c lib/curses.c lib/x11.c:
+ 1 UI is now implemented as dynamically loaded modules
+ -> plugins. Also added a switch by which user can
+ specify the module to use. Otherwise grobots shall
+ choose the best available (x11 if env varriable DISPLAY
+ is defined, curses otherwise).
+
+ 2 There is ONLY one binary now: grobots
+
+ 3 User dont need to provide full path to the maps or scheme
+ file. The pkgdatadir and the path declared through the
+ Env varriables GNU_ROBOTS_MAPS_PATH and
+ GNU_ROBOTS_SCRIPTS_PATH are searched for the file.
+
+2004-07-03 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * configure.ac lib/Makefile.am src/Makefile.am:
+ Start to use libtool.
+
+2004-07-01 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * *.h *.c:
+ Some minor chages and first phase of GLIBization.
+
+2004-06-30 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * curses.c:
+ Some minor changes.
+ * bootstrap.sh configure.in Makefile.am src/Makefile.am lib/Makefile.am
+ Makefile.in src/Makefile.in lib/Makefile.in:
+ Now we also use automake
+
+2004-06-29 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * hooks.h curses.c text.c x11.c main.c:
+ Added another function hook_put_string. Using it, added
+ code to throw the exceptions caught during interractive mode
+ to the display.
+
+2004-06-28 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * curses.c:
+ Added Colors. Let there be light!
+ * api.h curses.c x11.c:
+ Fixed some timing stuff
+ * api.h *.map:
+ A space is now repressented by a space, both in maps and
+ on the cureses-based display.
+ * main.c x11.c text.c curses.c:
+ Added interactive mode. If the scheme file is not specified,
+ we go into an interactive mode. I'll improve on it tomorrow.
+
+2004-06-27 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * api.h api.c:
+ Removed a bug i introduced
+
+ * random.h random.c:
+ Removed. No longer needed after guile 1.3
+
+ * Makefile.in src/Makefile.in lib/Makefile.in:
+ Corrected some build problems.
+
+
+2004-06-27 Zeeshan Ali Khattak <zak147@yahoo.com>
+
+ * *.c *.h:
+ Ran gstreamer provided script gst-indent to indent all the
+ source files according to what most of the people use rather
+ than strictly following the GNU Coding Standards.
+
+ * api.h text.c:
+ defined a global array of strings to translate the directions
+ to strings
+
+ * scheme/*.scm:
+ Changed some minor stuff in nice scripts writen a little badly
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..370477e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,23 @@
+##
+## Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+AUTOMAKE_OPTIONS = 1.8.5
+SUBDIRS = contrib doc getopt include lib maps scheme src
+EXTRA_DIST = build
+MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..688f4f0
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,59 @@
+RELEASE HISTORY FOR GNU ROBOTS:
+_____________________________________________________________________
+
+1.0D Added some extra documentation (but not much) and the early
+ beginning of code clean-up.
+
+1.0C Pawel <uzturnau@cyf-kr.edu.pl> fixed a bug where the robot was
+ not able to smell anything to the east or west.
+
+ Fixed a few other bugs.
+
+ Moving the robot around and zapping things and picking things up
+ just got a little more expensive. If you are running an old
+ robot under GNU Robots 1.0, you may notice that your robot won't
+ last as long. I think the new energy "costs" will challenge
+ people to write more efficient robot programs.
+
+ Removed scm_random and scm_randomize, since the random function
+ is now provided in GNU Guile 1.3. If you are trying to run GNU
+ Robots under GNU Guile 1.2 or previous, you will need to patch
+ it yourself using the src/random.c source file.
+
+ Ran all the .c files through GNU Indent. Sorry about not having
+ done that before, everyone.
+
+ Added more comments to the sample robot programs.
+
+ Tim Northover contributed a GNU Robots map editor. I have put
+ this in the `contrib' directory.
+
+_____________________________________________________________________
+
+0.95 - Applied several patches from Steinar Hamre
+ <steinarh@stud.fim.ntnu.no> that fix how `configure' locates
+ GNU Guile. No feature enhancements.
+
+0.91 - Fixed a few annoying bugs. No feature enhancements.
+
+0.9 - Used GNU Autoconf to configure the source for various platforms.
+ Made robot variables into `long', improved command line using
+ `getopt', and added Scheme functions to check robot status.
+ Also, included some sample robots that were submitted.
+
+0.8 - Added GNU Getopt to scan command line. Added contributions for
+ X Windows interface, and added cooler XPMs. Changed build
+ target names, to be more descriptive. Added html
+ documentation.
+
+0.77 - Added 'random' and 'randomize' functions. Redefined 'exit' and
+ 'quit' to exit nicely. Some tweaking to initial energy.
+
+0.76 - Added code to stop the game when the robot runs out of energy
+ or shields fall to zero. Reduced globals to only main.c and
+ api.c. Now builds both the curses and log-file game for 'make
+ all'.
+
+0.72 - Fixed a bug during movement. Added a new sample robot. First
+ release when the game engine actually seems to work. Does not
+ stop the game when the robot is dead, though.
diff --git a/README b/README
new file mode 100644
index 0000000..5304fbb
--- /dev/null
+++ b/README
@@ -0,0 +1,106 @@
+
+Introduction
+============
+
+GNU Robots is a game/diversion where you construct a program for a
+little robot, then set him loose and watch him explore a world on his
+own. The robot program is written in Scheme, and is implemented using
+GNU Guile.
+
+Installing GNU Robots
+======================
+
+(0) To build GNU Robots, you *first* need to have already compiled and
+ installed the GNU Guile library. GNU Robots was built using Guile
+ 1.3.
+
+ Guile 1.2 will also work, but you will need to provide your own
+ scm_random() function. See src/random.c
+
+(1) Type:
+
+ ./configure
+
+ To specify an unusual location for GNU Guile, you can use the
+ `--with-guile=' option, like this:
+
+ ./configure --with-guile=/home/jhall
+
+ To specify an unusual location for curses, you can use the
+ `--with-curses=' option, like this:
+
+ ./configure --with-curses=/hub/local
+
+(2) Look at the generated `Makefile', and check that everything is
+ okay. Then type:
+
+ make
+
+Notes
+=====
+
+* There is really one key missing piece in GNU Robots: I had
+* originally envisioned a "visual" programming interface for GNU
+* Robots, one where you could create a robot program by dropping into
+* place icons that represent the robot's actions. There would be one
+* icon to tell the robot to move forward, another to have him turn to
+* the left or right, and another to have him pick up things or fire
+* his little gun.
+*
+* This programming interface would really just act as a kind of code
+* generator; it would write a Scheme program that you could then load
+* into GNU Robots. Writing this in GTK+ would seem like a good idea.
+*
+* If anyone would like to help write this programming interface for
+* GNU Robots, please contact me! You may reach me at <jhall1@isd.net>
+
+
+There are three ways to run GNU Robots:
+
+1. X Windows ("xrobots")
+2. text mode, using curses ("robots")
+3. text mode, log file output ("robots_logfile")
+
+I use the robots_logfile when I am hosting a GNU Robots competition,
+because it is not really interesting for me to see how the many robots
+are individually interacting with their environments. I am only
+interested in the outcome.
+
+I use the xrobots program when I am running my own GNU Robot game,
+because there I *am* interested in what my robot is doing.
+
+--
+
+The "robots" program is a curses-based version of the game, using an
+ASCII approximation of the game elements. Your robot will appear as a
+"v" when it points South, "^" when it points North, and "<" and ">"
+for West and East. Empty spaces are shown as " ", walls as "#",
+baddies as "@", and food and prizes as "+" and "$".
+
+You'll note that this is the same notation used in the GNU Robots map
+files. The initial location of the robot is not shown in the map
+file, but is always at 1,1 facing East (the upper-left corner is
+always 0,0).
+
+The sample map that is provided as "maps/small.map" is just a single
+room, with prizes all along the four walls. The sample robot program
+"scheme/simple.scm" knows how to pick up all these prizes and then
+quit. Other map files can be found in the maps/ directory, and other
+robot programs are in the scheme/ directory.
+
+The usage for robots, xrobots, robots_logfile is as follows:
+
+ robots [OPTION]... [FILE]
+
+Options are:
+
+ -f, --map-file=FILE Load map file
+ -s, --shields=N Set initial shields to N
+ -e, --energy=N Set initial energy to N
+ -V, --version Output version information and exit
+ -h, --help Display this help and exit
+
+Even though it's not shown, the `-f' option to load a map file is
+required by GNU Robots. Otherwise, the game will not be able to open
+a map for your robot to explore!
+
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..3942c1f
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,14 @@
+GNU Robots THANKS file
+
+GNU Robots was originally written by Jim Hall.
+Other people contributed by reporting problems,
+suggesting various improvements, or submitting
+actual code. Here is a list of those people.
+
+Daniel M. B. Fortes Manoel <dmbfm2@uol.com.br>
+David Madore <david.madore@ens.fr>
+Pawel Turnau <uzturnau@cyf-kr.edu.pl>
+Steinar Hamre <steinarh@stud.fim.ntnu.no>
+Tim Northover <tim@pnorthover.freeserve.co.uk>
+Zeeshan Ali Khattak <zeenix@gmail.com>
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..704142f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,18 @@
+
+KNOWN BUGS:
+_____________________________________________________________________
+
+_____________________________________________________________________
+
+THINGS TO DO:
+_____________________________________________________________________
+
+* Improve the graphics, to make everything look better. I think I
+ need a graphic designer to help me do this. GTK+ would be nice.
+
+* In version 2.0, more creatures will get added. The things called
+ "baddie" and "food" and "prize" will be generic descriptors. For
+ example, "food" will be a generic name for "cookie" or "donut", so
+ that (robot-feel 'cookie) will fail if the thing is a donut, but
+ (robot-feel 'food) will still work.
+
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..607ca68
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+autoreconf -fisv
+
+echo "Running configure with no arguments"
+./configure
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..2c16a6a
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,145 @@
+dnl
+dnl configure.ac for GNU Robots
+dnl Copyright (C) 1998 Jim Hall, jhall1@isd.net
+dnl
+dnl GNU Robots is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl GNU Robots is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Robots; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+dnl
+
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT([GNU Robots], [1.1], [zeenix@gmail.com], [robots])
+AC_PREREQ([2.59])
+AM_CONFIG_HEADER([config.h])
+AC_CONFIG_AUX_DIR([build])
+AC_CONFIG_SRCDIR([include/api.h])
+AM_INIT_AUTOMAKE
+
+dnl Checks for programs.
+AC_PROG_CC
+
+dnl libtool stuff
+AC_LIBTOOL_DLOPEN
+dnl AC_LIBLTDL_CONVENIENCE
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+AC_SUBST(INCLTDL)
+AC_SUBST(LIBLTDL)
+
+dnl Locate X Windows
+dnl We need AC_PATH_XTRA to also locate extra libaries X depends on.
+dnl It will ``export'' X_CFLAGS, X_PRE_LIBS, X_EXTRA_LIBS and X_LIBS,
+dnl but for some reason we need to add -lX11 ourselves.
+AC_PATH_XTRA
+
+if test "$have_x" = yes; then
+ x_libs="-lX11"
+ use_x11="yes"
+
+dnl Checks for more X11 libraries, these go to X_LIBS.
+AC_CHECK_LIB(Xpm, XpmCreatePixmapFromData,
+ x_libs="-lXpm $x_libs"
+ use_x11="yes",
+ AC_MSG_WARN("can't find libXpm, X11 plugin shall not be compiled")
+ use_x11="no",
+ $X_LIBS $x_libs $X_PRE_LIBS $X_EXTRA_LIBS)
+
+dnl finished with X, so we update X_LIBS.
+X_LIBS="$X_LIBS $x_libs"
+
+else
+ AC_MSG_WARN("can't find X windows, X11 plugin shall not be compiled")
+ use_x11="no",
+fi
+
+AM_CONDITIONAL(USE_X11, test "$use_x11" = "yes")
+
+dnl Check for curses, add to CURSES_LIBS, and CURSES_CFLAGS.
+dnl At this time, only ncurses is supported.
+dnl We should check for SYSV curses too.
+AC_CHECK_HEADERS(ncurses.h,
+ use_curses="yes",
+ AC_MSG_WARN("Can't find ncurses. Curses plugin shall not be compiled.")
+ use_curses="no")
+
+dnl we dont need other checks if the headers are not found
+if test "$use_curses" = "yes"
+then
+
+dnl allow user to specify directory where to find ncurses
+if test -n "$with_ncurses"
+then
+ ncurses_cflags="-I$with_ncurses/include"
+ ncurses_libs="-L$with_ncurses/lib"
+fi
+
+AC_CHECK_LIB(ncurses, initscr,
+ CURSES_LIBS="$ncurses_libs -lncurses"
+ CURSES_CFLAGS="$ncurses_cflags"
+ use_curses="yes",
+ AC_MSG_WARN("Can't find ncurses. Curses plugin shall not be compiled.")
+ use_curses="no")
+
+AC_SUBST(CURSES_LIBS)
+AC_SUBST(CURSES_CFLAGS)
+
+fi
+
+AM_CONDITIONAL(USE_CURSES, test "$use_curses" = "yes")
+
+dnl Check for math library
+AC_CHECK_LIB(m, pow)
+
+dnl Check for guile
+GUILE_FLAGS
+
+dnl Some sytems need -ldl for dynamic library support.
+dnl AC_CHECK_LIB(dl, dlopen)
+
+dnl Check for glib2
+PKG_CHECK_MODULES(GLIB2,glib-2.0 >= 2.4 gobject-2.0 gmodule-2.0,HAVE_GLIB2=yes,HAVE_GLIB2=no)
+AC_SUBST(GLIB2_LIBS)
+AC_SUBST(GLIB2_CFLAGS)
+
+schemedir="\$(pkgdatadir)/scheme"
+AC_SUBST(schemedir)
+
+mapsdir="\$(pkgdatadir)/maps"
+AC_SUBST(mapsdir)
+
+if test "x$HAVE_GLIB2" = "xno"; then
+ AC_MSG_ERROR([GNU Robots requires GLib2 to compile.])
+fi
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+
+dnl Done.
+AC_CONFIG_FILES([Makefile
+ contrib/Makefile
+ doc/Makefile
+ getopt/Makefile
+ include/Makefile
+ lib/Makefile
+ lib/xpm/Makefile
+ maps/Makefile
+ scheme/Makefile
+ src/Makefile
+ ])
+AC_OUTPUT
+
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
new file mode 100644
index 0000000..e2e5a02
--- /dev/null
+++ b/contrib/Makefile.am
@@ -0,0 +1,21 @@
+##
+## contrib/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+EXTRA_DIST =\
+ mapedit.c
+
diff --git a/contrib/mapedit.c b/contrib/mapedit.c
new file mode 100644
index 0000000..fc16bda
--- /dev/null
+++ b/contrib/mapedit.c
@@ -0,0 +1,854 @@
+/* Map editor for GNU robots game */
+
+/* Copyright (C) 2000 Tim Northover, tim@pnorthover.freeserve.co.uk
+ using xpms from Tim Whittock*/
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* compile with:
+ gcc mapedit.c -omapedit -I../lib `gtk-config --cflags --libs` */
+
+/* Usage: mapedit [filename] */
+
+#include <gtk/gtk.h> /* xwindows functions */
+#include <stdio.h> /* for file functions */
+#include <stdlib.h> /* for atoi */
+
+/* indexes into the blocks array */
+
+#define SPACE 0
+#define FOOD 1
+#define WALL 2
+#define BADDIE 3
+#define PRIZE 4
+
+/* this is 1 more than the real size to allow for a border around
+ images: */
+
+#define IMGSIZE 17
+
+/* Stores information on blocks for display and storage */
+
+typedef struct
+{
+ int type; /* probably unnecessary at the moment,
+ but potentially useful (pointers) */
+ char *name; /* for display */
+ char save_char; /* character in map files */
+ char **xpm_data; /* again at the moment not really necessary,
+ but potentially */
+ GdkPixmap *pixmap; /* The image in gtk useable form */
+}
+BlockType;
+
+typedef struct
+{
+ int width, height;
+ char *data; /* will contain index into blocks array */
+}
+GridType;
+
+GridType grid; /* The internal grid representation */
+
+/* Now define known blocks -- leave xpm_data & pixmap for later init */
+
+BlockType blocks[] = { {SPACE, "Empty Space", '.', NULL, NULL},
+{FOOD, "Food", '+', NULL, NULL},
+{WALL, "Wall", '#', NULL, NULL},
+{BADDIE, "Baddie", '@', NULL, NULL},
+{PRIZE, "Prize", '$', NULL, NULL}
+};
+
+int nblocks = 5; /* number of blocks */
+
+GtkEntry *width_text, *height_text; /* for use by the size setting
+ button -- not ideal as
+ globals but simpler */
+
+int dragging; /* whether to change "grid" --
+ modified by button_press &
+ button_release */
+
+int current_tool; /* index into blocks */
+
+GtkWidget *grid_window; /* main window for displaying map --
+ used by various functions */
+
+/* initialisation/end funcs */
+
+/* blocks global */
+void init_blocks ();
+
+/* initialises global "grid" -- doesn't touch anything X related */
+void init_grid (char *filename);
+
+/* used at beginning and in load button func to actually set "grid" */
+void load_file (char *filename);
+
+/* used to report failure to load/save file */
+void message_box (char *title, char *message);
+
+/* ATM only frees "grid.data" */
+void freestuff ();
+
+/* creates a box with pixmap & label -- for toolbox display */
+GtkWidget *create_pixmap_with_label (GtkWidget * parent, GdkPixmap * pixmap,
+ char *text);
+/* handler function when new tool is clicked */
+void change_tool (GtkWidget * widget, gpointer data);
+
+
+/* Grid update hanlders */
+
+/* (mouse) button pressed in map window -- start draw */
+void button_press (GtkFixed * fixed, GdkEventButton * event, gpointer data);
+
+/* mouse moved in map window -- checks "dragging" */
+void mouse_move (GtkFixed * fixed, GdkEventMotion * event, gpointer data);
+
+/* stop drawing */
+void button_release (GtkFixed * fixed, GdkEventButton * event, gpointer data);
+
+/* sets "grid" and individual pixmap on map window */
+void update_grid (GtkFixed * fixed, int x, int y);
+
+/* creates radio button vertical box (for tools) */
+GtkWidget *create_toolbox_box (GtkWidget * parent, GtkSignalFunc func);
+
+/* creates box with load, save... */
+GtkWidget *create_command_box (char *filename);
+
+/* creates window for both of above widgets */
+GtkWidget *create_toolbox_window (char *filename);
+
+/* creates map display window */
+GtkWidget *create_grid_window ();
+
+/* clicked routine for Save */
+void save_button (GtkWidget * widget, GtkEntry * textbox);
+
+/* clicked routine for Load */
+void load_button (GtkWidget * widget, GtkEntry * textbox);
+
+/* clicked routine for Set Size */
+void set_size (GtkWidget * widget, gpointer data);
+
+/* destroys current map window and creates a new one from "grid" */
+void recreate_grid_window ();
+
+int
+main (int argc, char **argv)
+{
+ char *filename;
+ FILE *fp; /* for checking filename given */
+
+ GtkWidget *toolbox; /* main window -- currently unused but
+ saved for future -- and it's nice
+ to know I know something about the
+ window I've created */
+
+ /* Global initialisation */
+
+ if (argc > 1) /* check if filename specified */
+ {
+ filename = argv[1];
+ fp = fopen (filename, "r");
+ if (!fp)
+ {
+ g_print ("Could not open file '%s'\n", filename);
+ g_print ("Usage: %s [filename]\n", argv[0]);
+ return 1;
+ }
+ fclose (fp);
+ }
+ else
+ filename = NULL;
+
+ gtk_init (&argc, &argv); /* must be before any other gtk_functions... */
+ current_tool = SPACE;
+ init_blocks (); /* ...like the ones in here */
+
+ init_grid (filename); /* loads file or creates 16x16 grid
+ with SPACE */
+
+ toolbox = create_toolbox_window (filename); /* main window creation */
+
+ gtk_main (); /* Main message loop -- Go! */
+
+ return 0; /* Everything went fine (from our
+ perspective) */
+}
+
+/* initialises the rest of the "blocks" array */
+void
+init_blocks ()
+{
+ int i; /* counter */
+ GdkColormap *colour; /* necessary for creating pixmaps
+ -- otherwise warnings ensue */
+#include "xpm/food.xpm"
+#include "xpm/space.xpm"
+#include "xpm/prize.xpm"
+#include "xpm/baddie.xpm"
+#include "xpm/wall.xpm"
+
+ /* These could be set globally, but this avoids making the xpm data
+ global */
+
+ blocks[0].xpm_data = space_xpm;
+ blocks[1].xpm_data = food_xpm;
+ blocks[2].xpm_data = wall_xpm;
+ blocks[3].xpm_data = baddie_xpm;
+ blocks[4].xpm_data = prize_xpm;
+
+ colour = gdk_colormap_get_system (); /* needed to prevent warnings */
+
+ for (i = 0; i < nblocks; i++)
+ {
+ blocks[i].pixmap =
+ gdk_pixmap_colormap_create_from_xpm_d (NULL, colour, NULL, NULL,
+ blocks[i].xpm_data);
+ }
+}
+
+/* either loads file or creates blank map -- called at beginning */
+
+void
+init_grid (char *filename)
+{
+ int i; /* counter */
+
+ if (filename) /* file specified -- only false first
+ time if no command line options */
+ {
+ load_file (filename);
+ }
+
+ else
+ {
+ grid.width = grid.height = 16;
+
+ grid.data = (char *) g_malloc (grid.width * grid.height * sizeof (char)); /* grab memory */
+
+ for (i = 0; i < grid.width * grid.height; i++) /* initialise grid */
+ {
+ grid.data[i] = SPACE;
+ }
+ }
+}
+
+/* callback for radio buttons -- changes tool */
+
+void
+change_tool (GtkWidget * widget, gpointer data)
+{
+ /* can't just pass integer -- need GINT_TO_POINTER and converse */
+
+ current_tool = GPOINTER_TO_INT (data);
+}
+
+/* This creates a pixmap and a label from data -- returns hbox with contents */
+
+GtkWidget *
+create_pixmap_with_label (GtkWidget * parent, GdkPixmap * pixmap, char *text)
+{
+ GtkWidget *pixmapwid, *box, *label; /* All variables -- easier
+ than doubling up */
+
+ box = gtk_hbox_new (FALSE, 2);
+
+ /* Create them */
+
+ pixmapwid = gtk_pixmap_new (pixmap, NULL);
+ gtk_widget_show (pixmapwid);
+ label = gtk_label_new (text);
+ gtk_widget_show (label);
+
+ /* Put them in the box */
+
+ gtk_box_pack_start (GTK_BOX (box), pixmapwid, FALSE, FALSE, 4);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 4);
+ gtk_widget_show (box);
+
+ return box;
+}
+
+/* This creates a vbox with each tool in linked to specified function */
+
+GtkWidget *
+create_toolbox_box (GtkWidget * parent, GtkSignalFunc func)
+{
+ int i; /* counter */
+ GtkWidget *box; /* Box to return */
+ GtkWidget *button; /* radio button for tools */
+ GtkWidget *pixmap; /* Picture to display -- with label */
+
+ box = gtk_vbox_new (FALSE, 2);
+
+ for (i = 0, button = NULL; i < nblocks; i++)
+ {
+ pixmap = create_pixmap_with_label (parent, blocks[i].pixmap, blocks[i].name); /* actually a box -- but contains a pixmap */
+
+ /* create button radio group -- use ?: to prevent special case */
+
+ button =
+ gtk_radio_button_new (button ?
+ gtk_radio_button_group (GTK_RADIO_BUTTON
+ (button)) : NULL);
+
+ gtk_container_add (GTK_CONTAINER (button), pixmap);
+
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (i));
+
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+
+ gtk_widget_show (button);
+ }
+
+ return box; /* return a nice package */
+}
+
+/* callback for clicking save button -- currently only way so it does
+ th work here */
+
+void
+save_button (GtkWidget * widget, GtkEntry * textbox)
+{
+ /* textbox is passed as data in ...signal_connect */
+
+ int i, j; /* counters -- width & height */
+ FILE *fp;
+ char *filename; /* obtained from "textbox" */
+
+ if (!grid_window) /* Don't save if they've closed the window */
+ {
+ return;
+ }
+
+ /* Open and check file */
+
+ filename = gtk_entry_get_text (GTK_ENTRY (textbox));
+ fp = fopen (filename, "w");
+
+ if (!fp) /* can't proceed */
+ {
+ message_box ("Error:", "Could not save file");
+ return; /* Can't proceed */
+ }
+
+ /* Write file */
+
+ for (i = 0; i < grid.height; i++)
+ {
+ for (j = 0; j < grid.width; j++)
+ fputc (blocks[(int) grid.data[i * grid.width + j]].save_char, fp); /* put the save_char for correct "blocks" entry */
+
+ fputc ('\n', fp); /* newline */
+ }
+
+ fclose (fp);
+}
+
+/* actual function to load file -- don't put more spare \n's at end
+ than width -- it won't like it */
+
+void
+load_file (char *filename)
+{
+ FILE *fp;
+ int length; /* length of file */
+
+ int ctr, i, first; /* counter into data,
+ counter for finding correct block,
+ whether first line */
+
+ char *data, c; /* buffer and current character */
+
+ /* standard open and check... */
+
+ fp = fopen (filename, "r");
+
+ if (!fp)
+ {
+ message_box ("Error", "Could not open file");
+ return;
+ }
+
+ /* find file size -- and allocation */
+
+ fseek (fp, 0, SEEK_END);
+ length = ftell (fp);
+ rewind (fp); /* for reading */
+
+ data = (char *) g_malloc (length * sizeof (char));
+
+ /* will be larger than necessary -- but only by (height) bytes
+ usually */
+
+ ctr = 0; /* index into "data" */
+
+ first = 1; /* first line */
+
+ while ((c = fgetc (fp)) != EOF)
+ {
+ /* This is executed more frequently than strictly necessary
+ (ideally only on \n as well as normal) -- but this ensures
+ things work */
+
+ data[ctr] = WALL; /* Sensible default (used in xrobots
+ as default) */
+
+ /* find correct block */
+
+ for (i = 0; i < nblocks; i++)
+ if (c == blocks[i].save_char)
+ {
+ data[ctr++] = i;
+ break;
+ }
+
+ if (c == '\n' && first) /* end of first line -- now know width */
+ {
+ first = 0; /* not first any more */
+ grid.width = ctr;
+ }
+ }
+ fclose (fp); /* Done here */
+
+ grid.height = length / (grid.width + 1); /* height * (width + newlines) == file size (roughly) */
+
+ g_free (grid.data); /* free the old... */
+
+ grid.data = data; /* ...and replace with new */
+}
+
+/* Actual load button clicked -- calls load_file for hard work*/
+
+void
+load_button (GtkWidget * widget, GtkEntry * textbox)
+{
+ char *filename;
+
+ filename = gtk_entry_get_text (textbox);
+ load_file (filename);
+
+ recreate_grid_window (); /* destroys current window and creates new */
+}
+
+/* Callback for Setting Size button */
+
+void
+set_size (GtkWidget * widget, gpointer data)
+{
+ int x, y, i;
+
+ x = atoi (gtk_entry_get_text (width_text));
+ y = atoi (gtk_entry_get_text (height_text));
+ if (x > 0 && y > 0 && (x != grid.width || y != grid.height))
+ /* check data in boxes (don't change to same size as now) */
+ {
+ grid.width = x;
+ grid.height = y;
+
+ if (grid.data)
+ g_free (grid.data);
+
+ grid.data =
+ (char *) g_malloc (grid.width * grid.height * sizeof (char));
+
+ for (i = 0; i < grid.width * grid.height; i++) /* note that current grid is not saved or scaled */
+ grid.data[i] = SPACE;
+
+ recreate_grid_window (); /* inform gtk of change */
+ }
+}
+
+/* destroys current map window and creates new */
+
+void
+recreate_grid_window ()
+{
+ if (grid_window) /* just in case -- person could have
+ closed the window */
+ {
+ gtk_widget_destroy (grid_window);
+ }
+ grid_window = create_grid_window ();
+}
+
+/* create box of functions -- very tedious */
+
+GtkWidget *
+create_command_box (char *filename)
+{
+ char str[255]; /* to set text boxes based on
+ width/height -- I know it's
+ unlikely that it will be 255 chars
+ long */
+
+ GtkWidget *vbox, *sizebox; /* vbox == main box for widgets,
+ sizebox == box for Entrys & labels
+ for size */
+
+ GtkWidget *button, *textbox; /* generic button followed by textbox
+ for filename */
+
+ GtkWidget *label, *xsize, *ysize; /* stuff for setting size */
+
+ vbox = gtk_vbox_new (FALSE, 3); /* create main box */
+
+ /* create filename textentry */
+
+ textbox = gtk_entry_new ();
+
+ gtk_entry_set_text (GTK_ENTRY (textbox),
+ filename ? filename : "newmap.map");
+
+ gtk_widget_show (textbox);
+
+ gtk_box_pack_start (GTK_BOX (vbox), textbox, FALSE, FALSE, 2);
+
+ /* create save button & link with callback */
+
+ button = gtk_button_new_with_label ("Save");
+
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (save_button), textbox); /* note it gets the filename as data */
+
+ gtk_widget_show (button);
+
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
+
+ /* create the load button & link */
+
+ button = gtk_button_new_with_label ("Load");
+
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (load_button), textbox); /* Also gets callback */
+
+ gtk_widget_show (button);
+
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
+
+ /* create row for size controls -- except actual button */
+
+ sizebox = gtk_hbox_new (FALSE, 1);
+
+ /* X label & text */
+
+ label = gtk_label_new ("X:");
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX (sizebox), label, FALSE, FALSE, 1);
+
+ xsize = gtk_entry_new_with_max_length (3);
+ width_text = GTK_ENTRY (xsize);
+ sprintf (str, "%d", grid.width);
+ gtk_entry_set_text (GTK_ENTRY (xsize), str);
+ gtk_widget_set_usize (xsize, 30, 20);
+ gtk_widget_show (xsize);
+
+ gtk_box_pack_start (GTK_BOX (sizebox), xsize, FALSE, FALSE, 1);
+
+ /* Y label && text */
+
+ label = gtk_label_new ("Y:");
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX (sizebox), label, FALSE, FALSE, 1);
+
+ ysize = gtk_entry_new_with_max_length (3);
+ height_text = GTK_ENTRY (ysize);
+ sprintf (str, "%d", grid.height);
+ gtk_entry_set_text (GTK_ENTRY (ysize), str);
+ gtk_widget_set_usize (ysize, 30, 20);
+ gtk_widget_show (ysize);
+
+ gtk_box_pack_start (GTK_BOX (sizebox), ysize, FALSE, FALSE, 1);
+
+ gtk_widget_show (sizebox);
+ gtk_box_pack_start (GTK_BOX (vbox), sizebox, FALSE, FALSE, 2);
+
+ /* Done size controls */
+
+ /* Actual size button */
+
+ button = gtk_button_new_with_label ("Set Size");
+
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (set_size), NULL);
+
+ gtk_widget_show (button);
+
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
+
+ return vbox; /* return nice simple package */
+}
+
+/* This creates and initialises the toolbox window (actually the MAIN
+ WINDOW)*/
+
+GtkWidget *
+create_toolbox_window (char *filename)
+{
+ GtkWidget *window; /* main window */
+
+ GtkWidget *toolbox, *command_box, *hbox; /* three important components (hbox to store others) */
+
+ grid_window = create_grid_window (); /* map window controlled by
+ this -- needs to be able to
+ load */
+
+ /* Create our window -- its closure causes the app to quit... */
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Toolbox");
+
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL); /* ... as setup on this line */
+
+ /* create and display two panes of display */
+
+ toolbox = create_toolbox_box (window, change_tool);
+ gtk_widget_show (toolbox);
+ command_box = create_command_box (filename);
+ gtk_widget_show (command_box);
+
+ /* join two panes together */
+
+ hbox = gtk_hbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (hbox), toolbox, FALSE, FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (hbox), command_box, FALSE, FALSE, 5);
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (window), hbox);
+
+ /* show window */
+
+ gtk_widget_show (window);
+ return window; /* give it back to main */
+}
+
+/* receives position to change -- puts correct pixmap in place */
+
+/* See Fixed(Wibble1) in create_grid_window for description of fixed */
+
+void
+update_grid (GtkFixed * fixed, int x, int y)
+{
+ int length, i, dx, dy; /* length == how many children are in fixed,
+ i == counter for iteration,
+ dx, dy == How far apart the current position is from the desired one */
+
+ GList *children; /* children of fixed -- i.e. the
+ pixmap widgets */
+
+ GtkFixedChild *child; /* individual child of fixed */
+
+ grid.data[x + y * grid.width] = current_tool;
+
+ /* initialise for search */
+
+ children = fixed->children;
+ length = g_list_length (children);
+
+ /* start finding -- this is a horrible kludge, but the simplest to
+ code */
+
+ for (i = 0; i < length; i++)
+ {
+ child = (GtkFixedChild *) g_list_nth_data (children, i); /* get current thing */
+
+ dx = x - (child->x / IMGSIZE); /* position in pixels -- must be changed to reality */
+
+ dy = y - (child->y / IMGSIZE);
+
+ if (dx == 0 && dy == 0) /* if correct position */
+ {
+ gtk_pixmap_set (GTK_PIXMAP (child->widget),
+ blocks[current_tool].pixmap, NULL); /* change the pixmap */
+
+ break; /* and quit -- don't compound folly */
+ }
+ }
+}
+
+/* handler for drawing -- set dragging true */
+
+void
+button_press (GtkFixed * fixed, GdkEventButton * event, gpointer data)
+{
+ int i, j; /* positions */
+
+ dragging = 1;
+
+ i = (int) (event->x / IMGSIZE);
+ j = (int) (event->y / IMGSIZE);
+
+ update_grid (fixed, i, j); /* set current square so user doesn't
+ have to move mouse */
+}
+
+/* callback for mouse moved on map window -- checks dragging */
+
+/* This is not ideal as it puts extra load on the cpu when the mouse
+ is moving in the map window */
+
+void
+mouse_move (GtkFixed * fixed, GdkEventMotion * event, gpointer data)
+{
+ int i, j;
+
+ i = (int) (event->x / IMGSIZE);
+ j = (int) (event->y / IMGSIZE);
+ if (dragging)
+ update_grid (fixed, i, j);
+}
+
+/* stop drawing */
+
+void
+button_release (GtkFixed * fixed, GdkEventButton * event, gpointer data)
+{
+ dragging = 0;
+}
+
+/* called when user closes window -- sets grid_window to NULL to
+ prevent recreate_grid_window segfaulting */
+
+void
+destroy_func (GtkWidget * widget, gpointer data)
+{
+ *((GtkWidget **) data) = NULL;
+ grid_window = NULL;
+}
+
+/* Does the donkeywork in creating the map view */
+
+GtkWidget *
+create_grid_window ()
+{
+ int i, j, type; /* i, j for iteration through "grid.data",
+ type == index into blocks -- stored
+ for convenience */
+
+ GtkWidget *window; /* actual window */
+ GtkWidget *fixed; /* layout manager for pictures */
+
+ GtkWidget *pixmap; /* temporary sotrage for each picture
+ while in use */
+
+ /* first create and set up main features */
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (destroy_func), &window);
+ gtk_window_set_title (GTK_WINDOW (window), "Map View");
+
+ /* Fixed(Wibble1):
+ fixed is a method of storing widgets by position,
+ 1. I create a sequence of pixmap widgets and place them in correct positions,
+ 2. I initialise them to the correct picture,
+ 3. I link the fixed's press, motion & release events to something to find which
+ pixmap is under pointer and change picture & "grid" */
+
+ fixed = gtk_fixed_new ();
+
+ for (i = 0; i < grid.width; i++)
+ for (j = 0; j < grid.height; j++)
+ {
+ type = grid.data[i + j * grid.width];
+ pixmap = gtk_pixmap_new (blocks[type].pixmap, NULL);
+
+ gtk_fixed_put (GTK_FIXED (fixed), pixmap, i * IMGSIZE, j * IMGSIZE); /* position */
+
+ gtk_widget_show (pixmap);
+ }
+
+ /* enable events needed... */
+
+ gtk_widget_set_events (fixed,
+ GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK);
+
+ /* ... and take control */
+
+ gtk_signal_connect (GTK_OBJECT (fixed), "button_press_event",
+ GTK_SIGNAL_FUNC (button_press), NULL);
+
+ gtk_signal_connect (GTK_OBJECT (fixed), "motion_notify_event",
+ GTK_SIGNAL_FUNC (mouse_move), NULL);
+
+ gtk_signal_connect (GTK_OBJECT (fixed), "button_release_event",
+ GTK_SIGNAL_FUNC (button_release), NULL);
+
+ gtk_widget_show (fixed);
+
+ gtk_container_add (GTK_CONTAINER (window), fixed); /* window only contains pictures */
+
+ gtk_widget_show (window);
+
+ return window; /* give the window back to
+ create_toolbox_window */
+}
+
+/* Free all the rubbish */
+
+void
+freestuff ()
+{
+ g_free (grid.data);
+}
+
+/* Doesn't look very nice but is functional (message box and code) */
+
+void
+message_box (char *title, char *text)
+{
+ GtkWidget *label, *window, *button, *box;
+
+ window = gtk_window_new (GTK_WINDOW_DIALOG); /* make window */
+
+ gtk_window_set_title (GTK_WINDOW (window), title);
+
+ label = gtk_label_new (text); /* Label as required */
+
+ gtk_widget_show (label);
+
+ button = gtk_button_new_with_label ("OK"); /* Just an OK button
+ that kills the
+ window */
+
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ (gpointer) window);
+
+ gtk_widget_show (button);
+
+ box = gtk_vbox_new (FALSE, 3); /* Put everything in... */
+
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+
+ gtk_widget_show (box);
+
+ gtk_container_add (GTK_CONTAINER (window), box);
+
+ gtk_widget_show (window); /* ... and show */
+
+ /* Don't return anything -- no interaction necessary */
+}
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..8983896
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,23 @@
+##
+## doc/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+EXTRA_DIST =\
+ contrib\
+ guile-proj.scm\
+ Robots-HOWTO
+
diff --git a/doc/Robots-HOWTO b/doc/Robots-HOWTO
new file mode 100644
index 0000000..d15a18c
--- /dev/null
+++ b/doc/Robots-HOWTO
@@ -0,0 +1,241 @@
+Robots-HOWTO
+
+Writing programs for GNU Robots
+
+Jim Hall <jhall1@isd.net>
+
+_____________________________________________________________________
+
+Introduction
+_____________________________________________________________________
+
+Hi, and welcome to GNU Robots! I was going to call this file
+`api.txt' but I figured that wouldn't be very helpful. And I can tell
+right off the bat that I'm not just going to talk about the GNU Robots
+programming API. But I will talk about that quite a bit, since it's so
+important to using GNU Robots.
+
+GNU Robots is a game/diversion where you construct a program for a
+little robot, then set him loose and watch him explore a world on his
+own. The robot program is written in Scheme, and is implemented using
+GNU Guile.
+
+GNU Robots is an ideal way to introduce someone to the fundamentals of
+computer programming. Scheme is a very simple language to learn, and
+by writing Scheme programs for GNU Robots, you can immediately enjoy
+the results of your work.
+
+That said, I'll disclose now that I am not, by nature, a Scheme
+programmer. I only picked up a bit of Scheme when I created GNU
+Robots, and I found that the GNU project had created this wonderful
+extension library that is GNU Guile. In order to use my own program,
+I had to learn a bit of Scheme. It wasn't hard. Did I mention that
+Scheme is a simple language to learn?
+
+_____________________________________________________________________
+
+Writing programs
+_____________________________________________________________________
+
+Gosh, what's the best way to introduce computer programming with GNU
+Robots? I guess I'm not the kind of person who can teach someone else
+to do computer programming. So I'll take the easy way out:
+
+Most of writing programs for GNU Robots involves writing Scheme code.
+Remember, your robot program is just a Scheme program. So go buy
+yourself a nice introduction to Scheme book, if you don't already have
+one. Or, if you're a particularly brave person, see what you can pick
+up from the robot examples under the `scheme/' directory.
+
+Scheme is not a difficult language to pick up, both for programmers
+and for those new to programming. I would recommend that you adopt a
+"function" approach to programming a GNU Robot. Many people will
+refer to this as a "divide and conquer" strategy, and I find it works
+well.
+
+What this means is that you will want to identify the basic kinds of
+tasks that a robot can perform, then group those into particular kinds
+of activities. For example, one basic activity for a robot might be
+to pick up something directly in front of it, then move into the space
+that is now empty:
+
+ (define (grab-and-move)
+ (robot-grab)
+ (robot-move 1)
+ )
+
+The `define' statement is from Scheme, and allows us to define a
+function called `grab-and-move'. The function consists of two
+statements: `robot-grab' to pick up a thing immediately in front of
+the robot, and `robot-move' to move the robot a given number of
+spaces.
+
+That was easy. Now, let's try another.
+
+The whole goal of GNU Robots is to get the highest score that you can.
+To increase your score, you need to pick up prizes. So let's create a
+function that allows our little robot to pick up some prizes. We'll
+build on the `grab-and-move' function that we defined above.
+
+ (define (grab-prize)
+ (if (eqv? (robot-feel "prize") #t) (grab-and-move))
+ )
+
+This is not so scary a statement, if we look at it a piece at a time.
+The `eqv?' statement compares the truth value of two expressions. In
+this case, we compare a test expression against a literal true value
+(`#t'). Our test expression is `(robot-feel "prize")' which will
+return a `#t' value if the little robot is able to detect a prize in
+the space immediately in front of it.
+
+If the `eqv?' statement is successful (the two expression are the
+same, or in other words the robot is able to feel a prize in the space
+right in front of it) then Scheme will execute the `grab-and-move'
+function.
+
+In plain English: if the robot detects a prize in the space
+immediately before it, the robot will pick it up, and move forward
+into that space.
+
+But every time you make the little robot take an action, you cause it
+to use energy. To restore its energy levels, it needs to find and
+consume food. So let's create a function similar to the above that
+picks up a food item:
+
+ (define (grab-food)
+ (if (eqv? (robot-feel "food") #t) (grab-and-move))
+ )
+
+As you can see, the `grab-food' function is virtually identical to the
+`grab-prize' function. I don't think you need me to explain the
+difference.
+
+From here, you are on your way to creating a cool robot that you can
+set loose in GNU Robots. It's just a matter of picking up some more
+of the flow control structures like do-while loops and more of the
+if-then tests. Then you'll have a fine robot program to play with.
+
+_____________________________________________________________________
+
+Robot actions
+_____________________________________________________________________
+
+But the question you're probably waiting to have answered is: "What
+can I make the little robot do?" Ah, that's the list of `robot-*'
+functions.
+
+Here is a table of all the GNU Robots functions, called primitives,
+that you can use in your robot program. Each primitive has an energy
+cost associated with it.
+
+Note that some primitives will take an argument, and some will not.
+If an argument is a number, I'll print `N' after the function name.
+If the argument is a GNU Robots "thing" then I'll print `TH' after the
+function name. If the primitive does not take an argument, I will
+print nothing.
+
+ PRIMITIVE ENERGY ACTION
+=====================================================================
+ robot-turn N -2 Turns the robot N spaces to the right
+ or left. If `N' is a positive number,
+ the robot turns to the right. If `N'
+ is negative, the robot turns to the
+ left. Every turn has a cost of -2, so
+ if you `robot-turn 2' then the cost is
+ -4 to your energy.
+---------------------------------------------------------------------
+ robot-move N -2 Moves the robot N spaces forwards or
+ backwards. If `N' is a positive
+ number, the robot moves forwards. If
+ `N' is negative, the robot moves
+ backwards. Every move has a cost of
+ -2, so if you `robot-move 2' then the
+ cost is -4 to your energy.
+---------------------------------------------------------------------
+ robot-smell TH -1 Smells for a thing. If the thing is
+ in the surrounding eight spaces, the
+ function returns a true (`#t') value.
+---------------------------------------------------------------------
+ robot-feel TH -1 Feels for a thing in the space directly
+ in front of the robot. If the thing is
+ detected in that space, the function
+ returns a true (`#t') value. Note that
+ you can feel a baddie, and not take any
+ damage.
+---------------------------------------------------------------------
+ robot-look TH -1 Looks ahead across empty spaces for a
+ particular thing. If the thing is
+ seen, the function return returns a
+ true (`#t') value. Note that this is
+ sort of a braindead function, in that
+ it does not provide the distance to the
+ thing. The robot cannot look behind
+ objects, so if you look for a food
+ item, and there is a prize item in the
+ way, the function returns false.
+---------------------------------------------------------------------
+ robot-grab -5 Attempts to pick up what is in the
+ space directly in front of the little
+ robot. Note that you should not try to
+ pick up baddies or walls. If the item
+ is food, you increase your energy by
+ +10. If the item is a prize, you
+ increase your score by +1. The
+ function returns a true (`#t') if the
+ robot was able to pick the thing up.
+---------------------------------------------------------------------
+ robot-zap -10 Uses the robot's little gun to zap
+ whatever is in the space directly in
+ front of it. If you were able to zap
+ something (a baddie, or even a prize or
+ food) then the function returns a true
+ (`#t') value.
+---------------------------------------------------------------------
+ robot-stop 0 Exits GNU Robots immediately.
+---------------------------------------------------------------------
+ robot-get-shields 0 Returns the level of the little robot's
+ shields.
+---------------------------------------------------------------------
+ robot-get-energy 0 Returns the level of the little robot's
+ energy.
+---------------------------------------------------------------------
+ robot-get-score 0 Returns the robot's score (how many
+ prizes have been picked up.)
+=====================================================================
+
+
+And what kinds of "things" are out there to be detected by
+`robot-smell', `robot-feel' and `robot-look'? Here is a list of all
+possible things in the GNU Robots world:
+
+ THING DESCRIPTION
+=====================================================================
+ baddie A nasty little critter that is generally bad for your
+ health. Either leave these alone, or zap them. Don't try
+ to pick them up, or you will inflict damage to your
+ shields. Don't bump up against them--that doesn't feel
+ too good, either.
+---------------------------------------------------------------------
+ space An empty space. There's nothing interesting here.
+---------------------------------------------------------------------
+ food Yum! A health item that will help to restore +10 points
+ of your robot's energy levels.
+---------------------------------------------------------------------
+ prize Pick these up! This will add +1 point to your score.
+ Remember, the goal of GNU Robots is to get the highest
+ score!
+---------------------------------------------------------------------
+ wall An obstacle. You can't zap these, so you better go around
+ them. Trying to grab a wall does nothing to you, but
+ bumping up against one will inflict damage to your
+ shields.
+=====================================================================
+
+
+_____________________________________________________________________
+
+Go try it!
+_____________________________________________________________________
+
+Okay, that's about all the information you should need to set you on
+the way to writing really cool GNU Robots programs. Have fun!
diff --git a/doc/contrib b/doc/contrib
new file mode 100644
index 0000000..c4c6d74
--- /dev/null
+++ b/doc/contrib
@@ -0,0 +1,20 @@
+CONTRIBUTORS TO GNU ROBOTS:
+_____________________________________________________________________
+
+* Jim Hall, <jhall1@isd.net>
+ author
+
+* Tom Whittock, <shallow@dial.pipex.com>
+ X11 interface
+
+* Tim Northover, tim@pnorthover.freeserve.co.uk
+ mapedit.c (GNU Robots map editor, for GNOME)
+
+* Kyle Hasselbacher <kyle@toehold.com>
+ 'greedy.scm' and 'mapper.scm'
+
+* david.madore@ens.fr
+ Helped fix `configure.in' to detect X Windows
+
+* Steinar Hamre <steinarh@stud.fim.ntnu.no>
+ Patched `configure.in' and several other files to better detect GNU Guile
diff --git a/doc/guile-proj.scm b/doc/guile-proj.scm
new file mode 100644
index 0000000..b07020c
--- /dev/null
+++ b/doc/guile-proj.scm
@@ -0,0 +1,44 @@
+;;;How To Submit A Project
+;;;
+;;;The first thing to do is look at the Guile Project Mail Submission
+;;;doc. This will tell you all you need to know about describing your
+;;;project. Then, send a mail to me (Greg.Harvey@thezone.net) with the
+;;;subject "Guile Project Submission". Optionally, you can send it to
+;;;(Greg.Harvey+guile-project@thezone.net). Please do one or the
+;;;other, or else there's a good chance it'll end up in the spam
+;;;box. The body should contain your submission(s).
+;;;
+;;;How To Update A Project
+;;;
+;;;It's the exact same thing as making the initial submission, but you
+;;;don't have to include every field, just whatever you want
+;;;updated. So, say if you want to add a license field to your
+;;;existing entry, you'd just have ((name "foo") (license "bar")) as a
+;;;submission.
+
+((name "robots")
+
+ (category "Games")
+ (keywords "Game " "robots " "diversion")
+
+ (description "A game/diversion where you construct a robot (using Scheme) "
+ "then set him loose and watch him explore a world on his own."
+ "The GNU Robot program is written in Scheme, and implemented "
+ "using GNU Guile.")
+
+ (location (url "http://www.gnu.org/software/robots/" "GNU Robots homepage"))
+
+ (authors "Jim Hall")
+ (maintainer (email "Jim Hall" "jhall1@isd.net"))
+
+ (status "GNU Robots has finally been released as version 1.0!!")
+
+ (help-wanted "GNU Robots could really use a port to GTK+, for GNOME. "
+ "Also, it would be great if someone wrote a GNU Robots "
+ "code generator, that generated a robot Scheme program "
+ "based on the user contructing a robot program using "
+ "little icons that are dropped into place and ordered "
+ "using special connector wires. This would be a good "
+ "senior project for a computer science student!")
+
+ (license "GPL"))
diff --git a/getopt/Makefile.am b/getopt/Makefile.am
new file mode 100644
index 0000000..a5922a3
--- /dev/null
+++ b/getopt/Makefile.am
@@ -0,0 +1,23 @@
+##
+## getopt/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+EXTRA_DIST =\
+ getopt1.c\
+ getopt.c\
+ getopt.h
+
diff --git a/getopt/getopt.c b/getopt/getopt.c
new file mode 100644
index 0000000..4c77c09
--- /dev/null
+++ b/getopt/getopt.c
@@ -0,0 +1,683 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* NOTE!!! AIX requires this to be the first thing in the file.
+ Do not put ANYTHING before it! */
+#if !defined (__GNUC__) && defined (_AIX)
+#pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#else /* Not GNU C library. */
+#define __alloca alloca
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str) {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ to[i] = from[i];
+}
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) __alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+ my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ my_bcopy ((char *) temp,
+ (char *) &argv[first_nonopt + optind - last_nonopt], nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0) {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-') {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ } else if (optstring[0] == '+') {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ } else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0') {
+ if (ordering == PERMUTE) {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--")) {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc) {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ ) {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ )) {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar)) {
+ if (s - nextchar == strlen (p->name)) {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ } else if (pfound == NULL) {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ } else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact) {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL) {
+ option_index = indfound;
+ optind++;
+ if (*s) {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else {
+ if (opterr) {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ } else if (pfound->has_arg == 1) {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag) {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL) {
+ if (opterr) {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':') {
+ if (opterr) {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':') {
+ if (temp[2] == ':') {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0') {
+ optarg = nextchar;
+ optind++;
+ } else
+ optarg = 0;
+ nextchar = NULL;
+ } else {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0') {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ } else if (optind == argc) {
+ if (opterr) {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ } else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0, (int *) 0, 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/getopt/getopt.h b/getopt/getopt.h
new file mode 100644
index 0000000..4501d46
--- /dev/null
+++ b/getopt/getopt.h
@@ -0,0 +1,128 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+ extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+ extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+ extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+ extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+ struct option
+ {
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+ };
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+ extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+ extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+ extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+ extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts, const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+ extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind, int long_only);
+#else /* not __STDC__ */
+ extern int getopt ();
+ extern int getopt_long ();
+ extern int getopt_long_only ();
+
+ extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/getopt/getopt1.c b/getopt/getopt1.c
new file mode 100644
index 0000000..d0ac2af
--- /dev/null
+++ b/getopt/getopt1.c
@@ -0,0 +1,172 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..bdd9f2d
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,27 @@
+##
+## include/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+EXTRA_DIST =\
+ api.h\
+ configs.h\
+ map.h\
+ main.h\
+ grobot.h\
+ sign.h\
+ userinterface.h
+
diff --git a/include/api.h b/include/api.h
new file mode 100644
index 0000000..e04f27b
--- /dev/null
+++ b/include/api.h
@@ -0,0 +1,43 @@
+/* Robot API for the GNU Robots game */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _API_H
+#define _API_H
+
+#include <glib.h>
+#include <guile/gh.h> /* GNU Guile high */
+
+void api_init (void);
+
+/* Functions */
+SCM api_robot_turn (SCM s_n);
+SCM api_robot_move (SCM s_n);
+SCM api_robot_smell (SCM s_th);
+SCM api_robot_feel (SCM s_th);
+SCM api_robot_look (SCM s_th);
+SCM api_robot_grab (void);
+SCM api_robot_zap (void);
+SCM api_robot_stop (void);
+
+SCM api_robot_get_shields (void);
+SCM api_robot_get_energy (void);
+SCM api_robot_get_score (void);
+
+#endif /* _API_H */
diff --git a/include/configs.h b/include/configs.h
new file mode 100644
index 0000000..b3d5125
--- /dev/null
+++ b/include/configs.h
@@ -0,0 +1,63 @@
+#ifndef CONFIGS_H
+#define CONFIGS_H
+
+#define TILE_SIZE 16
+#undef USE_MITSHM
+
+#ifdef PKGLIBDIR
+#define MODULE_PATH PKGLIBDIR
+#else
+#ifdef ABS_TOP_BUILDDIR
+#define MODULE_PATH ABS_TOP_BUILDDIR "/lib/.libs"
+#else
+#define MODULE_PATH "lib/.libs"
+#endif /* ABS_TOP_BUILDDIR */
+#endif /* PKGLIBDIR */
+
+#ifndef MODULE_PATH_ENV
+# define MODULE_PATH_ENV "GNU_ROBOTS_PLUGIN_PATH"
+#endif
+
+#ifndef MAPS_PATH_ENV
+# define MAPS_PATH_ENV "GNU_ROBOTS_MAPS_PATH"
+#endif
+
+#ifndef SCRIPTS_PATH_ENV
+# define SCRIPTS_PATH_ENV "GNU_ROBOTS_SCRIPTS_PATH"
+#endif
+
+#define MAX_PATH 256
+
+/* Defaults */
+#define DEFAULT_MAP "maze.map"
+#define DEFAULT_SCRIPT "mapper.scm"
+
+/* Symbolic constants */
+#define SPACE ' '
+#define FOOD '+'
+#define PRIZE '$'
+#define WALL '#'
+#define BADDIE '@'
+#define ROBOT 'R'
+
+/* Directions */
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+/* For all displays */
+#define SLEEP_TIME 200 /* in milliseconds */
+#define USLEEP_TIME 200000 /* in microseconds */
+#define USLEEP_MULT 16 /* not used yet --jh */
+
+#define DEFAULT_ENERGY 1000
+#define DEFAULT_SHIELDS 100
+
+#define DEFAULT_MAP_COLUMNS 40
+#define DEFAULT_MAP_ROWS 20
+
+#define PKGINFO PACKAGE_NAME " " VERSION
+#define COPYRIGHT "Copyright (C) 1998,1999,2000 Jim Hall <jhall1@isd.net>"
+
+#endif /* CONFIGS_H */
diff --git a/include/grobot.h b/include/grobot.h
new file mode 100644
index 0000000..1ef0031
--- /dev/null
+++ b/include/grobot.h
@@ -0,0 +1,80 @@
+#ifndef _G_ROBOT_H
+#define _G_ROBOT_H
+/* MACROS */
+
+#include <glib-object.h>
+#include <glib.h>
+#include "userinterface.h"
+#include "map.h"
+
+G_BEGIN_DECLS
+
+extern GType _g_robot_type;
+
+typedef struct _GRobot GRobot;
+
+struct _GRobot {
+ GObject object;
+
+ gint x;
+ gint y;
+ gint dir;
+ glong score;
+ glong energy;
+ glong shields;
+ glong shots;
+ glong units;
+
+ UserInterface *ui;
+ Map *map;
+};
+
+typedef struct _GRobotClass GRobotClass;
+
+struct _GRobotClass {
+ GObjectClass parent_class;
+
+ void (*death) (GRobot *robot);
+};
+
+#define G_TYPE_ROBOT (_g_robot_type)
+#define G_IS_ROBOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_ROBOT))
+#define G_IS_ROBOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_ROBOT))
+#define G_ROBOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_ROBOT, GRobotClass))
+#define G_ROBOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_ROBOT, GRobot))
+#define G_ROBOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_ROBOT, GRobotClass))
+
+/* some convenient macros */
+#define G_ROBOT_POSITION_X(robot) ((robot)->x)
+#define G_ROBOT_POSITION_Y(robot) ((robot)->y)
+
+/* normal GObject stuff */
+GType g_robot_get_type (void);
+
+/* Our object functions */
+GRobot* g_robot_new (int x,
+ int y,
+ int dir,
+ long score,
+ long energy,
+ long shield,
+ long units,
+ long shots,
+ UserInterface *ui,
+ Map *map);
+
+void g_robot_turn (GRobot *robot, gint num_turns);
+gboolean g_robot_move (GRobot *robot, gint steps);
+gboolean g_robot_smell (GRobot *robot, gchar *str);
+gboolean g_robot_feel (GRobot *robot, gchar *str);
+gboolean g_robot_look (GRobot *robot, gchar *str);
+gboolean g_robot_grab (GRobot *robot);
+gboolean g_robot_zap (GRobot *robot);
+gboolean g_robot_stop (GRobot *robot);
+glong g_robot_get_shields (GRobot *robot);
+glong g_robot_get_energy (GRobot *robot);
+glong g_robot_get_score (GRobot *robot);
+
+G_END_DECLS
+
+#endif
diff --git a/include/main.h b/include/main.h
new file mode 100644
index 0000000..d09ac65
--- /dev/null
+++ b/include/main.h
@@ -0,0 +1,10 @@
+/* Functions */
+
+#include <glib.h>
+#include <grobot.h>
+
+void main_prog (void *closure, gint argc, gchar *argv[]);
+void death (GRobot *robot);
+void exit_nicely (void);
+void usage (const gchar *argv0);
+gint is_file (const gchar *filename);
diff --git a/include/map.h b/include/map.h
new file mode 100644
index 0000000..8818030
--- /dev/null
+++ b/include/map.h
@@ -0,0 +1,57 @@
+#ifndef _MAP_H
+#define _MAP_H
+/* MACROS */
+
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+extern GType _map_type;
+
+typedef struct
+{
+ gint num_rows;
+ gint num_cols;
+} MapSize;
+
+typedef struct _Map Map;
+
+struct _Map {
+ GObject object;
+
+ /* The actual Map */
+ gint **_map;
+ MapSize size;
+
+ gint errors;
+};
+
+typedef struct _MapClass MapClass;
+
+struct _MapClass {
+ GObjectClass parent_class;
+};
+
+#define G_TYPE_MAP (_map_type)
+#define G_IS_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_MAP))
+#define G_IS_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_MAP))
+#define MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_MAP, MapClass))
+#define MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_MAP, Map))
+#define MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_MAP, MapClass))
+
+/* some convenient macros */
+#define MAP_GET_OBJECT(map, x, y) ((map)->_map[(y)][(x)])
+#define MAP_SET_OBJECT(map, x, y, thing) ((map)->_map[(y)][(x)] = thing)
+
+/* normal GObject stuff */
+GType map_get_type (void);
+
+/* Our object functions */
+Map* map_new_from_file (const gchar *map,
+ gint num_rows,
+ gint num_cols);
+
+G_END_DECLS
+
+#endif
diff --git a/include/sign.h b/include/sign.h
new file mode 100644
index 0000000..f98c6c1
--- /dev/null
+++ b/include/sign.h
@@ -0,0 +1,3 @@
+#include <glib.h>
+
+gint sign (gint n);
diff --git a/include/userinterface.h b/include/userinterface.h
new file mode 100644
index 0000000..ba5ade9
--- /dev/null
+++ b/include/userinterface.h
@@ -0,0 +1,211 @@
+/* $Id: userinterface.h,v 1.7 2005/09/06 19:55:40 zeenix Exp $ */
+
+/* GNU Robots game engine. This is the header file for user_interface module */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __USER_INTERFACE_H__
+#define __USER_INTERFACE_H__
+
+#include <glib-object.h>
+#include "map.h"
+
+G_BEGIN_DECLS
+
+extern GType _user_interface_type;
+
+typedef struct _UserInterface UserInterface;
+typedef struct _UserInterfaceClass UserInterfaceClass;
+
+struct _UserInterfaceClass {
+ GTypeInterface parent;
+
+ void (* user_interface_add_thing) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing);
+
+ void (* user_interface_draw) (UserInterface *ui);
+
+ void (* user_interface_update_status) (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_move_robot) (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_robot_smell) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_robot_zap) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_robot_feel) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_robot_grab) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+ void (* user_interface_robot_look) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+/* routines to get/display data from/to user */
+ void (* user_interface_get_string) (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len);
+};
+
+#define G_TYPE_USER_INTERFACE (_user_interface_type)
+#define G_IS_USER_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_USER_INTERFACE))
+#define G_IS_USER_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_USER_INTERFACE))
+#define USER_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_USER_INTERFACE, UserInterfaceClass))
+#define USER_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_USER_INTERFACE, UserInterface))
+#define USER_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_USER_INTERFACE, UserInterfaceClass))
+
+/* normal GObject stuff */
+GType user_interface_get_type (void);
+
+/* functions we want implemented by the implementers of our interface */
+void user_interface_add_thing (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing);
+
+void user_interface_draw (UserInterface *ui);
+
+void user_interface_update_status (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_move_robot (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_robot_smell (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_robot_zap (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_robot_feel (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_robot_grab (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+void user_interface_robot_look (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields);
+
+/* routines to get/display data from/to user */
+void user_interface_get_string (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len);
+
+typedef UserInterface * (* UserInterfaceInitFunc) (Map *map,
+ GType parent_type);
+#define USER_INTERFACE_INIT_FUNCTION "user_interface_new"
+
+G_END_DECLS
+
+#endif /* __USER_INTERFACE_H__*/
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..f3d6283
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,48 @@
+##
+## lib/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+SUBDIRS = xpm
+
+if USE_CURSES
+CURSES_PLUGIN=libgrobots-curses.la
+else
+CURSES_PLUGIN=
+endif
+
+if USE_X11
+X11_PLUGIN=libgrobots-x11.la
+else
+X11_PLUGIN=
+endif
+
+INCLUDES = $(GLIB2_CFLAGS) $(CURSES_CFLAGS) $(X_FLAGS) -I$(top_builddir)/include
+
+pkglib_LTLIBRARIES = libgrobots-text.la $(CURSES_PLUGIN) $(X11_PLUGIN)
+
+libgrobots_text_la_SOURCES = textplugin.c
+libgrobots_text_la_LDFLAGS = -module -avoid-version
+libgrobots_text_la_LIBADD = $(GLIB2_LIBS)
+
+libgrobots_curses_la_SOURCES = cursesplugin.c
+libgrobots_curses_la_LDFLAGS = -module -avoid-version
+libgrobots_curses_la_LIBADD = $(GLIB2_LIBS) $(CURSES_LIBS)
+
+libgrobots_x11_la_SOURCES = x11plugin.c
+libgrobots_x11_la_LDFLAGS = -module -avoid-version
+libgrobots_x11_la_LIBADD = $(GLIB2_LIBS) $(X_LIBS)
+
diff --git a/lib/cursesplugin.c b/lib/cursesplugin.c
new file mode 100644
index 0000000..a3f08ad
--- /dev/null
+++ b/lib/cursesplugin.c
@@ -0,0 +1,599 @@
+/* $Id: cursesplugin.c,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include "configs.h"
+#include "cursesplugin.h"
+
+enum
+{
+ ARG_0,
+ ARG_MAP
+};
+
+GType _curses_plugin_type = 0;
+static GType _parent_type = 0;
+
+static void curses_plugin_class_init (CursesPluginClass * klass);
+static void curses_plugin_init (GObject * object);
+static void curses_plugin_interface_init (gpointer g_iface, gpointer iface_data);
+
+static GObject * curses_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
+
+static void curses_plugin_finalize (GObject * object);
+static void curses_plugin_dispose (GObject * object);
+
+static void curses_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void curses_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+inline void curses_plugin_update_status (CursesPlugin *curses,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+curses_plugin_get_type (void)
+{
+ if (!_curses_plugin_type) {
+ static const GTypeInfo object_info = {
+ sizeof (CursesPluginClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) curses_plugin_class_init,
+ NULL,
+ NULL,
+ sizeof (CursesPlugin),
+ 0,
+ (GInstanceInitFunc) curses_plugin_init,
+ NULL
+ };
+
+ static const GInterfaceInfo interface_info = {
+ (GInterfaceInitFunc) curses_plugin_interface_init,
+ NULL,
+ NULL
+ };
+
+ _curses_plugin_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "CursesPlugin",
+ &object_info,
+ 0);
+
+ g_type_add_interface_static (_curses_plugin_type,
+ _parent_type,
+ &interface_info);
+ }
+
+ return _curses_plugin_type;
+}
+
+static void
+curses_plugin_class_init (CursesPluginClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->constructor = curses_plugin_constructor;
+ gobject_class->set_property = curses_plugin_set_property;
+ gobject_class->get_property = curses_plugin_get_property;
+ gobject_class->dispose = curses_plugin_dispose;
+ gobject_class->finalize = curses_plugin_finalize;
+
+ g_object_class_override_property (gobject_class, ARG_MAP, "map");
+}
+
+static void
+curses_plugin_init (GObject * object)
+{
+ CursesPlugin *curses = CURSES_PLUGIN (object);
+
+ curses->map = NULL;
+ curses->map_size = NULL;
+}
+
+static GObject *
+curses_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ CursesPlugin *curses;
+
+ /* Chain up to the parent first */
+ object = parent_class->constructor (type, n_construct_properties, construct_properties);
+
+ curses = CURSES_PLUGIN (object);
+
+ /* Initialize curses mode */
+ gint color_pair;
+
+ curses->win = initscr ();
+
+ cbreak ();
+ noecho ();
+
+ scrollok (curses->win, TRUE); /* Put scrolling on */
+ setscrreg (LINES - 2, LINES - 1); /* Where to scroll */
+
+ //clearok (stdscr, TRUE);
+ nonl ();
+ intrflush (stdscr, FALSE);
+ keypad (stdscr, TRUE);
+
+ if (has_colors()) {
+ start_color();
+
+ /*
+ * Simple color assignment, often all we need.
+ **/
+ init_pair (COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
+ init_pair (COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
+ init_pair (COLOR_RED, COLOR_RED, COLOR_BLACK);
+ init_pair (COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
+ init_pair (COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
+ init_pair (COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
+ init_pair (COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
+ init_pair (COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
+ }
+
+ clear ();
+ refresh ();
+ curses->errors = 0;
+
+ return object;
+}
+
+static void
+curses_plugin_dispose (GObject * object)
+{
+ CursesPlugin *curses = CURSES_PLUGIN (object);
+
+ if (curses->map != NULL) {
+ g_object_unref (G_OBJECT (curses->map));
+
+ if (curses->map_size != NULL) {
+ g_free (curses->map_size);
+ }
+ }
+
+ parent_class->dispose (object);
+}
+
+/* finalize is called when the object has to free its resources */
+static void
+curses_plugin_finalize (GObject * object)
+{
+ /* End curses mode */
+ endwin ();
+
+ parent_class->finalize (object);
+}
+
+static void
+curses_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ CursesPlugin *curses;
+ GObject *obj;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_CURSES_PLUGIN (object));
+
+ curses = CURSES_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ obj = g_value_get_object (value);
+ g_return_if_fail (obj != NULL);
+
+ if (curses->map != NULL) {
+ g_object_unref (curses->map);
+ }
+
+ curses->map = MAP (g_object_ref (obj));
+
+ if (curses->map_size != NULL) {
+ g_free (curses->map_size);
+ }
+
+ g_object_get (G_OBJECT (curses->map),
+ "size", &curses->map_size,
+ NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+curses_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ CursesPlugin *curses;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_CURSES_PLUGIN (object));
+
+ curses = CURSES_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ g_value_set_object (value, g_object_ref (G_OBJECT (curses->map)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+UserInterface *
+user_interface_new (Map *map, GType parent_type)
+{
+ g_return_val_if_fail (map != NULL, NULL);
+ g_return_val_if_fail (_parent_type != 0 || parent_type != 0, NULL);
+
+ if (!_parent_type) {
+ _parent_type = parent_type;
+ }
+
+ CursesPlugin *curses =
+ CURSES_PLUGIN (g_object_new (curses_plugin_get_type (),
+ "map", map,
+ NULL));
+ if (curses->errors) {
+ g_object_unref (G_OBJECT (curses));
+ return NULL;
+ }
+
+ return USER_INTERFACE (curses);
+}
+
+inline void curses_plugin_add_thing (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint thing)
+{
+ gshort color;
+
+ /* Highlight the unusual chars */
+ if (thing == '?') {
+ standout ();
+ }
+
+ switch (thing) {
+ case SPACE:
+ color = COLOR_PAIR (COLOR_BLACK);
+ break;
+ case FOOD:
+ color = COLOR_PAIR (COLOR_GREEN);
+ break;
+ case PRIZE:
+ color = COLOR_PAIR (COLOR_YELLOW);
+ break;
+ case WALL:
+ color = COLOR_PAIR (COLOR_WHITE);
+ break;
+ case BADDIE:
+ color = COLOR_PAIR (COLOR_RED);
+ break;
+ case ROBOT:
+ color = COLOR_PAIR (COLOR_BLUE);
+ break;
+ default:
+ /* What here? */
+ color = COLOR_PAIR (COLOR_BLACK);
+ }
+
+ mvaddch (y, x, thing | color);
+
+ if (thing == '?') {
+ standend ();
+ }
+
+ redrawwin (curses->win);
+}
+
+inline void curses_plugin_draw (CursesPlugin *curses)
+{
+ gshort color;
+ gint i, j;
+
+ /* Draw the map for the GNU Robots game. */
+
+ for (j = 0; j < curses->map_size->num_rows; j++) {
+ for (i = 0; i < curses->map_size->num_cols; i++) {
+ /* Special cases */
+
+ switch (MAP_GET_OBJECT (curses->map, i, j)) {
+ case '\0':
+ /* Highlight the unusual chars */
+ if (MAP_GET_OBJECT (curses->map, i, j) == '?') {
+ standout ();
+ }
+ color = COLOR_PAIR (COLOR_BLACK);
+ break;
+ case SPACE:
+ color = COLOR_PAIR (COLOR_BLACK);
+ break;
+ case FOOD:
+ color = COLOR_PAIR (COLOR_GREEN);
+ break;
+ case PRIZE:
+ color = COLOR_PAIR (COLOR_YELLOW);
+ break;
+ case WALL:
+ color = COLOR_PAIR (COLOR_WHITE);
+ break;
+ case BADDIE:
+ color = COLOR_PAIR (COLOR_RED);
+ break;
+ case ROBOT:
+ color = COLOR_PAIR (COLOR_BLUE);
+ break;
+ default:
+ /* What here? */
+ color = COLOR_PAIR (COLOR_BLACK);
+ break;
+ } /* switch */
+
+ mvaddch (j, i, MAP_GET_OBJECT (curses->map, i, j) | color);
+
+ if (MAP_GET_OBJECT (curses->map, i, j) == '?') {
+ standend ();
+ }
+ } /* for i */
+ } /* for j */
+
+ redrawwin (curses->win);
+}
+
+inline void curses_plugin_move_robot (CursesPlugin *curses,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ /* Clear previous tile */
+
+ mvaddch (from_y, from_x, ' ' | COLOR_PAIR (COLOR_BLACK));
+
+ standout ();
+ switch (cdir) {
+ case NORTH:
+ mvaddch (to_y, to_x, '^' | COLOR_PAIR (COLOR_BLUE));
+ break;
+ case EAST:
+ mvaddch (to_y, to_x, '>' | COLOR_PAIR (COLOR_BLUE));
+ break;
+ case SOUTH:
+ mvaddch (to_y, to_x, 'v' | COLOR_PAIR (COLOR_BLUE));
+ break;
+ case WEST:
+ mvaddch (to_y, to_x, '<' | COLOR_PAIR (COLOR_BLUE));
+ break;
+ }
+
+ standend ();
+ refresh ();
+
+ g_usleep (USLEEP_TIME);
+}
+
+/* function to animate the robot */
+inline void curses_plugin_robot_smell (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ curses_plugin_update_status (curses, "robot smells...", energy, score, shields);
+}
+
+inline void curses_plugin_robot_zap (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ curses_plugin_update_status (curses, "robot fires his little gun...", energy, score, shields);
+}
+
+inline void curses_plugin_robot_feel (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ curses_plugin_update_status (curses, "robot feels for a thing...", energy, score, shields);
+}
+
+inline void curses_plugin_robot_grab (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ curses_plugin_update_status (curses, "robot grabs thing...", energy, score, shields);
+}
+
+inline void curses_plugin_robot_look (CursesPlugin *curses,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ curses_plugin_update_status (curses, "robot looks for a thing...", energy, score, shields);
+}
+
+/* function to get data from user */
+inline void curses_plugin_get_string (CursesPlugin *curses,
+ gchar *prompt,
+ gchar *buff,
+ gint len)
+{
+ mvaddstr (LINES - 2, 0, prompt);
+ refresh ();
+
+ echo ();
+ getnstr (buff, len);
+ noecho ();
+
+ move (LINES - 2, 0);
+ clrtoeol ();
+ refresh ();
+}
+
+inline void curses_plugin_update_status (CursesPlugin *curses,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ /* print on mode line (y=LINES-1) */
+ mvaddstr (LINES - 1, 1, s);
+ refresh ();
+
+ /* Sleep, then erase it */
+ napms (SLEEP_TIME);
+
+ move (LINES - 1, 1);
+ clrtoeol ();
+ refresh ();
+}
+
+static void curses_plugin_interface_init (gpointer g_iface, gpointer iface_data)
+{
+ UserInterfaceClass *klass = (UserInterfaceClass *)g_iface;
+
+ klass->user_interface_add_thing = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing))
+ curses_plugin_add_thing;
+
+ klass->user_interface_draw = (void (*) (UserInterface *ui)) curses_plugin_draw;
+ klass->user_interface_update_status = (void (*) (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_update_status;
+ klass->user_interface_move_robot = (void (*) (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_move_robot;
+ klass->user_interface_robot_smell = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_robot_smell;
+ klass->user_interface_robot_zap = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_robot_zap;
+ klass->user_interface_robot_feel = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_robot_grab;
+ klass->user_interface_robot_grab = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_robot_grab;
+ klass->user_interface_robot_look = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ curses_plugin_robot_look;
+ klass->user_interface_get_string = (void (*) (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len))
+ curses_plugin_get_string;
+}
diff --git a/lib/cursesplugin.h b/lib/cursesplugin.h
new file mode 100644
index 0000000..7f72d0e
--- /dev/null
+++ b/lib/cursesplugin.h
@@ -0,0 +1,69 @@
+/* $Id: cursesplugin.h,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CURSES_PLUGIN_H__
+#define __CURSES_PLUGIN_H__
+
+#include <glib-object.h>
+#include <curses.h>
+#include <stdio.h>
+#include <stdlib.h> /* for sleep */
+#include "configs.h"
+#include "userinterface.h"
+#include "map.h"
+
+G_BEGIN_DECLS
+
+extern GType _curses_plugin_type;
+
+typedef struct _CursesPlugin CursesPlugin;
+
+struct _CursesPlugin {
+ GObject object;
+ Map *map;
+ MapSize *map_size;
+ gint errors;
+
+ WINDOW *win;
+};
+
+typedef struct _CursesPluginClass CursesPluginClass;
+
+struct _CursesPluginClass {
+ GObjectClass parent_class;
+};
+
+#define G_TYPE_CURSES_PLUGIN (_curses_plugin_type)
+#define G_IS_CURSES_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_CURSES_PLUGIN))
+#define G_IS_CURSES_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_CURSES_PLUGIN))
+#define CURSES_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_CURSES_PLUGIN, CursesPluginClass))
+#define CURSES_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_CURSES_PLUGIN, CursesPlugin))
+#define CURSES_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_CURSES_PLUGIN, CursesPluginClass))
+
+/* normal GObject stuff */
+GType curses_plugin_get_type (void);
+
+CursesPlugin* curses_plugin_new (void);
+
+G_END_DECLS
+
+#endif /* __CURSES_PLUGIN_H__*/
diff --git a/lib/textplugin.c b/lib/textplugin.c
new file mode 100644
index 0000000..32a5a56
--- /dev/null
+++ b/lib/textplugin.c
@@ -0,0 +1,444 @@
+/* $Id: textplugin.c,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include "configs.h"
+#include "textplugin.h"
+
+enum
+{
+ ARG_0,
+ ARG_MAP
+};
+
+GType _text_plugin_type = 0;
+static GType _parent_type = 0;
+
+static void text_plugin_class_init (TextPluginClass * klass);
+static void text_plugin_init (GObject * object);
+static void text_plugin_interface_init (gpointer g_iface, gpointer iface_data);
+
+static GObject * text_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
+
+static void text_plugin_finalize (GObject * object);
+static void text_plugin_dispose (GObject * object);
+
+static void text_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void text_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+inline void text_plugin_update_status (TextPlugin *text,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields);
+
+static GObjectClass *parent_class = NULL;
+
+/* For translation of directions to strings */
+static gchar *str_dir[] = { "North", "East", "South", "West" };
+
+GType
+text_plugin_get_type (void)
+{
+ if (!_text_plugin_type) {
+ static const GTypeInfo object_info = {
+ sizeof (TextPluginClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) text_plugin_class_init,
+ NULL,
+ NULL,
+ sizeof (TextPlugin),
+ 0,
+ (GInstanceInitFunc) text_plugin_init,
+ NULL
+ };
+
+ static const GInterfaceInfo interface_info = {
+ (GInterfaceInitFunc) text_plugin_interface_init,
+ NULL,
+ NULL
+ };
+
+ _text_plugin_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "TextPlugin",
+ &object_info,
+ 0);
+
+ g_type_add_interface_static (_text_plugin_type,
+ _parent_type,
+ &interface_info);
+ }
+
+ return _text_plugin_type;
+}
+
+static void
+text_plugin_class_init (TextPluginClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->constructor = text_plugin_constructor;
+ gobject_class->set_property = text_plugin_set_property;
+ gobject_class->get_property = text_plugin_get_property;
+ gobject_class->dispose = text_plugin_dispose;
+ gobject_class->finalize = text_plugin_finalize;
+
+ g_object_class_override_property (gobject_class, ARG_MAP, "map");
+}
+
+static void
+text_plugin_init (GObject * object)
+{
+ TextPlugin *text = TEXT_PLUGIN (object);
+
+ text->map = NULL;
+ text->map_size = NULL;
+}
+
+static GObject *
+text_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+
+ /* Chain up to the parent first */
+ object = parent_class->constructor (type, n_construct_properties, construct_properties);
+
+ g_printf ("GNU Robots starting..\n");
+
+ return object;
+}
+
+static void
+text_plugin_dispose (GObject * object)
+{
+ TextPlugin *text = TEXT_PLUGIN (object);
+
+ if (text->map != NULL) {
+ g_object_unref (G_OBJECT (text->map));
+
+ if (text->map_size != NULL) {
+ g_free (text->map_size);
+ }
+ }
+
+ parent_class->dispose (object);
+}
+
+/* finalize is called when the object has to free its resources */
+static void
+text_plugin_finalize (GObject * object)
+{
+ g_printf ("GNU Robots done.\n");
+
+ parent_class->finalize (object);
+}
+
+static void
+text_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ TextPlugin *text;
+ GObject *obj;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_TEXT_PLUGIN (object));
+
+ text = TEXT_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ obj = g_value_get_object (value);
+ g_return_if_fail (obj != NULL);
+
+ if (text->map != NULL) {
+ g_object_unref (text->map);
+ }
+
+ text->map = MAP (g_object_ref (obj));
+
+ if (text->map_size != NULL) {
+ g_free (text->map_size);
+ }
+
+ g_object_get (G_OBJECT (text->map),
+ "size", &text->map_size,
+ NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+text_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ TextPlugin *text;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_TEXT_PLUGIN (object));
+
+ text = TEXT_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ g_value_set_object (value, g_object_ref (G_OBJECT (text->map)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+UserInterface *
+user_interface_new (Map *map, GType parent_type)
+{
+ g_return_val_if_fail (map != NULL, NULL);
+ g_return_val_if_fail (_parent_type != 0 || parent_type != 0, NULL);
+
+ if (!_parent_type) {
+ _parent_type = parent_type;
+ }
+
+ TextPlugin *text =
+ TEXT_PLUGIN (g_object_new (text_plugin_get_type (),
+ "map", map,
+ NULL));
+ if (text->errors) {
+ g_object_unref (G_OBJECT (text));
+ return NULL;
+ }
+
+ return USER_INTERFACE (text);
+}
+
+inline void text_plugin_add_thing (TextPlugin *text,
+ gint x,
+ gint y,
+ gint thing)
+{
+ g_printf ("thing `%c' added at %d,%d\n", thing, x, y);
+}
+
+inline void text_plugin_draw (TextPlugin *text)
+{
+ gint i, j;
+
+ for (j = 0; j < text->map_size->num_rows; j++) {
+ for (i = 0; i < text->map_size->num_cols; i++) {
+ g_printf ("thing `%c' added at %d,%d\n", MAP_GET_OBJECT (text->map, i, j), i, j);
+ }
+ }
+}
+
+inline void text_plugin_move_robot (TextPlugin *text,
+ gint from_x,
+ gint from_y,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("robot now at %d,%d facing %s\n", x, y, str_dir[cdir]);
+}
+
+/* function to animate the robot */
+inline void text_plugin_robot_smell (TextPlugin *text,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("the robot sniffs..\n");
+}
+
+inline void text_plugin_robot_zap (TextPlugin *text,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("robot fires gun at space %d,%d\n", x_to, y_to);
+}
+
+inline void text_plugin_robot_feel (TextPlugin *text,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("robot feels space %d,%d\n", x_to, y_to);
+}
+
+inline void text_plugin_robot_grab (TextPlugin *text,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("robot grabs for space %d,%d\n", x_to, y_to);
+}
+
+inline void text_plugin_robot_look (TextPlugin *text,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ g_printf ("robot looks towards %s from %d,%d\n", str_dir[cdir], x, y);
+}
+
+/* function to get data from user */
+inline void text_plugin_get_string (TextPlugin *text,
+ gchar *prompt,
+ gchar *buff,
+ gint len)
+{
+ fputs (prompt, stdout);
+ fgets (buff, len, stdin);
+}
+
+inline void text_plugin_update_status (TextPlugin *text,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ puts (s);
+}
+
+static void text_plugin_interface_init (gpointer g_iface, gpointer iface_data)
+{
+ UserInterfaceClass *klass = (UserInterfaceClass *)g_iface;
+
+ klass->user_interface_add_thing = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing))
+ text_plugin_add_thing;
+
+ klass->user_interface_draw = (void (*) (UserInterface *ui)) text_plugin_draw;
+ klass->user_interface_update_status = (void (*) (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_update_status;
+ klass->user_interface_move_robot = (void (*) (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_move_robot;
+ klass->user_interface_robot_smell = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_robot_smell;
+ klass->user_interface_robot_zap = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_robot_zap;
+ klass->user_interface_robot_feel = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_robot_grab;
+ klass->user_interface_robot_grab = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_robot_grab;
+ klass->user_interface_robot_look = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ text_plugin_robot_look;
+ klass->user_interface_get_string = (void (*) (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len))
+ text_plugin_get_string;
+}
diff --git a/lib/textplugin.h b/lib/textplugin.h
new file mode 100644
index 0000000..fd9eb7b
--- /dev/null
+++ b/lib/textplugin.h
@@ -0,0 +1,63 @@
+/* $Id: textplugin.h,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __TEXT_PLUGIN_H__
+#define __TEXT_PLUING_H__
+
+#include <glib-object.h>
+#include "userinterface.h"
+#include "map.h"
+
+G_BEGIN_DECLS
+
+extern GType _text_plugin_type;
+
+typedef struct _TextPlugin TextPlugin;
+
+struct _TextPlugin {
+ GObject object;
+ Map *map;
+ MapSize *map_size;
+ gint errors;
+};
+
+typedef struct _TextPluginClass TextPluginClass;
+
+struct _TextPluginClass {
+ GObjectClass parent_class;
+};
+
+#define G_TYPE_TEXT_PLUGIN (_text_plugin_type)
+#define G_IS_TEXT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_TEXT_PLUGIN))
+#define G_IS_TEXT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_TEXT_PLUGIN))
+#define TEXT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_TEXT_PLUGIN, TextPluginClass))
+#define TEXT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_TEXT_PLUGIN, TextPlugin))
+#define TEXT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_TEXT_PLUGIN, TextPluginClass))
+
+/* normal GObject stuff */
+GType text_plugin_get_type (void);
+
+TextPlugin* text_plugin_new (void);
+
+G_END_DECLS
+
+#endif /* __TEXT_PLUGIN_H__*/
diff --git a/lib/x11plugin.c b/lib/x11plugin.c
new file mode 100644
index 0000000..d40efd9
--- /dev/null
+++ b/lib/x11plugin.c
@@ -0,0 +1,840 @@
+/* $Id: x11plugin.c,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include "configs.h"
+#include "x11plugin.h"
+
+enum
+{
+ ARG_0,
+ ARG_MAP
+};
+
+GType _x11_plugin_type = 0;
+static GType _parent_type = 0;
+
+static void x11_plugin_class_init (X11PluginClass * klass);
+static void x11_plugin_init (GObject * object);
+static void x11_plugin_interface_init (gpointer g_iface, gpointer iface_data);
+
+static GObject * x11_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
+
+static void x11_plugin_finalize (GObject * object);
+static void x11_plugin_dispose (GObject * object);
+
+static void x11_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void x11_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void put_tile (X11Plugin *x11, XImage *image, gint x, gint y);
+static void put_winbuf (X11Plugin *x11);
+static void setup_winbuf (X11Plugin *x11);
+void create_image (X11Plugin *x11, gchar **data, XImage ** image);
+inline void x11_plugin_update_status (X11Plugin *x11,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+x11_plugin_get_type (void)
+{
+ if (!_x11_plugin_type) {
+ static const GTypeInfo object_info = {
+ sizeof (X11PluginClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) x11_plugin_class_init,
+ NULL,
+ NULL,
+ sizeof (X11Plugin),
+ 0,
+ (GInstanceInitFunc) x11_plugin_init,
+ NULL
+ };
+
+ static const GInterfaceInfo interface_info = {
+ (GInterfaceInitFunc) x11_plugin_interface_init,
+ NULL,
+ NULL
+ };
+
+ _x11_plugin_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "X11Plugin",
+ &object_info,
+ 0);
+
+ g_type_add_interface_static (_x11_plugin_type,
+ _parent_type,
+ &interface_info);
+ }
+
+ return _x11_plugin_type;
+}
+
+static void
+x11_plugin_class_init (X11PluginClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->constructor = x11_plugin_constructor;
+ gobject_class->set_property = x11_plugin_set_property;
+ gobject_class->get_property = x11_plugin_get_property;
+ gobject_class->dispose = x11_plugin_dispose;
+ gobject_class->finalize = x11_plugin_finalize;
+
+ g_object_class_override_property (gobject_class, ARG_MAP, "map");
+}
+
+static void
+x11_plugin_init (GObject * object)
+{
+ X11Plugin *x11 = X11_PLUGIN (object);
+
+ x11->map = NULL;
+ x11->map_size = NULL;
+}
+
+static GObject *
+x11_plugin_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ /* Initialize X11 */
+ GObject *object;
+ X11Plugin *x11;
+#include "xpm/statusbar.xpm"
+#include "xpm/space.xpm"
+#include "xpm/food.xpm"
+#include "xpm/wall.xpm"
+#include "xpm/prize.xpm"
+#include "xpm/baddie.xpm"
+#include "xpm/robot_north.xpm"
+#include "xpm/robot_east.xpm"
+#include "xpm/robot_south.xpm"
+#include "xpm/robot_west.xpm"
+#include "xpm/robot.xpm"
+ Atom prots[6];
+ XClassHint classhint;
+ XWMHints wmhints;
+ XGCValues values;
+ Atom delete_win;
+ gint x;
+
+ /* Chain up to the parent first */
+ object = parent_class->constructor (type, n_construct_properties, construct_properties);
+
+ x11 = X11_PLUGIN (object);
+
+ if ((x11->dpy = XOpenDisplay ("")) == NULL) {
+ g_printf ("Couldn't open the X Server Display!\n");
+ exit (1); /* Exit nicely isn't needed yet, and causes segfault */
+ }
+
+ delete_win = XInternAtom (x11->dpy, "WM_DELETE_WINDOW", False);
+
+ x11->win_width = x11->map_size->num_cols * TILE_SIZE;
+ x11->win_height = x11->map_size->num_rows * TILE_SIZE + 32;
+ x11->x_win = XCreateSimpleWindow (x11->dpy, DefaultRootWindow (x11->dpy), 0, 0,
+ x11->win_width, x11->win_height, 0, 0, 0);
+
+ prots[0] = delete_win;
+ XSetWMProtocols (x11->dpy, x11->x_win, prots, 1);
+
+ XStoreName (x11->dpy, x11->x_win, "GNU Robots");
+
+ classhint.res_name = "robots";
+ classhint.res_class = "Robots";
+ XSetClassHint (x11->dpy, x11->x_win, &classhint);
+
+ /* XSetCommand() seems to segfault... */
+
+ wmhints.input = True;
+ wmhints.flags = InputHint;
+ XSetWMHints (x11->dpy, x11->x_win, &wmhints);
+
+ XSelectInput (x11->dpy, x11->x_win,
+ KeyPressMask | KeyReleaseMask | StructureNotifyMask | FocusChangeMask);
+
+ XMapWindow (x11->dpy, x11->x_win);
+
+ x11->text = XLoadFont (x11->dpy, "-*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*");
+ values.font = x11->text;
+ values.foreground = WhitePixel (x11->dpy, DefaultScreen (x11->dpy));
+
+ x11->gc = XCreateGC (x11->dpy, x11->x_win, GCFont | GCForeground, &values);
+
+ create_image (x11, statusbar_xpm, &x11->statusbar);
+ create_image (x11, space_xpm, &x11->space);
+ create_image (x11, food_xpm, &x11->food);
+ create_image (x11, wall_xpm, &x11->wall);
+ create_image (x11, prize_xpm, &x11->prize);
+ create_image (x11, baddie_xpm, &x11->baddie);
+ create_image (x11, robot_north_xpm, &x11->robotDirs[0]);
+ create_image (x11, robot_east_xpm, &x11->robotDirs[1]);
+ create_image (x11, robot_south_xpm, &x11->robotDirs[2]);
+ create_image (x11, robot_west_xpm, &x11->robotDirs[3]);
+ create_image (x11, robot_xpm, &x11->robotPix);
+
+ setup_winbuf (x11);
+
+ //update_status ("Welcome to GNU Robots");
+ x11->errors = 0;
+
+ return object;
+}
+
+static void
+x11_plugin_dispose (GObject * object)
+{
+ X11Plugin *x11 = X11_PLUGIN (object);
+
+ if (x11->map != NULL) {
+ g_object_unref (G_OBJECT (x11->map));
+
+ if (x11->map_size != NULL) {
+ g_free (x11->map_size);
+ }
+ }
+
+ parent_class->dispose (object);
+}
+
+/* finalize is called when the object has to free its resources */
+static void
+x11_plugin_finalize (GObject * object)
+{
+ X11Plugin *x11 = X11_PLUGIN (object);
+
+ /* End X11 mode */
+#ifdef USE_MITSHM
+ if (use_mitshm) {
+ XShmDetach (x11->dpy, &shm_info);
+ if (shm_info.shmaddr)
+ shmdt (shm_info.shmaddr);
+ if (shm_info.shmid >= 0)
+ shmctl (shm_info.shmid, IPC_RMID, 0);
+ }
+#endif
+ XDestroyWindow (x11->dpy, x11->x_win);
+ XUnloadFont (x11->dpy, x11->text);
+
+ parent_class->finalize (object);
+}
+
+static void
+x11_plugin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ X11Plugin *x11;
+ GObject *obj;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_X11_PLUGIN (object));
+
+ x11 = X11_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ obj = g_value_get_object (value);
+ g_return_if_fail (obj != NULL);
+
+ if (x11->map != NULL) {
+ g_object_unref (x11->map);
+ }
+
+ x11->map = MAP (g_object_ref (obj));
+
+ if (x11->map_size != NULL) {
+ g_free (x11->map_size);
+ }
+
+ g_object_get (G_OBJECT (x11->map),
+ "size", &x11->map_size,
+ NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+x11_plugin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ X11Plugin *x11;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_X11_PLUGIN (object));
+
+ x11 = X11_PLUGIN (object);
+
+ switch (prop_id) {
+ case ARG_MAP:
+ g_value_set_object (value, g_object_ref (G_OBJECT (x11->map)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+UserInterface *
+user_interface_new (Map *map, GType parent_type)
+{
+ g_return_val_if_fail (map != NULL, NULL);
+ g_return_val_if_fail (_parent_type != 0 || parent_type != 0, NULL);
+
+ if (!_parent_type) {
+ _parent_type = parent_type;
+ }
+
+ X11Plugin *x11 =
+ X11_PLUGIN (g_object_new (x11_plugin_get_type (),
+ "map", map,
+ NULL));
+ if (x11->errors) {
+ g_object_unref (G_OBJECT (x11));
+ return NULL;
+ }
+
+ return USER_INTERFACE (x11);
+}
+
+/* note that hook_delete_thing(x,y) is the same as
+ hook_add_thing(x,y,space) */
+inline void x11_plugin_add_thing (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint thing)
+{
+ gint w_x, w_y;
+
+ w_x = x * TILE_SIZE;
+ w_y = y * TILE_SIZE;
+
+ switch (thing) {
+ case SPACE:
+ put_tile (x11, x11->space, w_x, w_y);
+ break;
+ case FOOD:
+ put_tile (x11, x11->food, w_x, w_y);
+ break;
+ case PRIZE:
+ put_tile (x11, x11->prize, w_x, w_y);
+ break;
+ case WALL:
+ put_tile (x11, x11->wall, w_x, w_y);
+ break;
+ case BADDIE:
+ put_tile (x11, x11->baddie, w_x, w_y);
+ break;
+ case ROBOT:
+ put_tile (x11, x11->robotPix, w_x, w_y);
+ break;
+ default:
+ put_tile (x11, x11->wall, w_x, w_y);
+ break;
+ }
+
+ put_winbuf (x11);
+ XFlush (x11->dpy);
+}
+
+inline void x11_plugin_draw (X11Plugin *x11)
+{
+ gint i, j;
+
+ /* Draw the map for the GNU Robots game. */
+ for (j = 0; j < x11->map_size->num_rows; j++) {
+ for (i = 0; i < x11->map_size->num_cols; i++) {
+ /* Special cases */
+ switch (MAP_GET_OBJECT (x11->map, i, j)) {
+ /* Add something for the ROBOT?? */
+ case '\0':
+ put_tile (x11, x11->wall, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case SPACE:
+ put_tile (x11, x11->space, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case FOOD:
+ put_tile (x11, x11->food, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case PRIZE:
+ put_tile (x11, x11->prize, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case WALL:
+ put_tile (x11, x11->wall, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case BADDIE:
+ put_tile (x11, x11->baddie, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ case ROBOT:
+ put_tile (x11, x11->robotPix, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ default:
+ put_tile (x11, x11->wall, i * TILE_SIZE, j * TILE_SIZE);
+ break;
+ } /* switch */
+ } /* for i */
+ } /* for j */
+
+ put_winbuf (x11);
+ XSync (x11->dpy, FALSE);
+}
+
+inline void x11_plugin_move_robot (X11Plugin *x11,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ const static gint movement = TILE_SIZE / 16;
+ guint8 distance = dist (from_x, from_y, to_x, to_y);
+ guint w_x = to_x * TILE_SIZE, w_y = to_y * TILE_SIZE, tw_x, tw_y;
+ Bool ok;
+
+ g_assert (distance <= 1);
+
+ x11_plugin_update_status (x11, "robot moves..", energy, score, shields);
+
+ /* Check if robot is moving withing a single box */
+ if (distance == 0) {
+ put_tile (x11, x11->space, from_x * TILE_SIZE, from_y * TILE_SIZE);
+ put_tile (x11, x11->robotDirs[cdir], to_x * TILE_SIZE, to_y * TILE_SIZE);
+
+ put_winbuf (x11);
+ XSync (x11->dpy, False);
+ g_usleep (USLEEP_TIME / 16);
+
+ return;
+ }
+
+ from_x *= TILE_SIZE;
+ from_y *= TILE_SIZE;
+ tw_y = w_y;
+ tw_x = w_x;
+ switch (cdir) {
+ case NORTH:
+ tw_y = from_y - movement;
+ break;
+ case SOUTH:
+ tw_y = from_y + movement;
+ break;
+ case EAST:
+ tw_x = from_x + movement;
+ break;
+ case WEST:
+ tw_x = from_x - movement;
+ break;
+ default:
+ g_printf ("Weird unknown robot direction. I'm Confused.\n");
+ }
+
+ while (1) {
+ put_tile (x11, x11->space, from_x, from_y);
+ put_tile (x11, x11->robotDirs[cdir], tw_x, tw_y);
+
+ ok = False;
+ if (tw_x < w_x) {
+ tw_x += movement;
+ ok = True;
+ } else if (tw_x > w_x) {
+ tw_x -= movement;
+ ok = True;
+ }
+ if (tw_y < w_y) {
+ tw_y += movement;
+ ok = True;
+ } else if (tw_y > w_y) {
+ tw_y -= movement;
+ ok = True;
+ }
+ put_winbuf (x11);
+ XSync (x11->dpy, False);
+ g_usleep (USLEEP_TIME / 16);
+ if (!ok)
+ break;
+ }
+
+ g_usleep (USLEEP_TIME);
+}
+
+/* hooks to animate the robot */
+inline void x11_plugin_robot_smell (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ /* If we want to change the pic, do it here */
+ x11_plugin_update_status (x11, "robot sniffs...", energy, score, shields);
+ g_usleep (USLEEP_TIME);
+}
+
+inline void x11_plugin_robot_zap (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ x11_plugin_update_status (x11, "robot fires his little gun...", energy, score, shields);
+ g_usleep (USLEEP_TIME);
+}
+
+inline void x11_plugin_robot_feel (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ x11_plugin_update_status (x11, "robot feels for a thing...", energy, score, shields);
+ g_usleep (USLEEP_TIME);
+}
+
+inline void x11_plugin_robot_grab (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ x11_plugin_update_status (x11, "robot grabs thing...", energy, score, shields);
+ g_usleep (USLEEP_TIME);
+}
+
+inline void x11_plugin_robot_look (X11Plugin *x11,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ x11_plugin_update_status (x11, "robot looks for a thing...", energy, score, shields);
+ g_usleep (USLEEP_TIME);
+}
+
+/* hooks to get/display data from/to user */
+inline void x11_plugin_get_string (X11Plugin *x11,
+ gchar *prompt,
+ gchar *buff,
+ gint len)
+{
+ /* You want me to write a text-box using xlib?
+ * You got to be kidding me
+ * */
+ fputs (prompt, stdout);
+ fgets (buff, len, stdin);
+}
+
+inline void x11_update_status (X11Plugin *x11,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ gchar status[20];
+ gint x = 0;
+
+ while (x < x11->win_width) {
+ XPutImage (x11->dpy, x11->win_buf, x11->buf_gc, x11->statusbar, 0, 0, x, x11->map_size->num_rows * TILE_SIZE, 96,
+ 32);
+ x = x + 96;
+ }
+
+ XDrawString (x11->dpy, x11->win_buf, x11->gc, 3, x11->map_size->num_rows * TILE_SIZE + 16, s, strlen (s));
+
+ if (energy > -1) {
+ g_sprintf (status, "Robot Energy: %3d", energy);
+ XDrawString (x11->dpy, x11->win_buf, x11->gc, 240, x11->map_size->num_rows * TILE_SIZE + 12, status,
+ strlen (status));
+ }
+
+ if (score > -1) {
+ g_sprintf (status, "Robot Score: %3d", score);
+ XDrawString (x11->dpy, x11->win_buf, x11->gc, 240, x11->map_size->num_rows * TILE_SIZE + 25, status,
+ strlen (status));
+ }
+
+ if (shields > -1) {
+ g_sprintf (status, "Robot Shields: %3d", shields);
+ XDrawString (x11->dpy, x11->win_buf, x11->gc, 480, x11->map_size->num_rows * TILE_SIZE + 12, status,
+ strlen (status));
+ }
+}
+
+inline void x11_plugin_update_status (X11Plugin *x11,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ gint x;
+ XEvent ev;
+
+ x11_update_status (x11, s, energy, score, shields);
+
+ while (XPending (x11->dpy)) {
+ XNextEvent (x11->dpy, &ev);
+
+ switch (ev.type) {
+ case KeyPress:
+ case KeyRelease:
+ switch (XKeycodeToKeysym (x11->dpy, ev.xkey.keycode, 0)) {
+ case XK_Escape:
+ exit (0);
+ break;
+ }
+ }
+ }
+
+ put_winbuf (x11);
+}
+
+#ifdef USE_MITSHM
+inline gint
+shm_error_handler (X11Plugin *x11, Display * d, XErrorEvent * e)
+{
+ x11->use_mitshm = 0;
+ return 0;
+}
+#endif
+
+static void
+setup_winbuf (X11Plugin *x11)
+{
+ gint major, minor;
+ Bool shared;
+ XVisualInfo *matches;
+ XVisualInfo plate;
+ gint count;
+ guint depth;
+ XGCValues values;
+ Visual *vis;
+
+ vis = DefaultVisualOfScreen (DefaultScreenOfDisplay (x11->dpy));
+ plate.visualid = XVisualIDFromVisual (vis);
+ matches = XGetVisualInfo (x11->dpy, VisualIDMask, &plate, &count);
+ depth = matches[0].depth;
+
+#ifdef USE_MITSHM
+ x11->use_mitshm = 1;
+ x11->shm_info.shmid = shmget (IPC_PRIVATE, win_height * win_width * depth,
+ IPC_CREAT | 0777);
+ if (x11->shm_info.shmid < 0) {
+ g_fprintf (stderr, "shmget failed, looks like I'll have to use XPutImage\n");
+ x11->use_mitshm = 0;
+ } else {
+ x11->shm_info.shmaddr = (gchar *) shmat (x11->shm_info.shmid, 0, 0);
+
+ if (!x11->shm_info.shmaddr) {
+ g_fprintf (stderr, "shmat failed, looks like I'll have to use XPutImage\n");
+ shmctl (x11->shm_info.shmid, IPC_RMID, 0);
+ use_mitshm = 0;
+ } else {
+ XErrorHandler error_handler = XSetErrorHandler (shm_error_handler);
+
+ x11->win_bufi = XShmCreateImage (x11->dpy, vis, depth, ZPixmap, x11->shm_info.shmaddr,
+ &x11->shm_info, x11->win_width, x11->win_height);
+ x11->shm_info.readOnly = False;
+ XShmAttach (x11->dpy, &x11->shm_info);
+ win_buf = XShmCreatePixmap (x11->dpy, x11->x_win, x11->shm_info.shmaddr, &x11->shm_info,
+ x11->win_width, x11->win_height, depth);
+ XSync (x11->dpy, False);
+ (void) XSetErrorHandler (error_handler);
+ if (!use_mitshm) {
+ p_fprintf (stderr,
+ "XShmAttach failed, looks like I'll have to use XPutImage\n");
+ XFreePixmap (x11->dpy, x11->win_buf);
+ XDestroyImage (x11->win_bufi);
+ shmdt (x11->shm_info.shmaddr);
+ shmctl (x11->shm_info.shmid, IPC_RMID, 0);
+ }
+ }
+ }
+
+ if (!x11->use_mitshm) {
+#endif /* USE_MITSHM */
+ x11->win_buf = XCreatePixmap (x11->dpy, x11->x_win, x11->win_width, x11->win_height, depth);
+#ifdef USE_MITSHM
+ } else {
+ g_printf ("Using MIT Shared Memory Pixmaps. Good.\n", major, minor);
+ }
+#endif
+
+ values.font = x11->text;
+ values.foreground = WhitePixel (x11->dpy, DefaultScreen (x11->dpy));
+
+ x11->buf_gc = XCreateGC (x11->dpy, x11->win_buf, GCFont | GCForeground, &values);
+}
+
+void
+create_image (X11Plugin *x11, gchar **data, XImage ** image)
+{
+ XpmAttributes a;
+ gint err;
+
+ a.valuemask = XpmCloseness | XpmAllocCloseColors;
+ a.closeness = 40000; /* the xpm manual suggests 40000 */
+ a.alloc_close_colors = 1; /* allocate the colours chosen */
+ err = XpmCreateImageFromData (x11->dpy, data, image, NULL, &a);
+ if (err != 0) {
+ g_fprintf (stderr, "Cannot create image from xpm: %s\n",
+ XpmGetErrorString (err));
+ exit (1);
+ }
+}
+
+static void
+put_tile (X11Plugin *x11, XImage *image, gint x, gint y)
+{
+ XPutImage (x11->dpy, x11->win_buf, x11->gc, image, 0, 0, x, y, TILE_SIZE, TILE_SIZE);
+}
+
+static void put_winbuf (X11Plugin *x11)
+{
+#ifdef USE_MITSHM
+ if (use_mitshm)
+ XShmPutImage (x11->dpy, x11->x_win, x11->gc, x11->win_bufi, 0, 0, 0, 0, x11->win_width, x11->win_height,
+ False);
+ else
+#endif
+ XCopyArea (x11->dpy, x11->win_buf, x11->x_win, x11->gc, 0, 0, x11->win_width, x11->win_height, 0, 0);
+
+ XSync (x11->dpy, 0);
+}
+
+static void x11_plugin_interface_init (gpointer g_iface, gpointer iface_data)
+{
+ UserInterfaceClass *klass = (UserInterfaceClass *)g_iface;
+
+ klass->user_interface_add_thing = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing))
+ x11_plugin_add_thing;
+
+ klass->user_interface_draw = (void (*) (UserInterface *ui)) x11_plugin_draw;
+ klass->user_interface_update_status = (void (*) (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_update_status;
+ klass->user_interface_move_robot = (void (*) (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_move_robot;
+ klass->user_interface_robot_smell = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_robot_smell;
+ klass->user_interface_robot_zap = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_robot_zap;
+ klass->user_interface_robot_feel = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_robot_grab;
+ klass->user_interface_robot_grab = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_robot_grab;
+ klass->user_interface_robot_look = (void (*) (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields))
+ x11_plugin_robot_look;
+ klass->user_interface_get_string = (void (*) (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len))
+ x11_plugin_get_string;
+}
diff --git a/lib/x11plugin.h b/lib/x11plugin.h
new file mode 100644
index 0000000..0c39fa2
--- /dev/null
+++ b/lib/x11plugin.h
@@ -0,0 +1,102 @@
+/* $Id: x11plugin.h,v 1.1 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __X11_PLUGIN_H__
+#define __X11_PLUGIN_H__
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/xpm.h>
+#include <X11/keysym.h>
+
+#include <glib-object.h>
+#include "userinterface.h"
+#include "map.h"
+
+G_BEGIN_DECLS
+
+extern GType _x11_plugin_type;
+
+typedef struct _X11Plugin X11Plugin;
+
+struct _X11Plugin {
+ GObject object;
+ Map *map;
+ MapSize *map_size;
+ gint errors;
+
+ Display *dpy;
+ Window x_win;
+ GC gc;
+ GC buf_gc;
+ Font text;
+
+#ifdef USE_MITSHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+
+ XShmSegmentInfo
+ shm_info;
+ guchar use_mitshm = 1;
+#endif
+
+ gint win_width;
+ gint win_height;
+
+ Pixmap win_buf;
+
+ XImage *win_bufi;
+ XImage *statusbar;
+ XImage *space;
+ XImage *food;
+ XImage *wall;
+ XImage *prize;
+ XImage *baddie;
+ XImage *robotDirs[4];
+ XImage *robotPix;
+};
+
+typedef struct _X11PluginClass X11PluginClass;
+
+struct _X11PluginClass {
+ GObjectClass parent_class;
+};
+
+#define G_TYPE_X11_PLUGIN (_x11_plugin_type)
+#define G_IS_X11_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_X11_PLUGIN))
+#define G_IS_X11_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_X11_PLUGIN))
+#define X11_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_X11_PLUGIN, X11PluginClass))
+#define X11_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_X11_PLUGIN, X11Plugin))
+#define X11_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_X11_PLUGIN, X11PluginClass))
+
+/* normal GObject stuff */
+GType x11_plugin_get_type (void);
+
+X11Plugin* x11_plugin_new (void);
+
+/* SYMBOLIC CONSTANTS */
+#define dist(f_x, f_y, t_x, t_y) (abs((f_x)-(t_x))+abs((f_y)-(t_y)))
+
+G_END_DECLS
+
+#endif /* __X11_PLUGIN_H__*/
diff --git a/lib/xpm/Makefile.am b/lib/xpm/Makefile.am
new file mode 100644
index 0000000..60cb556
--- /dev/null
+++ b/lib/xpm/Makefile.am
@@ -0,0 +1,31 @@
+##
+## xpm/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+EXTRA_DIST =\
+ baddie.xpm\
+ food.xpm\
+ prize.xpm\
+ robot_east.xpm\
+ robot_north.xpm\
+ robot_south.xpm\
+ robot_west.xpm\
+ robot.xpm\
+ space.xpm\
+ statusbar.xpm\
+ wall.xpm
+
diff --git a/lib/xpm/baddie.xpm b/lib/xpm/baddie.xpm
new file mode 100644
index 0000000..60c1c6d
--- /dev/null
+++ b/lib/xpm/baddie.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *baddie_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #ffffff",
+"# c #990033",
+"a c #c0c0c0",
+"b c #808080",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"......#...#.....",
+".......###......",
+".....a#####a....",
+".....b#c###b....",
+"....b#c###b#b...",
+"....##cbab###...",
+"...#####a#####..",
+"....####a####...",
+"...#b###a###b#..",
+".....###a###....",
+"....#a##a##a#...",
+".......#b#......",
+"................",
+"................"
+};
diff --git a/lib/xpm/food.xpm b/lib/xpm/food.xpm
new file mode 100644
index 0000000..34558d3
--- /dev/null
+++ b/lib/xpm/food.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static char *food_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 4 1",
+/* colors */
+". c #f83000",
+"# c #c8ccc8",
+"a c #989898",
+"b c #f8fcf8",
+/* pixels */
+"bbbbbbbbbbbbbbbb",
+"bbbbbbbbbbbbbbbb",
+"bbbbbbbbbbbbbbbb",
+"bbb#bbbbbb#b#abb",
+"bbbbbbbbbbbbbabb",
+"bbbbbbbbbbbbbabb",
+"bbbbbbbb.bbbbabb",
+"bbbbbbbb.bbbbabb",
+"bbbbbb.....bbabb",
+"bbbbbbbb.bbbbabb",
+"bbbbbbbb.bbbbabb",
+"bbbbbbbbbbbbbabb",
+"bbbbbbbbbbbbbabb",
+"bbbaaaaaaaaaaabb",
+"bbbbbbbbbbbbbbbb",
+"bbbbbbbbbbbbbbbb"
+};
diff --git a/lib/xpm/prize.xpm b/lib/xpm/prize.xpm
new file mode 100644
index 0000000..96c4dad
--- /dev/null
+++ b/lib/xpm/prize.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static char *prize_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 8 1",
+/* colors */
+". c #303098",
+"# c #003098",
+"a c #989898",
+"b c #c8ccc8",
+"c c #606460",
+"d c #f8fcf8",
+"e c #989800",
+"f c #000000",
+/* pixels */
+"dddddddddddddddd",
+"dddddddddddddddd",
+"dddddddddddddddd",
+"dddddddddddddddd",
+"dddd........dddd",
+"dddd#deeeed.dddd",
+"dddd#dedded#dddd",
+"dddd#dedddd#dddd",
+"dddd##.#.###dddd",
+"dddd##c#cc##dddd",
+"dddd##c#cc#.dddd",
+"dddd.#cccc#.dddd",
+"dddddddddddddddd",
+"dddddddddddddddd",
+"dddddddddddddddd",
+"dddddddddddddddd"
+};
diff --git a/lib/xpm/robot.xpm b/lib/xpm/robot.xpm
new file mode 100644
index 0000000..fea60e2
--- /dev/null
+++ b/lib/xpm/robot.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *robot_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #bfbfbf",
+"# c #000000",
+"a c #808080",
+"b c #c0c0c0",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"................",
+"..####...####...",
+".#bccb#.#bccb#..",
+"#bccccb#bccccb#.",
+"#cccccc#cccccc#a",
+"#cc##cc#cc##cc#a",
+"#cc##cc#cc##cc#a",
+"#bccccb#bccccb#a",
+".#bccb#a#bccb#aa",
+"..####aa.####aa.",
+"...aaaa...aaaa..",
+"................",
+"................",
+"................"
+};
diff --git a/lib/xpm/robot_east.xpm b/lib/xpm/robot_east.xpm
new file mode 100644
index 0000000..14da711
--- /dev/null
+++ b/lib/xpm/robot_east.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *robot_east_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #bfbfbf",
+"# c #000000",
+"a c #808080",
+"b c #c0c0c0",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"................",
+"..####...####...",
+".#bccb#.#bccb#..",
+"#bccccb#bccccb#.",
+"#cccccc#cccccc#a",
+"#ccc##c#ccc##c#a",
+"#ccc##c#ccc##c#a",
+"#bccccb#bccccb#a",
+".#bccb#a#bccb#aa",
+"..####aa.####aa.",
+"...aaaa...aaaa..",
+"................",
+"................",
+"................"
+};
diff --git a/lib/xpm/robot_north.xpm b/lib/xpm/robot_north.xpm
new file mode 100644
index 0000000..ec7284d
--- /dev/null
+++ b/lib/xpm/robot_north.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *robot_north_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #bfbfbf",
+"# c #000000",
+"a c #808080",
+"b c #c0c0c0",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"................",
+"..####...####...",
+".#bccb#.#bccb#..",
+"#bc##cb#bc##cb#.",
+"#cc##cc#cc##cc#a",
+"#cccccc#cccccc#a",
+"#cccccc#cccccc#a",
+"#bccccb#bccccb#a",
+".#bccb#a#bccb#aa",
+"..####aa.####aa.",
+"...aaaa...aaaa..",
+"................",
+"................",
+"................"
+};
diff --git a/lib/xpm/robot_south.xpm b/lib/xpm/robot_south.xpm
new file mode 100644
index 0000000..b0ffc68
--- /dev/null
+++ b/lib/xpm/robot_south.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *robot_south_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #bfbfbf",
+"# c #000000",
+"a c #808080",
+"b c #c0c0c0",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"................",
+"..####...####...",
+".#bccb#.#bccb#..",
+"#bccccb#bccccb#.",
+"#cccccc#cccccc#a",
+"#cccccc#cccccc#a",
+"#cc##cc#cc##cc#a",
+"#bc##cb#bc##cb#a",
+".#bccb#a#bccb#aa",
+"..####aa.####aa.",
+"...aaaa...aaaa..",
+"................",
+"................",
+"................"
+};
diff --git a/lib/xpm/robot_west.xpm b/lib/xpm/robot_west.xpm
new file mode 100644
index 0000000..4a5a2af
--- /dev/null
+++ b/lib/xpm/robot_west.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *robot_west_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 5 1",
+/* colors */
+". c #bfbfbf",
+"# c #000000",
+"a c #808080",
+"b c #c0c0c0",
+"c c #ffffff",
+/* pixels */
+"................",
+"................",
+"................",
+"..####...####...",
+".#bccb#.#bccb#..",
+"#bccccb#bccccb#.",
+"#cccccc#cccccc#a",
+"#c##ccc#c##ccc#a",
+"#c##ccc#c##ccc#a",
+"#bccccb#bccccb#a",
+".#bccb#a#bccb#aa",
+"..####aa.####aa.",
+"...aaaa...aaaa..",
+"................",
+"................",
+"................"
+};
diff --git a/lib/xpm/space.xpm b/lib/xpm/space.xpm
new file mode 100644
index 0000000..bce27fb
--- /dev/null
+++ b/lib/xpm/space.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static char *space_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 3 1",
+/* colors */
+". c #989898",
+"# c #c8ccc8",
+"a c #f8fcf8",
+/* pixels */
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa"
+};
diff --git a/lib/xpm/statusbar.xpm b/lib/xpm/statusbar.xpm
new file mode 100644
index 0000000..89f5a05
--- /dev/null
+++ b/lib/xpm/statusbar.xpm
@@ -0,0 +1,58 @@
+/* XPM */
+static char * statusbar_xpm[] = {
+"96 32 23 1",
+" c None",
+". c #323232",
+"+ c #343434",
+"@ c #363636",
+"# c #313131",
+"$ c #373737",
+"% c #3A3A3A",
+"& c #393939",
+"* c #2F2F2F",
+"= c #262626",
+"- c #282828",
+"; c #2A2A2A",
+"> c #2D2D2D",
+", c #1B1B1B",
+"' c #1D1D1D",
+") c #222222",
+"! c #242424",
+"~ c #202020",
+"{ c #2B2B2B",
+"] c #3D3D3D",
+"^ c #3C3C3C",
+"/ c #3F3F3F",
+"( c #191919",
+".++@@++.##.$%&*=-;>#..>-,')!=)','~=>#*>;-;{>>*>*#......#=;*$&${~)!-;>>>>**#+++*{{>*#.++..+@&&&$@",
+"++@@@.#**>#@&&#{-->*+.>>'~)!!~',''=>##>{-;{>>***##..++..;{*@&@>=!!-{>>>>>**.@+#>>>>#...+#.@$$$$@",
+"++@@+#>>>{>+&&+*--{>.+.*!!!!)~''''!{*#*>;;{>>*#....+@++@>>>#@+*;!=;{>>>>>>*#@@+#{>>*##..#.+@@@@+",
+"+@@@.*{---{#@&$+;-;>#+++;;-=)~''''!;*#*>{{{>>#.+..++@$$$*>{>*#>{=-;>>>>>>>>*.$@@{>>>>##.##...+.+",
+".@@@+*;===;>.@&${;;{*.@@>>{-=)~~'~);>###>>>>>#.@..++@$&&.>;-{>{-=-{>>*>>>{;>#+@@>{{>>>*#***####.",
+"#.@$+>;!!=-;>.@&*>-->#+@##*>{-!)~~)->#..*>>>>#+@++++@$&&@#;=-;-!!-{>**>>{;=-{*.+{{{;{>*#**>>>*##",
+"*.@@@*{====-{>+$.>;-;>#..++.#>-!))!->*#.##>>>#+$+++@@@$&%+>;--!)!={>##*>{-))=>*#>{;-;>>**>>>>>**",
+">#@$@#{-====->.$@#;!->*#.+@$.>;!!!!=>*...#>>>*+$+@++@$$&]$#{;-!~)={>##**{=~~);>>{{;-;{>**>>{{>>*",
+";>+&&.>;)-;;-;>.+.#>;;>*##.$%&#;!!)={>##+..*>>.+++$+..&%$&&.;!!!=={*..*>{-)''~!;=-;=!!{*#*>>>>>*",
+"-{*+&@*{!={;;;>#+.#>{;>*#**@&&+>-=!={>*#...#>*#.+@@+.#@&&&&+>=!==-;>.+#*{;!~')!-=;;-!!;>.#*>>>**",
+"{;;*@&+>=-;;;{>*++.*{{{>**>.$&@.{;--{>>>.+.#**#.+@@+#*#.&^^&*;--;;{>#+++>;=)~~!=-;{;!)-{####*###",
+">=!;+%$.=-;;{{>*.++#>{>>>>>*+&&&>{{;>>>>.++.***#@@@+#*>>&^]%@>;-{{{>#@@${;=!))!!-{>;!!!;##....##",
+">-~-.&&+;;-;{>>>#.++#>>{>>>>#@&&+#>>>>>>..++####+@@@.*{=@&/]&#{;>>{>#++@;;-=!!)!=;>;=)!-*#++@++.",
+">-)-*@$@{;-;>>>>*.@@.*>>{{{>*+$&@+#*>*>>#.+@.##.++@@@#;!*$]/&.>{>>>>#.#*=-==!!!)!-{{=!!->#+@$@+#",
+">{;;>#@@>;-->>>{>#@$@#>>;{>>*#@$&@.#***>>.+@+.#.+++$&.>!-#%/%+>{>>>*#*>;!!====))~={{-==;>*+$&@+#",
+"#>>{{>.+>;=;>>>{>*@&@.*>>{>>>*.@%&+.##*>>#+@+.....@&&+>!!>&]%@>>>>>##>;=))====!)'!;{-=-;>>+$&@.#",
+"=-;>*#**{{-;>>>{>>*+&&.{{{{{>*#+@@$$@+#*>>*+$$+.##+$&&#;=;>+&$.>>>*#.*-~''~=;-!~'~!=--;-{>#@&&@.",
+"-=-{#..*>{;;>>>>{;>.$&.>{{{{>*#.@$$$$@..>>*.@$@...+&%&+>-;>.@@.>*>>*.#{!''~=--=~~~)!--;;{>*+&&$+",
+"{=!;#$@.>{;{>**>;-{*$$+#>>>>>>**@@$&$$$@>>*.@$$@.#.$%%$.;;>#.+#**{->+@>=''')-;-=~)!=--;->>*+&&&$",
+">=~-#&&+>>{{>*##--->.$@.>>>>>>>*+@$&&&&&##*#+@$@.##+&&&+{{>*#.#**;)-#@#;''')=;;-)!!=--;;{>>#@&&$",
+">-)=*$&&*>>>*#.#;-!;*++.*>>>>>>>.+@$&&%%+.*#.@$$.*>*+$@.>>>*##*>>!'!>.#>~'''!-;{===--;;;>>{>.$$&",
+">;==>.$&+*>>*...>;!={*##>*>>>>>>#.+@$&&%&+#*#+$&+*>>*.#**>*#.#>;=~''=>**!)'')-;;;;-;;;{{*>{{>.++",
+">>{-->@^@.*>#...#{=!->*>>>>>>>>>##.+@&&%&$#**+$$&.>{>**>**.++#{-''','!>.;)''~=-{{{{;{{>>*>;-{>*#",
+">>>;!>+^$+***.+.+>=)={>>>>>>***>**#.@$&&^&#**.@&%@>{>>>>*#+$@#{!(,'(('{.{=~''!-;>>{{{{>>.>-=-{>>",
+">>>{;>*.@+####.@.#>=~~->;{>>>*>*>>*#.+$&&&@#>>#@$$.>{{>*+##+&$*-,'''(')-;-!)');>*>>>>>*##*{-=-;>",
+">>>{{{>#++.####.+.#;!)->{>>>>**>>>**.+@$&&$#>{>+&$+#>>*..##+&$#{''~','~=-;=)~!->>*>****#.*>-=-;{",
+">>>>{{>*++..***>+@+>-!=;{{>>****>>>*#.++&&$.>;>*$$+#*>#+#**+$&@#)))'''~);;-!))->>*##..+..*>-=-;;",
+">>>>>{{>..+.#*>;+@$.>==-{{>>>*#*>>>>**..$&&+>-;{++.#**#.*>>#$&$@--!)~'~);;;-=!-;>*#+@@@++#>-==-;",
+"{>**>{{{#.++.>-=*+$$#;=={{{>>**#>>>>>**#+$&+>-=->>**>>*#>>>*.$&&>>;=!!))-{>{---;>*.+@$$&@.>;-=-;",
+"{>*#>>{{>#+@.>=~-*$&+>-!;;{{>>*#>>>>>>>**+$@*;==;{>>>>>*>{>>*+$&.*>{;;=!;{>>>{;{>**.@$&&&+*{---;",
+"->*#*>{{>*+@+>!'~;@&@*-=;;;;>>**>>>>>>>>{#@@*;==-;>>>>>#>>{{>*+&$+>>>>{=-{***>{>>>**.$&^&$#>---;",
+"-{*#*>{{;>+@+>!'(-.&$*;=---;{>***>>>>>>>-*+@#{=!-{>>>>*#>{;-;>.$&@#***>{->*.*>>>*>>>#@&]&$.>;-;{"};
diff --git a/lib/xpm/wall.xpm b/lib/xpm/wall.xpm
new file mode 100644
index 0000000..48b6a7c
--- /dev/null
+++ b/lib/xpm/wall.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static char *wall_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 16 16 3 1",
+/* colors */
+". c #cccccc",
+"# c #993300",
+"a c #cc0033",
+/* pixels */
+"...............#",
+".aaaaaaaaaaaaaa#",
+".aaaaaaaaaaaaaa#",
+".aa##########aa#",
+".aa#aaaaaaaa.aa#",
+".aa#aaaaaaaa.aa#",
+".aa#aa...#aa.aa#",
+".aa#aa.aa#aa.aa#",
+".aa#aa.aa#aa.aa#",
+".aa#aa####aa.aa#",
+".aa#aaaaaaaa.aa#",
+".aa#aaaaaaaa.aa#",
+".aa#.........aa#",
+".aaaaaaaaaaaaaa#",
+".aaaaaaaaaaaaaa#",
+"################"
+};
diff --git a/maps/Makefile.am b/maps/Makefile.am
new file mode 100644
index 0000000..79c4634
--- /dev/null
+++ b/maps/Makefile.am
@@ -0,0 +1,30 @@
+##
+## maps/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+mapsdir = $(pkgdatadir)/maps
+
+maps_DATA =\
+ maze.map\
+ pattern.map\
+ small.map
+
+EXTRA_DIST =\
+ maze.map\
+ pattern.map\
+ small.map
+
diff --git a/maps/maze.map b/maps/maze.map
new file mode 100644
index 0000000..3834a93
--- /dev/null
+++ b/maps/maze.map
@@ -0,0 +1,18 @@
+########################################
+# ##@@##$ #+++ ###########@@@$$#
+# ##$@##$#@@ ###### $$$@@ #$$#
+# ##$+##$#@# ### +#$$$# #####@### ####
+# ##$+##$#$# +#$$$# #+++++#++#
+# ##$+# $#$# ########$##### #$$$$$$$$#
+# ##$+@@$#$##@@ @@@@$@@@@$#$$$######
+#@@@ @######@@ ###########$$#$$$######
+# @@ # #++ # ++#####++++++++++++#
+######## #++ # +#
+#########$$#++##+ $$$$$$$$$$$$$$$$$ +#
+#+++$$$$$$ # #++ $$$$$$$$$$$$$$$$$ +#
+#+++######## ##++ $ +++++++++++ $ +#
+#+++######@ ##++ $ +++++++++++ $ +#
+#####@ #@ ##++ $$$$$$$$$$$$$$$$$ +#
+#++@@@$# #@#$$########$$$$$$$$$$$$$$ +#
+#++ $$$#+++#$$$#+++++++++++++++++++++++#
+########################################
diff --git a/maps/pattern.map b/maps/pattern.map
new file mode 100644
index 0000000..ec1f29d
--- /dev/null
+++ b/maps/pattern.map
@@ -0,0 +1,21 @@
+##############################################
+#+ @ $#+ @ $#+ @ $#+ @ $#+ @ $#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#
+#+ @ $#+ @ $#+ @ $#+ @ $#+ @ $#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#+#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#
+#+ @ $#+ @ $#+ @ $#+ @ $#+ @ $#
+#+$#+ @ $#+ @ $#+ @ $#+ @ $#+ $#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#+#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#+#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#
+#+ @ $#+ @ $#+ @ $#+ @ $#+ @ $#
+#+$#+ @ $#+ @ $#+ @ $#+ @ $#+ $#
+##+ @ $#+ @ $#+ @ $#+ @ $#+$#+ $#
+#+$#+ @ $#+ @ $#+ @ $#+ @ $#+ $#
+#+ $#+ @ $#+ @ $#+ @ $#+ @ $#+$#+#
+#+$#+ @ $#+ @ $#+ @ $#+ @ $#+$#+$#
+#+ @ $#+ @ $#+ @ $#+ @ $#+ @ $#
+#+$#+ @ $#+ @ $#+ @ $#+ @ $#+ $#
+#+#+ @ $#+ @ $#+ @ $#+ @ $#+$#+ $#
+##############################################
diff --git a/maps/small.map b/maps/small.map
new file mode 100644
index 0000000..91fbe04
--- /dev/null
+++ b/maps/small.map
@@ -0,0 +1,10 @@
+##########################
+#$$$$$$$$$$$$$$$$$$$$$$$$#
+#$ $#
+#$ ### @@ $#
+#$ @ ++ $#
+#$ ++ $#
+#$ @ ++ +@+ $#
+#$ $#
+#$$$$$$$$$$$$$$$$$$$$$$$$#
+##########################
diff --git a/scheme/Makefile.am b/scheme/Makefile.am
new file mode 100644
index 0000000..1a379e9
--- /dev/null
+++ b/scheme/Makefile.am
@@ -0,0 +1,36 @@
+##
+## scheme/Makefile.am
+##
+## GNU Robots 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.
+##
+## GNU Robots 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 GNU Robots; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+
+schemedir = $(pkgdatadir)/scheme
+
+scheme_SCRIPTS =\
+ beep.scm\
+ greedy.scm\
+ mapper.scm\
+ simple.scm\
+ stop.scm\
+ zap.scm
+
+EXTRA_DIST =\
+ beep.scm\
+ greedy.scm\
+ mapper.scm\
+ simple.scm\
+ stop.scm\
+ zap.scm
+
diff --git a/scheme/beep.scm b/scheme/beep.scm
new file mode 100644
index 0000000..72b462b
--- /dev/null
+++ b/scheme/beep.scm
@@ -0,0 +1,30 @@
+;;; beep.scm
+;;; Sample robot provided by Jim Hall <jhall1@isd.net>
+;;; This robot will just turn around 360-degrees, and will beep if it finds
+;;; a prize item. This is similar to a radar.
+
+;;; Define a function that will generate an audible beep
+
+(define (beep) (display "\a"))
+
+;;; Define a function that turns one unit, then feels for a prize.
+;;; If we find a prize, make a beep.
+
+(define (turn-and-feel)
+ (robot-turn 1)
+ (if (robot-feel "prize") (beep))
+)
+
+;;; Make one sweep:
+
+(turn-and-feel)
+(sleep 1)
+
+(turn-and-feel)
+(sleep 1)
+
+(turn-and-feel)
+(sleep 1)
+
+(turn-and-feel)
+(sleep 1)
diff --git a/scheme/greedy.scm b/scheme/greedy.scm
new file mode 100644
index 0000000..79a57f8
--- /dev/null
+++ b/scheme/greedy.scm
@@ -0,0 +1,112 @@
+;;;
+;;; Greedy robot for GNU Robots 0.77
+;;; 1998-08-15 by Kyle Hasselbacher <kyle@toehold.com>
+;;;
+
+;;; Greedy Robot wanders around looking for food and valuable prizes.
+;;; The definitions for thing-one and thing-two determine which it thinks
+;;; is more important (thing-one is).
+;;; It's not always very efficient in its gathering and can easily walk in
+;;; a circle if it can't see anything worth grabbing. It also assumes that
+;;; there is nothing interesting behind it, and that's not always true.
+;;; It treats baddies and walls the same way in that they are not
+;;; food, prizes, or open space. It just avoids running into them.
+
+(define thing-one "food")
+(define thing-two "prize")
+
+;;; If something interesting has been spotted, in-sights holds the name
+;;; of the thing we're headed for. Once it's grabbed, we set! in-sights
+;;; back to #f. Using the variable saves us a little energy since we don't
+;;; have to keep looking at the same thing over and over.
+(define in-sights #f)
+
+;;; grab a single prize (and move onto the space that had it)
+(define (grab)
+ (if (robot-grab)
+ (robot-move 1))
+ (set! in-sights #f))
+
+;;; Look around!
+(define (look-left-right thing)
+ (if (not (equal? in-sights thing))
+ (robot-turn 1))
+ (if (and (not (equal? in-sights thing)) (robot-look thing))
+ (set! in-sights thing))
+ (if (not (equal? in-sights thing))
+ (robot-turn 2))
+ (if (and (not (equal? in-sights thing)) (robot-look thing))
+ (set! in-sights thing)))
+
+(define (seek-thing thing)
+ (if (and (not (equal? in-sights thing)) (robot-look thing))
+ (set! in-sights thing))
+ (look-left-right thing)
+ (if (not (equal? in-sights thing))
+ (robot-turn 1))
+ (equal? in-sights thing))
+
+;;; Book it for a priority-one item. We don't look around for anything
+;;; else, but we do sniff the air for items of the same type we might pass
+;;; on the way.
+(define (get-thing thing)
+ (if (robot-feel thing)
+ (grab)
+ (begin (smell-test thing)
+ (if (robot-move 1)
+ (get-thing thing)))))
+
+;;; This doesn't do any smelling. It's called by smell-test when it thinks
+;;; there might be something to the left (it's already checked to the right).
+(define (smell-behind thing)
+ (robot-turn 2)
+ (if (robot-feel thing)
+ (robot-grab))
+ (robot-turn 1))
+
+;;; This feels to the right and left if it smells the thing its asked about.
+;;; Do the smell test after (robot-feel thing) fails.
+;;; Otherwise you spin around from smelling what's in front of you.
+;;; smell-test does a lot of turning but leaves you facing the same way.
+(define (smell-test thing)
+ (if (robot-smell thing)
+ (begin
+ (robot-turn 1)
+ (if (robot-feel thing)
+ (begin
+ (robot-grab)
+ (if (robot-smell thing)
+ (smell-behind thing)
+ (robot-turn -1)))
+ (smell-behind thing)))))
+
+;;; The drunkard's walk isn't too drunk.
+;;; Without obstructions, it only turns once in a while (1/10 steps).
+(define (drunkard-walk)
+ (if (and (not (= (random 10) 0)) (robot-feel "space"))
+ (robot-move 1)
+ (begin (robot-turn (+ 1 (random 2))) (drunkard-walk))))
+
+;;; The main loop! We go for our thing-one if we can see it. If we can see
+;;; thing-two, we go for that while checking for thing-one. If we can see
+;;; neither, we drunkards-walk one step.
+(define (main-loop)
+ (cond ((seek-thing thing-one)
+ (get-thing thing-one)
+ (set! in-sights #f))
+
+ ((seek-thing thing-two)
+ (if (robot-feel thing-two)
+ (grab)
+ (begin
+ (smell-test thing-two)
+ (robot-move 1))))
+
+ (#t (drunkard-walk)))
+ (main-loop))
+
+;;; Be random
+;(randomize)
+
+;;; Go to it.
+(main-loop)
diff --git a/scheme/mapper.scm b/scheme/mapper.scm
new file mode 100644
index 0000000..ba00c76
--- /dev/null
+++ b/scheme/mapper.scm
@@ -0,0 +1,827 @@
+;
+; Mapping robot for GNU Robots 0.77
+; 1998-08-22 by Kyle Hasselbacher <kyle@toehold.com>
+;
+
+; The central idea here is that the robot keeps a map of where it's been.
+;
+; BEHAVIOR
+; The robot will move in a straight line until it encounters a wall or some
+; place that it's already been. When it gets there, it will head for some
+; place it hasn't been.
+; Any time the robot is in a place it hasn't been before, it will feel the
+; spaces around it as necessary to find out what's there. If it feels
+; something it can grab, it does.
+;
+; PROBLEMS
+; (1) Speed. If the robot is far away from a "frontier", it takes a long
+; time for it to find a path there.
+; (2) It sometimes does some unnecessary turning. The (feel-around)
+; function always leaves it facing as it was, but after that it'll want to
+; turn anway because there's something in front of it.
+; (3) Its exploration isn't particularly systematic. It never really makes
+; zero progress, but it sometimes goes goes over ground multiple times when
+; it doesn't need to.
+;
+; NOTES
+; It keeps a list of frequencies of everything it's found so that it always
+; feels for the most prevalent map items first.
+; The map data structure stretches as the robot expands its area of
+; knowledge.
+; The robot also keeps track of its location and orientation.
+
+;;;
+;;; Variables
+;;;
+(define freq '(("space" 1) ("wall" 0) ("baddie" 0) ("food" 0) ("prize" 0)))
+
+; Oops. I redefined a primitive. Well, I didn't like that function anyway...
+(define map '())
+
+; Assumed to start facing east at the origin.
+(define facing (list 'east 'south 'west 'north))
+(define loc (cons 1 1))
+
+(define map-wide 0)
+(define map-tall 0)
+
+; We change this over the life of the robot, to keep it from getting hung up
+;(define favorite-direction 'east)
+;(define on-frontier #t)
+
+; If predict-death is true, the robot will dump its map to the screen and
+; exit when it think it's low on energy.
+(define predict-death #t)
+(define energy 1000) ; Starting energy
+
+; If this is true, the robot will cut short path searches as soon as it
+; finds a place it hasn't been before. This sometimes makes the robot
+; unnecessarily aggressive because it will see a path THROUGH a baddie
+; to a frontier before it notices the (cheaper) path around it.
+(define loose-goals #f)
+
+;;;
+;;; Mapping functions
+;;;
+(define (init-map x y)
+ (set! map-wide x)
+ (set! map-tall y)
+ (map-rows (+ 2 x) (+ 2 y)))
+
+(define (widen-map n)
+ (set! map-wide (+ n map-wide))
+ (set! map (widen-map-n map n)))
+
+(define (widen-map-n map n)
+ (if (null? map)
+ '()
+ (cons (append (car map) (make-list n #f)) (widen-map-n (cdr map) n))))
+
+(define (heighten-map n)
+ (set! map-tall (+ n map-tall))
+ (set! map (append map (map-rows (list-count (car map)) n))))
+
+; Yuck! This doesn't work: (make-list y (make-list x #f))
+; because every row is a pointer to the same list!
+(define (map-rows x n)
+ (if (< n 1)
+ '()
+ (cons (make-list x #f) (map-rows x (- n 1)))))
+
+(define (mark-map! loc thing)
+ (list-set! (list-ref map (cdr loc)) (car loc) thing))
+
+;;;
+;;; Path finding
+;;;
+
+;
+; We have a map, so we should be able to find a path from one part of the
+; map to another without having to grope around, right? Here's how:
+;
+; (1) Make a list of possible paths. Each path is a list containing the
+; "cost" of taking that path (including a heuristic estimate) and the
+; points along the path.
+; (2) Extend the current least-cost path in every possible direction
+; (creating new paths) and generate new cost estimates.
+; (3) Eliminate paths to duplicate locations (keeping the least-cost path).
+; (4) Eliminate paths with loops.
+; (5) Sort the list of paths.
+;
+; The heuristic will probably be the horizontal difference plus the
+; vertical difference plus one. Note that it costs to turn, so we need to
+; keep track of how the robot is facing too. We'll make it cost 5 to move
+; through a baddie since you can do it if you zap 'im.
+;
+
+;
+; A lot of the code below was stolen wholesale (with comments) directly
+; from my second assignment in CS 348 (Intro to AI) at the U of I four
+; years ago. It was written in LISP, so few changes were necessary, but
+; variable names aren't always consistent.
+;
+
+; PATH DATA STRUCTURE:
+; It's a list that looks like this: (123 'north (1 . 2) (3 . 4))
+; The number is the estimated cost of the path from beginning to
+; destination (NOT from beginning to the current end of the path)
+; The direction is the initial orientation of the robot. It never
+; changes.
+; The first pair is the location the path started. The second is the first
+; step of the path, etc. The last pair in the list is the end of the path
+; right now (which may not be at the goal).
+
+; This will return a path including its cost.
+(define (find-path dest-loc)
+ (find-path-a dest-loc (list (list (guess-cost loc dest-loc)
+ (car facing) loc))))
+
+(define (find-path-a dest-loc path-list)
+ (d-list (list "find-path " dest-loc " " path-list "\n"))
+ (cond ((null? path-list) path-list)
+ ((is-goal? dest-loc (car (last-pair (car path-list)))) (car path-list))
+ (#t (find-path-a dest-loc
+ (sort-paths
+ (elim-common-dest
+ (reject-loops
+ (append (cdr path-list)
+ (new-paths (car path-list)
+ dest-loc)))))))))
+
+; The last location in the path.
+(define (end-path path)
+ (list-ref path (- (list-count path) 1)))
+
+; How much it costs to take a particular set of steps.
+; It needs to know the final destination so it can guess the cost of the
+; rest of the steps to get there.
+; It needs to know the initial orientation so that it can detect turns.
+(define (steps-cost steps dest face)
+; (d-list (list "steps-cost " steps " " dest " " face "\n"))
+ (if (null? (cdr steps))
+ (guess-cost (car steps) dest)
+ (+ (if (equal? face (tell-direction (car steps) (cadr steps)))
+ 0 1)
+ (cond ((equal? (at-loc (car steps)) "space") 1)
+ ((equal? (at-loc (car steps)) "baddie") 6)
+ (#t 10000))
+ (steps-cost (cdr steps) dest (tell-direction (car steps)
+ (cadr steps))))))
+
+(define (guess-cost start-loc dest-loc)
+ (+ (abs (- (car start-loc) (car dest-loc)))
+ (abs (- (cdr start-loc) (cdr dest-loc)))
+ 1))
+
+; Find more paths based on this path.
+(define (new-paths path dest-loc)
+ (recompute-costs dest-loc
+ (path-sanity (list
+ (append path (list (vector-loc 'north (end-path path))))
+ (append path (list (vector-loc 'south (end-path path))))
+ (append path (list (vector-loc 'east (end-path path))))
+ (append path (list (vector-loc 'west (end-path path))))))))
+
+; Throw out paths that try to go through anything other than spaces or
+; baddies.
+; Throw out paths that go through points outside the map.
+(define (path-sanity path-list)
+ (if (null? path-list)
+ '()
+ (if (or (and (not (equal? (at-loc (end-path (car path-list))) "space"))
+ (not (equal? (at-loc (end-path (car path-list))) "baddie")))
+ (out-of-bounds? (end-path (car path-list))))
+ (path-sanity (cdr path-list))
+ (cons (car path-list) (path-sanity (cdr path-list))))))
+
+(define (recompute-costs dest-loc path-list)
+; (d-list (list "recompute-costs " dest-loc " " path-list "\n"))
+ (if (null? path-list)
+ '()
+ (begin
+ (set-car! (car path-list) (steps-cost (cddar path-list) dest-loc
+ (cadar path-list)))
+ (cons (car path-list) (recompute-costs dest-loc (cdr path-list))))))
+
+;
+; Takes a path list and removes those paths which contain loops (double
+; occurrances of any one node). Each path is checked with the looping
+; procedure.
+;
+(define (reject-loops path-list)
+; (d-list (list "reject-loops " path-list "\n"))
+ (if (null? path-list)
+ path-list
+ (if (looping (car path-list))
+ (reject-loops (cdr path-list))
+ (cons (car path-list) (reject-loops (cdr path-list))))))
+;
+; A path is checked for loops by checking each node for membership in the
+; remainder of the path.
+;
+(define (looping path)
+; (d-list (list "looping " path "\n"))
+ (if (null? path)
+ #f
+ (if (pair? (car path))
+ (or (member (car path) (cdr path))
+ (looping (cdr path)))
+ (looping (cdr path)))))
+
+; This was a LISP primitive. It might be a Scheme primitive too, but it
+; didn't do what I wanted. (The original code used symbols for nodes, but
+; this is using pairs.)
+(define (member test-loc loc-list)
+ (if (null? loc-list)
+ #f
+ (or (loc-eq? test-loc (car loc-list))
+ (member test-loc (cdr loc-list)))))
+
+;
+; This takes a list of paths and eliminates those which end at the same
+; node. It takes a list of all paths which have the same ending as the
+; current path (provided by same-end)--this list can contain only one
+; thing--and takes the shortest of those paths to remain in the list.
+;
+(define (elim-common-dest path-list)
+ (if (null? path-list)
+ '()
+ (cons (shortest-path (same-end (end-path (car path-list))
+ path-list))
+ (elim-common-dest (elim-dest (end-path (car path-list))
+ (cdr path-list))))))
+
+;
+; This takes a path list and an ending node, and returns all paths in the
+; list which do not end at that node. It's used to eliminate paths which
+; end at the same node.
+;
+(define (elim-dest dest path-list)
+ (if (null? path-list)
+ '()
+ (if (loc-eq? dest (end-path (car path-list)))
+ (elim-dest dest (cdr path-list))
+ (cons (car path-list)
+ (elim-dest dest (cdr path-list))))))
+
+;
+; This takes an ending node and a path list and returns all paths in the
+; list which DO end at that node. It's used to FIND paths which end at the
+; same node.
+;
+(define (same-end end path-list)
+ (if (null? path-list) path-list
+ (if (loc-eq? end (end-path (car path-list)))
+ (cons (car path-list)
+ (same-end end (cdr path-list)))
+ (same-end end (cdr path-list)))))
+;
+; This is just a proper call to real-sp, which does the real work of
+; finding the shortest path in a list of paths. It returns a path.
+;
+(define (shortest-path path-list)
+ (real-sp '() path-list))
+;
+; This recursive function finds the shortest path in a list. The first
+; argument is the shortest path found so far, and the second argument is
+; the list of paths for comparison.
+;
+(define (real-sp shortest path-list)
+ (if (null? path-list) shortest
+ (if (and (number? (caar path-list)) ; Just in case path-list is messed.
+ (or (null? shortest)
+ (< (caar path-list) (car shortest))))
+ (real-sp (car path-list) (cdr path-list))
+ (real-sp shortest (cdr path-list)))))
+
+; Tell whether our current endpoint is the goal. If loose-goals is true,
+; this will include any location we haven't already visited. This might
+; later be expanded to include "good enough" goals for when the real goal
+; is completely inaccessible.
+(define (is-goal? dest-loc cur-loc)
+ (or (loc-eq? dest-loc cur-loc)
+ (and loose-goals (not (been-to cur-loc)))))
+
+; Test whether two locations are equal.
+(define (loc-eq? a b)
+ (and (= (car a) (car b)) (= (cdr a) (cdr b))))
+
+(define (sort-paths path-list)
+ (quicksort path-list (lambda (a b)
+ (cond ((< (car a) (car b)) 'less-than)
+ ((= (car a) (car b)) 'equal-to)
+ ((> (car a) (car b)) 'greater-than)))))
+
+(define (execute-path path)
+ (d-list (list "execute-path " path "\n"))
+ (execute-steps (cdddr path)))
+
+; Go through the steps dictated by a path. This will make all the turns,
+; moves, and zaps necessary to get you where you're going according to the
+; plan.
+(define (execute-steps step-list)
+ (d-list (list "execute-steps " step-list "\n"))
+ (if (null? step-list)
+ '()
+ (begin
+ (turn-face (tell-direction loc (car step-list)))
+ (if (equal? (at-loc (car step-list)) "baddie")
+ (zap))
+ (move 1)
+ (execute-steps (cdr step-list)))))
+
+;;;
+;;; Action wrappers
+;;;
+
+(define (zap)
+ (decr-energy 5)
+ (if (robot-zap)
+ (mark-map! (front-loc) "space")))
+
+; Maybe this should also note the spaciness of intervening map squares,
+; but hopefully we won't move into them if they're not spaces.
+(define (move n)
+ (decr-energy n)
+ (if (robot-move n)
+ (begin
+ (change-loc n)
+ (if (< map-wide (car loc))
+ (widen-map (- (car loc) map-wide)))
+ (if (< map-tall (cdr loc))
+ (heighten-map (- (cdr loc) map-tall)))
+ (feel-around))
+ #f))
+
+(define (change-loc n)
+ (if (= n 0)
+ '()
+ (begin
+ (set! loc (front-loc))
+ (change-loc (- n 1)))))
+
+(define (turn n)
+ (decr-energy (abs n))
+ (change-face n)
+ (robot-turn n))
+
+(define (change-face n)
+ (if (= n 0)
+ '()
+ (begin
+ (if (> n 0)
+ (begin
+ (set! facing (append (cdr facing) (list (car facing))))
+ (change-face (- n 1))))
+ (if (< n 0)
+ (begin
+ (set! facing (list (list-ref facing 3) (list-ref facing 0)
+ (list-ref facing 1) (list-ref facing 2)))
+ (change-face (+ n 1)))))))
+
+;;;
+;;; Sensory functions.
+;;;
+
+; This will feel in front of the robot for everything it knows and grab
+; things that are worth grabbing.
+(define (grope)
+ (let ((thing (grope-things freq)))
+ (note-freq! freq thing)
+ (if (or (equal? thing "food")
+ (equal? thing "prize"))
+ (begin
+ (robot-grab)
+ (if (equal? thing "food")
+ (set! energy (+ 10 energy)))
+ (decr-energy 1)
+ "space")
+ thing)))
+
+; This does the actual feeling for the individual things in the frequency
+; list.
+(define (grope-things freq)
+ (if (null? freq)
+ #f
+ (begin (decr-energy 1)
+ (if (robot-feel (caar freq))
+ (caar freq)
+ (grope-things (cdr freq))))))
+
+; This makes sure the robot knows its immediate surroundings. It's called
+; after every movement. It won't feel spaces it's already felt, and it
+; always leaves the robot facing the same direction it started.
+(define (feel-around)
+ (let ((start-face (car facing)))
+ (feel-directions facing)
+ (turn-face start-face)))
+
+(define (feel-directions face-list)
+ (if (null? face-list)
+ '()
+ (begin
+ (if (not (at-loc (vector-loc (car face-list) loc)))
+ (begin
+; (set! on-frontier #t)
+ (turn-face (car face-list))
+ (mark-map! (front-loc) (grope))))
+ (feel-directions (cdr face-list)))))
+
+; An old version of feel-around.
+
+;(define (feel-around)
+; (if (not (at-loc (front-loc)))
+; (mark-map! (front-loc) (grope)))
+; (if (not (at-loc (right-loc)))
+; (begin
+; (turn 1) ; right from "front"
+; (mark-map! (front-loc) (grope))
+; (if (not (at-loc (back-loc)))
+; (begin
+; (turn 2) ; left from "front"
+; (mark-map! (front-loc) (grope))
+; (turn 1)) ; front
+; (turn -1))) ; front
+; (if (not (at-loc (left-loc)))
+; (begin
+; (turn -1) ; left from "front"
+; (mark-map! (front-loc) (grope))
+; (turn 1))))) ; front
+
+; This changes the frequency list to reflect the last thing we felt.
+(define (note-freq! freq thing)
+ (if (null? freq)
+ '()
+ (if (equal? (caar freq) thing)
+ (set-car! freq (list thing (+ 1 (cadar freq))))
+ (note-freq! (cdr freq) thing))))
+
+(define (sort-freq!)
+ (set! freq (quicksort freq (lambda (a b)
+ (cond ((> (cadr a) (cadr b)) 'less-than)
+ ((= (cadr a) (cadr b)) 'equal-to)
+ ((< (cadr a) (cadr b)) 'greater-than))))))
+
+; THE SCHEMATICS OF COMPUTATION by Vincent S. Manis and James J. Little
+; page 487
+(define quicksort
+ (lambda (x compare)
+ (if (null? x)
+ x
+ (let*
+ ((pivot (car x))
+ (smaller '()) (equal '()) (larger '())
+ (classify
+ (lambda (item)
+ (case (compare item pivot)
+ ((less-than)
+ (set! smaller (cons item smaller)))
+ ((equal-to)
+ (set! equal (cons item equal)))
+ ((greater-than)
+ (set! larger (cons item larger)))))))
+ (for-each classify x)
+; (format #t "smaller: ~a equal: ~a larger: ~%"
+; smaller equal larger)
+ (append (quicksort smaller compare)
+ equal (quicksort larger compare))))))
+
+;;;
+;;; Orientation-related functions
+;;;
+
+; These give the coordinates of spots around the robot
+(define (front-loc)
+ (relative-loc 'front loc))
+
+(define (back-loc)
+ (relative-loc 'back loc))
+
+(define (right-loc)
+ (relative-loc 'right loc))
+
+(define (left-loc)
+ (relative-loc 'left loc))
+
+; Tell me a direction (right, left, front, back) and a location, and I'll
+; tell you the coordinate in the direction from the location. This uses
+; the current orientation of the robot to do its computation.
+(define (relative-loc dir loc)
+ (case dir
+ ((left) (case (car facing)
+ ((west) (cons (car loc) (+ 1 (cdr loc))))
+ ((east) (cons (car loc) (- (cdr loc) 1)))
+ ((north) (cons (- (car loc) 1) (cdr loc)))
+ ((south) (cons (+ (car loc) 1) (cdr loc)))))
+ ((right) (case (car facing)
+ ((east) (cons (car loc) (+ 1 (cdr loc))))
+ ((west) (cons (car loc) (- (cdr loc) 1)))
+ ((south) (cons (- (car loc) 1) (cdr loc)))
+ ((north) (cons (+ (car loc) 1) (cdr loc)))))
+ ((back) (case (car facing)
+ ((south) (cons (car loc) (- (cdr loc) 1)))
+ ((north) (cons (car loc) (+ 1 (cdr loc))))
+ ((west) (cons (+ (car loc) 1) (cdr loc)))
+ ((east) (cons (- (car loc) 1) (cdr loc)))))
+ ((front) (case (car facing)
+ ((south) (cons (car loc) (+ 1 (cdr loc))))
+ ((north) (cons (car loc) (- (cdr loc) 1)))
+ ((west) (cons (- (car loc) 1) (cdr loc)))
+ ((east) (cons (+ (car loc) 1) (cdr loc)))))))
+
+; Tell me a vector (north, south, east, west) and a location, and I'll tell
+; you the location in that direction from your location.
+(define (vector-loc face loc)
+ (case face
+ ((east) (cons (+ (car loc) 1) (cdr loc)))
+ ((west) (cons (- (car loc) 1) (cdr loc)))
+ ((north) (cons (car loc) (- (cdr loc) 1)))
+ ((south) (cons (car loc) (+ (cdr loc) 1)))))
+
+; Turn in a particular direction (north, south, east, west).
+(define (turn-face face)
+ (case face
+ ((east) (case (car facing)
+ ((east) #t)
+ ((west) (turn 2))
+ ((north) (turn 1))
+ ((south) (turn -1))))
+ ((west) (case (car facing)
+ ((west) #t)
+ ((east) (turn 2))
+ ((north) (turn -1))
+ ((south) (turn 1))))
+ ((north) (case (car facing)
+ ((north) #t)
+ ((south) (turn 2))
+ ((east) (turn -1))
+ ((west) (turn 1))))
+ ((south) (case (car facing)
+ ((south) #t)
+ ((north) (turn 2))
+ ((east) (turn 1))
+ ((west) (turn -1))))))
+
+;;;
+;;; Unorganized functions.
+;;;
+
+(define (decr-energy n)
+ (set! energy (- energy n))
+ (d-list (list "*** energy " energy " ***\n"))
+ (if (and predict-death (< energy 11))
+ (dump)))
+
+; I bet there's a primitive to do this, but I can write this faster
+; than I can look it up.
+(define (list-count tsil)
+ (if (null? tsil)
+ 0
+ (+ 1 (list-count (cdr tsil)))))
+
+; Tell whether a coordinate is outside the map.
+(define (out-of-bounds? loc)
+ (or (> 1 (car loc)) (> 1 (cdr loc))
+ (> (car loc) (- (list-count (car map)) 1))
+ (> (cdr loc) (- (list-count map) 1))))
+
+; Tell what's at a particular location. This will say "wall" for
+; out-of-bounds locations to the north or west and #f for out-of-bounds
+; locations to the south or east (since the map may be stretched in that
+; direction, theoretically).
+(define (at-loc loc)
+ (if (or (> 0 (car loc)) (> 0 (cdr loc)))
+ "wall"
+ (if (or (> (car loc) (- (list-count (car map)) 1))
+ (> (cdr loc) (- (list-count map) 1)))
+ #f
+ (list-ref (list-ref map (cdr loc)) (car loc)))))
+
+; Tell whether we've visited a particular location. It checks whether we
+; know what's at that location and the locations around it, so you can get
+; a true return even if you haven't actually stepped on the spot, but it
+; still means you don't need to go there.
+(define (been-to loc)
+ (and (at-loc loc)
+ (at-loc (cons (+ 1 (car loc)) (cdr loc)))
+ (at-loc (cons (- (car loc) 1) (cdr loc)))
+ (at-loc (cons (car loc) (- (cdr loc) 1)))
+ (at-loc (cons (car loc) (+ 1 (cdr loc))))))
+
+; This gives a list of coordinates that surround a particular location at a
+; particular "radius." The coordinates actually form a square. If the
+; radius is 1, you'll get 8 coordinates. If the radius is 2, you get 16.
+; This is used to search for locations of a particular type in a radiating
+; fashion from the robot itself.
+(define (coord-around-list loc radius)
+ (append (h-coord-list (cons (- (car loc) radius) (- (cdr loc) radius))
+ (+ 1 (* 2 radius)))
+ (v-coord-list (cons (+ (car loc) radius) (+ 1 (- (cdr loc) radius)))
+ (- (* 2 radius) 1))
+ (h-coord-list (cons (- (car loc) radius) (+ (cdr loc) radius))
+ (+ 1 (* 2 radius)))
+ (v-coord-list (cons (- (car loc) radius) (+ 1 (- (cdr loc) radius)))
+ (- (* 2 radius) 1))))
+
+(define (h-coord-list loc n)
+ (if (= n 0)
+ '()
+ (cons loc (h-coord-list (cons (+ 1 (car loc)) (cdr loc)) (- n 1)))))
+
+(define (v-coord-list loc n)
+ (if (= n 0)
+ '()
+ (cons loc (v-coord-list (cons (car loc) (+ 1 (cdr loc))) (- n 1)))))
+
+; Gimme a function and a list. I'll give you a list of pairs.
+; (function-results . pair) Of course, the function should take one argument.
+
+;(define (coord-list-apply func loc-list)
+; (if (null? loc-list)
+; '()
+; (cons (cons (func (car loc-list))
+; (car loc-list))
+; (coord-list-apply func (cdr loc-list)))))
+
+;(define (find-result x tsil)
+; (if (null? tsil)
+; '()
+; (if (eqv? x (caar tsil))
+; (cons (cdar tsil)
+; (find-result x (cdr tsil)))
+; (find-result x (cdr tsil)))))
+
+
+; What direction is loc2 from loc1 ?
+; (If the direction is an exact diagonal, I don't know what you'll get, but
+; I don't think that's particularly wrong either.)
+(define (tell-direction loc1 loc2)
+ (if (> (abs (- (car loc1) (car loc2)))
+ (abs (- (cdr loc1) (cdr loc2))))
+ (if (< 0 (- (car loc1) (car loc2)))
+ 'west
+ 'east)
+ (if (< 0 (- (cdr loc1) (cdr loc2)))
+ 'north
+ 'south)))
+
+;(define (new-favorite-direction)
+;; (d-list (list "--- favorite direction is: " favorite-direction "\n"))
+; (set! on-frontier #f)
+; (let* ((cur-dir favorite-direction)
+; (face-dir (car facing))
+; (new-dir (tell-direction loc (find-frontier 1))))
+; (if (equal? new-dir cur-dir)
+; (if (equal? new-dir face-dir)
+; (set! favorite-direction (cadr facing))
+; (set! favorite-direction face-dir))
+; (set! favorite-direction new-dir))))
+
+; Call this with an initial argument of 1. It will search outward from the
+; robot for a location it hasn't yet visited. It will return a list of
+; such locations which are all roughly the same distance from the robot.
+; This is used to select a new destination for the robot when it's gotten
+; stuck somewhere.
+(define (find-frontier n)
+ (d-list (list "--- find-frontier " n " ---\n"))
+ (if (> n 20) (dump)) ; PROBABLY a problem
+ (let ((result (frontier-do n)))
+ (d-list (list result "\n"))
+ (if (and (not (null? result))
+ (equal? "baddie" (at-loc (car result)))
+ (= n 1))
+ (set! result (append (frontier-do 2) result)))
+ (if (null? result)
+ (find-frontier (+ n 1))
+ (car result))))
+
+; Produces a list of possible frontier values (sorted and sanity checked).
+(define (frontier-do n)
+ (quicksort ; Spaces are better than baddies.
+ (frontier-sanity (coord-around-list loc n))
+ (lambda (a b)
+ (cond ((and (equal? (at-loc a) "space")
+ (equal? (at-loc b) "baddie")) 'less-than)
+ ((and (equal? (at-loc a) "baddie")
+ (equal? (at-loc b) "space")) 'greater-than)
+ (#t 'equal-to)))))
+
+; This keeps the results of find-frontier in check. We throw out:
+;
+; (1) Locations that are off the map.
+; (2) Walls.
+; (3) Locations we haven't mapped (find-path doesn't know how to get there).
+; (4) Locations we've already visited.
+;
+; That way find-frontier should give us a spot which is exatly next to a
+; spot we haven't mapped.
+(define (frontier-sanity loc-list)
+ (if (null? loc-list)
+ '()
+ (if (or (out-of-bounds? (car loc-list))
+ (equal? (at-loc (car loc-list)) "wall")
+ (not (at-loc (car loc-list)))
+ (been-to (car loc-list)))
+ (frontier-sanity (cdr loc-list))
+ (cons (car loc-list) (frontier-sanity (cdr loc-list))))))
+
+; This decides how we move.
+(define (go)
+ (if (and (equal? (at-loc (front-loc)) "space")
+ (not (been-to (front-loc))))
+ (move 1)
+ (let ((path (find-path (find-frontier 1))))
+ (if (null? path)
+ (dump)
+ (execute-path path)))))
+
+;(define (go)
+; (if (and (equal? (at-loc (vector-loc favorite-direction loc)) "space")
+; (or (not on-frontier)
+; (not (been-to (vector-loc favorite-direction loc))))
+; (not (equal? (car facing) favorite-direction)))
+; (turn-face favorite-direction)
+; (if (equal? (at-loc (front-loc)) "space")
+; (move 1)
+; (if (and (equal? (at-loc (right-loc)) "space")
+; (or (not on-frontier) (not (been-to (right-loc)))))
+; (turn 1)
+; (if (and (equal? (at-loc (left-loc)) "space")
+; (or (not on-frontier) (not (been-to (left-loc)))))
+; (turn -1)
+; (let ((path (find-path (find-frontier 1))))
+; (if (null? path)
+; (dump)
+; (execute-path path))))))))
+
+
+; (new-favorite-direction)
+; (turn-face favorite-direction)))))))
+
+;;;
+;;; Debugging functions.
+;;;
+
+; Dummies (so the guile interpreter doesn't blow up)
+;(define (robot-feel n) (display "robot-feel\n") "space")
+;(define (robot-move n) (display "robot-move\n") #t)
+;(define (robot-turn n) (display "robot-turn\n") #t)
+;(define (robot-grab) (display "robot-grab\n") #t)
+
+;(define (d-list tsil) (if (null? tsil) '() (cons (display (car tsil)) (d-list (cdr tsil)))))
+
+(define (d-list tsil) tsil)
+
+; Print the map to the screen and exit.
+(define (dump)
+ (display-map map)
+ (quit))
+
+(define (display-map map)
+ (if (null? map)
+ '()
+ (begin
+ (display-map-line (car map))
+ (display-map (cdr map)))))
+
+(define (space-out n)
+ (if (= n 0)
+ '()
+ (begin
+ (display " ")
+ (space-out (- n 1)))))
+
+(define (display-map-line tsil)
+ (if (null? tsil)
+ (space-out (- 80 (list-count (car map))))
+; (display "\n")
+ (begin
+ (if (equal? "space" (car tsil))
+ (display "."))
+ (if (equal? "baddie" (car tsil))
+ (display "@"))
+ (if (equal? "wall" (car tsil))
+ (display "#"))
+ (if (not (car tsil))
+ (display "x"))
+ (if (equal? "food" (car tsil))
+ (display "+"))
+ (if (equal? "prize" (car tsil))
+ (display "$"))
+ (display-map-line (cdr tsil)))))
+
+;;;
+;;; Main program.
+;;;
+
+(define (main-loop)
+ (go)
+ (main-loop))
+
+; INITIALIZATION.
+(set! map (init-map 1 1)) ; The map is tiny, but it will grow.
+(sort-freq!) ; Sort the frequency list if it isn't already.
+(mark-map! loc "space") ; I start out on a space, Shirly.
+(feel-around) ; Get your bearings.
+
+(main-loop) ; GO.
diff --git a/scheme/simple.scm b/scheme/simple.scm
new file mode 100644
index 0000000..66f3591
--- /dev/null
+++ b/scheme/simple.scm
@@ -0,0 +1,32 @@
+;;; simple.scm
+;;; Sample robot provided by Jim Hall <jhall1@isd.net>
+;;; This robot will simply hunt down and grab any prizes in its direct
+;;; line of sight. If it runs into an obstacle, it turns right and
+;;; continues from there. When it has turned 360-degrees, it stops.
+
+;;; Define a function to feel for prize (wrapper)
+(define (feel-prize)
+ (robot-feel "prize"))
+
+;;; Define a function to grab a single prize
+(define (grab-prize)
+ (robot-grab)
+ (robot-move 1))
+
+;;; Define a function to grab all prizes
+(define (grab-all-prizes)
+ (do () (not (feel-prize)) (grab-prize)))
+
+;;; The program starts here: hunt for all prizes
+
+(grab-all-prizes)
+(robot-turn 1)
+
+(grab-all-prizes)
+(robot-turn 1)
+
+(grab-all-prizes)
+(robot-turn 1)
+
+(grab-all-prizes)
+(sleep 1)
diff --git a/scheme/stop.scm b/scheme/stop.scm
new file mode 100644
index 0000000..511988b
--- /dev/null
+++ b/scheme/stop.scm
@@ -0,0 +1,16 @@
+;;; stop.scm
+;;; Sample robot provided by Jim Hall <jhall1@isd.net>
+;;; THIS ROBOT IS NOT REALLY INTENDED FOR PUBLIC CONSUMPTION!
+;;; Tests my new `stop' and `quit' primitives for GNU Robots
+
+;;; Define a function to make a beep
+(define (beep) (display "\a"))
+
+;;; The program starts here:
+
+(beep)
+(sleep 1)
+
+;;; Test my new `stop' and `quit' primitives:
+;(stop)
+(quit)
diff --git a/scheme/zap.scm b/scheme/zap.scm
new file mode 100644
index 0000000..67e8d4d
--- /dev/null
+++ b/scheme/zap.scm
@@ -0,0 +1,36 @@
+;;; zap.scm
+;;; Sample robot provided by Jim Hall <jhall1@isd.net>
+;;; This is an agressive little robot that will just turn 360-degrees,
+;;; and will immediately zap anything that isn't a space. This builds
+;;; on the beep.scm robot program, so it will also beep if it finds a
+;;; prize (but then destroys it.)
+
+;;; Define a function to make a beep
+(define (beep) (display "\a"))
+
+;;; Define a function to blow away anything that isn't a space
+(define (blast-nonspace)
+ (if (robot-feel "space") (robot-zap)))
+
+;;; Define a function to turn, then see if a prize is there
+(define (turn-and-feel)
+ (robot-turn 1)
+ (if (robot-feel "prize") (beep)))
+
+;;; The program begins here: make one sweep
+
+(turn-and-feel)
+(blast-nonspace)
+(sleep 1)
+
+(turn-and-feel)
+(blast-nonspace)
+(sleep 1)
+
+(turn-and-feel)
+(blast-nonspace)
+(sleep 1)
+
+(turn-and-feel)
+(blast-nonspace)
+(sleep 1)
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..47d7f3b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS = grobots
+
+INCLUDES = $(GLIB2_CFLAGS) $(GUILE_CFLAGS) -I$(top_builddir)/include \
+ -DPKGLIBDIR=\"$(pkglibdir)\" \
+ -DABS_TOP_BUILDDIR=\"$(abs_top_builddir)\" \
+ -DPKGDATADIR=\"$(pkgdatadir)\" \
+ -DMAPS_PATH=\"$(mapsdir)\" \
+ -DSCRIPTS_PATH=\"$(schemedir)\"
+
+grobots_SOURCES = main.c api.c sign.c map.c grobot.c userinterface.c
+grobots_LDFLAGS = $(GLIB2_LIBS) $(GUILE_LDFLAGS) -lltdl
+
diff --git a/src/api.c b/src/api.c
new file mode 100644
index 0000000..81776e5
--- /dev/null
+++ b/src/api.c
@@ -0,0 +1,160 @@
+/* $Id: api.c,v 1.16 2005/09/06 19:55:40 zeenix Exp $ */
+
+/* Robot API for the GNU Robots game */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for abs, free */
+
+#include <glib.h>
+#include <libguile.h> /* GNU Guile high */
+
+#include "api.h" /* GNU Robots API */
+#include "main.h" /* for exit_nicely */
+#include "sign.h" /* a hack for +/- sign */
+#include "grobot.h"
+
+extern GRobot *robot;
+
+/* Functions */
+
+SCM
+api_robot_turn (SCM s_n)
+{
+ g_robot_turn (robot, scm_num2int (s_n, 0, NULL));
+
+ return SCM_BOOL (TRUE);
+}
+
+SCM
+api_robot_move (SCM s_n)
+{
+ return SCM_BOOL (g_robot_move (robot, scm_num2int (s_n, 0, NULL)));
+}
+
+SCM
+api_robot_smell (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_smell (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_feel (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_feel (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_look (SCM s_th)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = SCM_STRING_CHARS (s_th);
+ ret = g_robot_look (robot, str);
+
+ return SCM_BOOL (ret);
+}
+
+SCM
+api_robot_grab (void)
+{
+ return SCM_BOOL (g_robot_grab (robot));
+}
+
+SCM
+api_robot_zap (void)
+{
+ return SCM_BOOL (g_robot_zap (robot));
+}
+
+SCM
+api_robot_stop (void)
+{
+ return SCM_BOOL (g_robot_stop (robot));
+}
+
+SCM
+api_robot_get_shields (void)
+{
+ glong shields;
+
+ g_object_get (robot, "shields", &shields, NULL);
+
+ /* Returns the robot shields */
+ return (scm_long2num (shields));
+}
+
+SCM
+api_robot_get_energy (void)
+{
+ glong energy;
+
+ g_object_get (robot, "energy", &energy, NULL);
+
+ /* Returns the robot energy */
+ return (scm_long2num (energy));
+}
+
+SCM
+api_robot_get_score (void)
+{
+ glong score;
+
+ g_object_get (robot, "score", &score, NULL);
+
+ /* Returns the robot score */
+ return (scm_long2num (score));
+}
+
+void
+api_init (void)
+{
+ /* define some new builtins (hooks) so that they are available in
+ Scheme. */
+
+ scm_c_define_gsubr ("robot-turn", 1, 0, 0, api_robot_turn);
+ scm_c_define_gsubr ("robot-move", 1, 0, 0, api_robot_move);
+ scm_c_define_gsubr ("robot-smell", 1, 0, 0, api_robot_smell);
+ scm_c_define_gsubr ("robot-feel", 1, 0, 0, api_robot_feel);
+ scm_c_define_gsubr ("robot-look", 1, 0, 0, api_robot_look);
+ scm_c_define_gsubr ("robot-grab", 0, 0, 0, api_robot_grab);
+ scm_c_define_gsubr ("robot-zap", 0, 0, 0, api_robot_zap);
+
+ scm_c_define_gsubr ("robot-get-shields", 0, 0, 0, api_robot_get_shields);
+ scm_c_define_gsubr ("robot-get-energy", 0, 0, 0, api_robot_get_energy);
+ scm_c_define_gsubr ("robot-get-score", 0, 0, 0, api_robot_get_score);
+
+ scm_c_define_gsubr ("stop", 0, 0, 0, api_robot_stop);
+ scm_c_define_gsubr ("quit", 0, 0, 0, api_robot_stop);
+}
+
diff --git a/src/grobot.c b/src/grobot.c
new file mode 100644
index 0000000..89602a0
--- /dev/null
+++ b/src/grobot.c
@@ -0,0 +1,833 @@
+/* Robot object for the GNU Robots game */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "grobot.h"
+#include "configs.h"
+#include "userinterface.h" /* GNU Robots UI */
+#include <stdio.h>
+#include <glib.h>
+
+enum
+{
+ DEATH,
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_POS_X,
+ ARG_POS_Y,
+ ARG_DIRECTION,
+ ARG_SCORE,
+ ARG_ENERGY,
+ ARG_SHIELDS,
+ ARG_UNITS,
+ ARG_SHOTS,
+
+ ARG_USER_INTERFACE,
+ ARG_MAP
+};
+
+static gchar *things[] = { "space", "food", "prize", "wall", "baddie", "robot" };
+static gint cthings[] = { SPACE, FOOD, PRIZE, WALL, BADDIE, ROBOT };
+
+GType _g_robot_type;
+
+static guint g_robot_signals[LAST_SIGNAL] = { 0 };
+static void g_robot_class_init (GRobotClass * klass);
+
+static void g_robot_dispose (GObject * object);
+static void g_robot_finalize (GObject * object);
+
+static void g_robot_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void g_robot_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GObjectClass *parent_class = NULL;
+
+static gint what_thing (const gchar *th);
+
+GType
+g_robot_get_type (void)
+{
+ if (!_g_robot_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GRobotClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) g_robot_class_init,
+ NULL,
+ NULL,
+ sizeof (GRobot),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ };
+
+ _g_robot_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "GRobot",
+ &object_info,
+ 0);
+ }
+
+ return _g_robot_type;
+}
+
+static void
+g_robot_class_init (GRobotClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->dispose = g_robot_dispose;
+ gobject_class->finalize = g_robot_finalize;
+ gobject_class->set_property = g_robot_set_property;
+ gobject_class->get_property = g_robot_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POS_X,
+ g_param_spec_int ("x",
+ "x",
+ "X co-ordinate of current Position of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POS_Y,
+ g_param_spec_int ("y",
+ "y",
+ "y co-ordinate of current Position of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DIRECTION,
+ g_param_spec_int ("direction",
+ "direction",
+ "current Direction of the Robot",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCORE,
+ g_param_spec_long ("score",
+ "Score",
+ "current Score of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENERGY,
+ g_param_spec_long ("energy",
+ "Energy",
+ "current Energy-level of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SHIELDS,
+ g_param_spec_long ("shields",
+ "Shields",
+ "current Shield-level of the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UNITS,
+ g_param_spec_long ("units",
+ "Units",
+ "Units walked by the Robot so far",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SHOTS,
+ g_param_spec_long ("shots",
+ "Shots",
+ "Number of Shots fired by the Robot",
+ G_MINLONG,
+ G_MAXLONG,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USER_INTERFACE,
+ g_param_spec_object ("user-interface",
+ "UserInterface",
+ "Reference to the UI object",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAP,
+ g_param_spec_object ("map",
+ "Map",
+ "Reference to the Game Map object",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_robot_signals[DEATH] =
+ g_signal_new ("death",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GRobotClass, death),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0, NULL);
+}
+
+static void
+g_robot_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GRobot *robot;
+ GObject *obj;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_ROBOT (object));
+
+ robot = G_ROBOT (object);
+
+ switch (prop_id) {
+ case ARG_POS_X:
+ robot->x = g_value_get_int (value);
+ break;
+ case ARG_POS_Y:
+ robot->y = g_value_get_int (value);
+ break;
+ case ARG_DIRECTION:
+ robot->dir = g_value_get_int (value);
+ break;
+ case ARG_SCORE:
+ robot->score = g_value_get_long (value);
+ break;
+ case ARG_ENERGY:
+ robot->energy = g_value_get_long (value);
+ break;
+ case ARG_SHIELDS:
+ robot->shields = g_value_get_long (value);
+ break;
+ case ARG_SHOTS:
+ robot->shots = g_value_get_long (value);
+ break;
+ case ARG_UNITS:
+ robot->units = g_value_get_long (value);
+ break;
+ case ARG_USER_INTERFACE:
+ if (robot->ui != NULL) {
+ g_object_unref (robot->ui);
+ }
+
+ obj = g_value_get_object (value);
+ if (obj != NULL) {
+ robot->ui = g_object_ref (obj);
+ }
+
+ else {
+ robot->ui = NULL;
+ }
+ break;
+ case ARG_MAP:
+ if (robot->map != NULL) {
+ g_object_unref (robot->map);
+ }
+
+ obj = g_value_get_object (value);
+ if (obj != NULL) {
+ robot->map = g_object_ref (obj);
+ }
+
+ else {
+ robot->map = NULL;
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_robot_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GRobot *robot;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_ROBOT (object));
+
+ robot = G_ROBOT (object);
+
+ switch (prop_id) {
+ case ARG_POS_X:
+ g_value_set_int (value, robot->x);
+ break;
+ case ARG_POS_Y:
+ g_value_set_int (value, robot->y);
+ break;
+ case ARG_DIRECTION:
+ g_value_set_int (value, robot->dir);
+ break;
+ case ARG_SCORE:
+ g_value_set_long (value, robot->score);
+ break;
+ case ARG_ENERGY:
+ g_value_set_long (value, robot->energy);
+ break;
+ case ARG_SHIELDS:
+ g_value_set_long (value, robot->shields);
+ break;
+ case ARG_SHOTS:
+ g_value_set_long (value, robot->shots);
+ break;
+ case ARG_UNITS:
+ g_value_set_long (value, robot->units);
+ break;
+ case ARG_USER_INTERFACE:
+ g_value_set_object (value, g_object_ref (G_OBJECT (robot->ui)));
+ break;
+ case ARG_MAP:
+ g_value_set_object (value, g_object_ref (G_OBJECT (robot->map)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+GRobot *
+g_robot_new (gint x, gint y, gint dir, glong score, glong energy, glong shields,
+ glong units, glong shots, UserInterface *ui, Map *map)
+{
+
+ return g_object_new (g_robot_get_type (),
+ "x", x,
+ "y", y,
+ "direction", dir,
+ "score", score,
+ "energy", energy,
+ "shields", shields,
+ "units", units,
+ "shots", shots,
+ "user_interface", ui,
+ "map", map,
+ NULL);
+}
+
+static void
+g_robot_dispose (GObject * object)
+{
+ GRobot *robot = G_ROBOT (object);
+
+ if (robot->ui != NULL) {
+ g_object_unref (G_OBJECT (robot->ui));
+ }
+
+ if (robot->map != NULL) {
+ g_object_unref (G_OBJECT (robot->map));
+ }
+
+ parent_class->dispose (object);
+}
+
+static void
+g_robot_finalize (GObject * object)
+{
+ parent_class->finalize (object);
+}
+
+void
+g_robot_turn (GRobot *robot, gint num_turns)
+{
+ gint i;
+ gint incr;
+
+ /* turn left or right? */
+
+ incr = sign (num_turns);
+
+ for (i = 0; i < abs (num_turns); i++) {
+ robot->dir += incr;
+
+ if (robot->dir > 3) {
+ robot->dir = 0;
+ }
+
+ else if (robot->dir < 0) {
+ robot->dir = 3;
+ }
+
+ /* animate the robot */
+ user_interface_move_robot (robot->ui, robot->x, robot->y, robot->x, robot->y, robot->dir, robot->energy, robot->score, robot->shields);
+
+ robot->energy -= 2;
+
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ } /* for */
+}
+
+gboolean
+g_robot_move (GRobot *robot, gint steps)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+ gint i;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1 * sign (steps);
+ break;
+ case EAST: /* E */
+ dx = sign (steps);
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = sign (steps);
+ break;
+ case WEST: /* W */
+ dx = -1 * sign (steps);
+ dy = 0;
+ break;
+ }
+
+ /* Move the robot */
+
+ for (i = 0; i < abs (steps); i++) {
+ /* check for a space */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ /* no matter what, this took energy */
+
+ robot->energy -= 2;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE: /* space */
+ /* move the robot there */
+
+ MAP_SET_OBJECT (robot->map, robot->x, robot->y, SPACE);
+ MAP_SET_OBJECT (robot->map, x_to, y_to, ROBOT);
+
+ user_interface_move_robot (robot->ui, robot->x, robot->y, x_to, y_to, robot->dir, robot->energy, robot->score, robot->shields);
+
+ robot->x = x_to;
+ robot->y = y_to;
+ robot->units++;
+
+ break;
+
+ case BADDIE: /* baddie */
+ /* Damage */
+
+ robot->shields -= 10;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return FALSE;
+
+ break;
+
+ case WALL: /* wall */
+ /* less damage */
+
+ robot->shields -= 2;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return (FALSE);
+
+ break;
+
+ default:
+ /* even less damage */
+
+ if (--robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ return (FALSE);
+
+ break;
+ }
+ } /* for */
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_smell (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint i, j;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* no matter what, this took energy */
+
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ user_interface_robot_smell (robot->ui, robot->x, robot->y, robot->dir, robot->energy, robot->score, robot->shields);
+
+ /* Smell for the thing */
+
+ for (i = robot->x - 1; i <= robot->x + 1; i++) {
+ for (j = robot->y - 1; j <= robot->y + 1; j++) {
+ if (!(i == robot->x && j == robot->y) && MAP_GET_OBJECT (robot->map, i, j) == th) {
+ /* Found it */
+
+ return (TRUE);
+ }
+ } /* for */
+ } /* for */
+
+ /* Failed to find it */
+
+ return (FALSE);
+}
+
+gboolean
+g_robot_feel (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* determine changes to x,y */
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* no matter what, this took energy */
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ /* Feel for the thing */
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ user_interface_robot_feel (
+ robot->ui,
+ robot->x, robot->y,
+ robot->dir, x_to, y_to,
+ robot->energy, robot->score,
+ robot->shields);
+
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == BADDIE) {
+ /* touching a baddie is hurtful */
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ }
+
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == th) {
+ return (TRUE);
+ }
+
+ /* Did not feel it */
+ return (FALSE);
+}
+
+gboolean
+g_robot_look (GRobot *robot, gchar *str)
+{
+ gint th;
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ th = what_thing (str);
+
+ /* determine changes to x,y */
+ switch (robot->dir) {
+ case 0: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case 1: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case 2: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case 3: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* no matter what, this took energy */
+ if (--robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ /* Look for the thing */
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ user_interface_robot_look (
+ robot->ui,
+ robot->x, robot->y,
+ robot->dir, x_to, y_to,
+ robot->energy, robot->score,
+ robot->shields);
+
+ while (MAP_GET_OBJECT (robot->map, x_to, y_to) == SPACE) {
+ /* move the focus */
+ x_to += dx;
+ y_to += dy;
+ }
+
+ /* Outside the loop, we have found something */
+ if (MAP_GET_OBJECT (robot->map, x_to, y_to) == th) {
+ return (TRUE);
+ }
+
+ /* else, we did not find it */
+ return (FALSE);
+}
+
+gboolean
+g_robot_grab (GRobot *robot)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* Try to grab the thing */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ robot->energy -= 5;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+
+ user_interface_robot_grab (robot->ui, robot->x, robot->y, robot->dir, x_to, y_to, robot->energy, robot->score, robot->shields);
+
+ /* Did we grab it? */
+
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE:
+ case WALL:
+ case ROBOT:
+ return (FALSE);
+ break;
+
+ case BADDIE:
+ robot->shields -= 10;
+ if (robot->shields < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ return (FALSE);
+
+ case FOOD:
+ /* I want the net gain to be +10 */
+ robot->energy += 15;
+ break;
+
+ case PRIZE:
+ robot->score++;
+ break;
+ }
+
+ /* only successful grabs get here */
+ MAP_SET_OBJECT (robot->map, x_to, y_to, SPACE);
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_zap (GRobot *robot)
+{
+ gint x_to, y_to;
+ gint dx, dy;
+
+ g_return_val_if_fail (robot->ui != NULL && robot->map != NULL, FALSE);
+
+ /* determine changes to x,y */
+
+ switch (robot->dir) {
+ case NORTH: /* N */
+ dx = 0;
+ dy = -1;
+ break;
+ case EAST: /* E */
+ dx = 1;
+ dy = 0;
+ break;
+ case SOUTH: /* S */
+ dx = 0;
+ dy = 1;
+ break;
+ case WEST: /* W */
+ dx = -1;
+ dy = 0;
+ break;
+ }
+
+ /* Try to zap the thing */
+
+ x_to = robot->x + dx;
+ y_to = robot->y + dy;
+
+ robot->energy -= 10;
+ if (robot->energy < 1) {
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+ }
+ robot->shots++;
+ user_interface_robot_zap (robot->ui, robot->x, robot->y, robot->dir, x_to, y_to, robot->energy, robot->score, robot->shields);
+
+ /* Did we destroy it? */
+ switch (MAP_GET_OBJECT (robot->map, x_to, y_to)) {
+ case SPACE:
+ case WALL:
+ case ROBOT: /* what to w/ robots? */
+ return (FALSE);
+ break;
+
+ case BADDIE:
+ case FOOD:
+ case PRIZE:
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+ break;
+ }
+
+ /* only success gets here */
+ MAP_SET_OBJECT (robot->map, x_to, y_to, SPACE);
+ user_interface_add_thing (robot->ui, x_to, y_to, SPACE);
+
+ return (TRUE);
+}
+
+gboolean
+g_robot_stop (GRobot *robot)
+{
+ /* Must be a SCM function, even though it returns no value */
+ /* Stop the robot immediately */
+
+ g_signal_emit (robot, g_robot_signals[DEATH], 0);
+
+ return (TRUE); /* never gets here */
+}
+
+static gint
+what_thing (const gchar *th)
+{
+ /* what_thing - this function scans the list of possible things
+ (strings) and returns a cthing. Returns -1 if not found in the
+ list. */
+
+ /* My idea here is that by return -1 on error, this won't match
+ anything in the list of cthings. That way, the function that
+ uses what_thing to determine the cthing doesn't have to care if
+ the call failed or not. This helps me keep the code simple,
+ since now I don't have to add a branch for failure, but which
+ also decrements energy. */
+
+ gint i;
+
+ for (i = 0; i < 6; i++) {
+ if (strcmp (th, things[i]) == 0) {
+ return (cthings[i]);
+ }
+ } /* for */
+
+ /* not found */
+
+ return (-1);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ec6a581
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,565 @@
+/* $Id: main.c,v 1.28 2005/09/06 19:55:40 zeenix Exp $ */
+/*
+ GNU Robots game engine. This is the main() program, using GNU
+ Guile as my backend to handle the language.
+
+ Copyright (C) 1998 Jim Hall, jhall1@isd.net
+
+ GNU Robots 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.
+
+ GNU Robots 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 GNU Robots; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <unistd.h> /* for getopt */
+#include <string.h> /* for strdup */
+
+#include <glib.h>
+#include <gmodule.h>
+
+#include <libguile.h>
+
+#include <getopt.h> /* for GNU getopt_long */
+#include <ltdl.h> /* For loading our ui plugins */
+
+#include "grobot.h" /* the robot structure, and robot manipulation routines */
+#include "api.h" /* robot API, as Scheme functions */
+#include "userinterface.h"
+#include "config.h"
+#include "configs.h"
+#include "map.h" /* Game Map */
+#include "main.h" /* for this source file */
+
+#define BUFF_LEN 1024
+#define MODULE_PREFIX "grobots-"
+#define MODULE_PATH_MAX 256
+#define MODULE_NAME_MAX 256
+
+/* Plugins we should know about STATICALLY */
+#define X11_MODULE "x11"
+#define CURSES_MODULE "curses"
+
+/* Globals (share with api.c) */
+GList *robots = NULL;
+GRobot *robot = NULL; // The current robot
+UserInterface *ui;
+Map *map;
+GModule *plugin;
+
+UserInterface * load_ui_module (gchar *module_name, Map *map);
+SCM catch_handler (void *data, SCM tag, SCM throw_args);
+
+/************************************************************************
+ * main() *
+ * The program starts here! *
+ ************************************************************************/
+
+gint
+main (gint argc, gchar *argv[])
+{
+ gint opt; /* the option read from getopt */
+
+ gint flag; /* flag passed back from getopt - NOT
+ USED */
+ gchar maps_path[MAX_PATH], scripts_path[MAX_PATH];
+
+ gchar *main_argv[5] = { "GNU Robots",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ struct option long_opts[] = {
+ {"version", 0, NULL, 'V'},
+ {"help", 0, NULL, 'h'},
+ {"map-file", 1, NULL, 'f'},
+ {"shields", 1, NULL, 's'},
+ {"energy", 1, NULL, 'e'},
+ {"plugin", 1, NULL, 'p'},
+ {NULL, 0, NULL, 0}
+ };
+
+ /* Initialize the GType system first */
+ g_type_init ();
+
+ /* Check command line */
+
+ /* Create a robot Object */
+ robot = g_robot_new (1, 1, 1, 0, DEFAULT_ENERGY, DEFAULT_SHIELDS, 0, 0, NULL, NULL);
+
+ g_assert (robot != NULL);
+
+ /* And add to to the list of robots */
+ robots = g_list_append (robots, robot);
+
+ while ((opt = getopt_long (argc, argv, "Vhf:s:e:p:", long_opts, &flag)) != EOF) {
+ switch (opt) {
+ case 'V':
+
+ /* Display version, then quit */
+ g_printf ("\n%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("\nGNU Robots is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n");
+ g_printf ("\nGNU Robots is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n");
+ g_printf ("\nYou should have received a copy of the GNU General Public License\n"
+ "along with GNU Robots; if not, write to the Free Software\n"
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n");
+ exit (0);
+ break;
+
+ case 'h':
+
+ /* Display help, then quit. */
+
+ usage (argv[0]);
+ exit (0);
+
+ break;
+
+ case 'f':
+
+ /* Set map file */
+
+ main_argv[1] = optarg; /* pointer assignment */
+
+ break;
+
+ case 's':
+
+ /* Set shields */
+
+ robot->shields = (glong) atol (optarg);
+
+ break;
+
+ case 'e':
+
+ /* Set energy */
+
+ robot->energy = (glong) atol (optarg);
+
+ break;
+
+ case 'p':
+
+ /* Set plugin */
+
+ main_argv[3] = optarg; /* pointer assignment */
+
+ break;
+
+ default:
+
+ /* invalid option */
+
+ usage (argv[0]);
+ exit (1);
+
+ break;
+ } /* switch */
+ } /* while */
+
+ /* Extra arg is the Scheme file */
+
+ if (optind < argc) {
+ /* Set Scheme file */
+
+ main_argv[2] = argv[optind]; /* pointer assignment */
+ }
+
+ /* Check that files have been given */
+ if (main_argv[1] == NULL) {
+ main_argv[1] = g_malloc (MAX_PATH);
+ g_strlcpy (main_argv[1], DEFAULT_MAP, MAX_PATH);
+ g_fprintf (stderr, "map file not specified, trying default: %s\n",
+ main_argv[1]);
+ }
+
+ /* Check that files exist */
+ g_strlcpy (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ g_strlcpy (maps_path, MAPS_PATH, MAX_PATH);
+ g_strlcat (maps_path, "/", MAX_PATH);
+ g_strlcat (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ gchar *env = getenv (MAPS_PATH_ENV);
+
+ if (env != NULL) {
+ g_strlcpy (maps_path, env, MAX_PATH);
+ g_strlcat (maps_path, "/", MAX_PATH);
+ g_strlcat (maps_path, main_argv[1], MAX_PATH);
+
+ if (!is_file_readable (maps_path)) {
+ g_fprintf (stderr,
+ "%s: %s: game map file does not exist or is not readable\n",
+ argv[0], main_argv[1]);
+ exit (1);
+ }
+ }
+
+ else {
+ g_fprintf (stderr,
+ "%s: %s: game map file does not exist or is not readable\n",
+ argv[0], main_argv[1]);
+ exit (1);
+ }
+ }
+ }
+
+ main_argv[1] = maps_path;
+
+ /* Now the Scheme file */
+ if (main_argv[2] != NULL) {
+ g_strlcpy (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ g_strlcpy (scripts_path, SCRIPTS_PATH, MAX_PATH);
+ g_strlcat (scripts_path, "/", MAX_PATH);
+ g_strlcat (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ gchar *env = getenv (SCRIPTS_PATH_ENV);
+
+ if (env != NULL) {
+ g_strlcpy (scripts_path, env, MAX_PATH);
+ g_strlcat (scripts_path, "/", MAX_PATH);
+ g_strlcat (scripts_path, main_argv[2], MAX_PATH);
+
+ if (!is_file_readable (scripts_path)) {
+ g_fprintf (stderr,
+ "%s: %s: Scheme file does not exist or is not readable\n",
+ argv[0], main_argv[2]);
+ exit (1);
+ }
+ }
+
+ else {
+ g_fprintf (stderr,
+ "%s: %s: Scheme file does not exist or is not readable\n",
+ argv[0], main_argv[2]);
+ exit (1);
+ }
+ }
+ }
+
+ main_argv[2] = scripts_path;
+ }
+
+ else {
+ /* argv[2] can't be NULL as argv[3] may also be NULL */
+ main_argv[2] = "";
+ }
+
+ /* Start Guile environment. Does not exit */
+ g_printf ("%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("GNU Robots comes with ABSOLUTELY NO WARRANTY\n");
+ g_printf ("This is free software, and you are welcome to redistribute it\n");
+ g_printf ("under certain conditions; see the file `COPYING' for details.\n");
+ g_printf ("Loading Guile ... Please wait\n\n");
+
+ scm_boot_guile (3, main_argv, main_prog, NULL);
+
+ return 0; /* never gets here, but keeps compiler
+ happy */
+}
+
+/************************************************************************
+ * main_prog() *
+ * the main program code that is executed after Guile starts up. Pass *
+ * the Scheme program as argv[1] and the map file as argv[2]. The *
+ * program name is still argv[0]. *
+ ************************************************************************/
+
+void
+main_prog (void *closure, gint argc, gchar *argv[])
+{
+ gint i;
+ gchar *map_file = argv[1];
+ gchar *robot_program = argv[2];
+ gchar *module = argv[3];
+
+ api_init ();
+
+ g_printf ("Map file: %s\n", map_file);
+
+ map = map_new_from_file (map_file, DEFAULT_MAP_ROWS, DEFAULT_MAP_COLUMNS);
+
+ if (map == NULL) {
+ exit_nicely ();
+ }
+
+ /* ensure the robot is placed properly */
+ MAP_SET_OBJECT (map,
+ G_ROBOT_POSITION_Y (robot),
+ G_ROBOT_POSITION_X (robot),
+ ROBOT);
+
+ ui = load_ui_module (module, map);
+
+ if (ui == NULL) {
+ exit_nicely ();
+ }
+
+ /* Now initialize the rest of the Robot properties */
+ g_object_set (G_OBJECT (robot),
+ "user-interface", G_OBJECT (ui),
+ "map", G_OBJECT (map),
+ NULL);
+
+ g_signal_connect (G_OBJECT (robot), "death", G_CALLBACK (death), NULL);
+
+ /* draw the map */
+ user_interface_draw (ui);
+
+ if (strlen (robot_program) != 0) {
+ /* execute a Scheme file */
+ g_printf ("Robot program: %s\n", robot_program);
+ scm_c_primitive_load (robot_program);
+ }
+
+ else {
+ gchar buff[BUFF_LEN];
+ SCM value;
+
+ g_printf ("Robot program not specified. Entering interactive mode..\n");
+ while (1) {
+ user_interface_get_string (ui, "guile> ", buff, BUFF_LEN);
+ value = scm_internal_catch (SCM_BOOL_T,
+ (scm_t_catch_body) scm_c_eval_string,
+ (void *) buff,
+ catch_handler,
+ NULL);
+ }
+ }
+
+ /* done */
+ exit_nicely ();
+}
+
+/************************************************************************
+ * catch_handler (void *data, SCM tag, SCM throw_args);
+ *
+ * Responsible for handling errors
+ *************************************************************************/
+
+SCM catch_handler (void *data, SCM tag, SCM throw_args)
+{
+ gchar *message = "Could'nt get error message\n";
+
+ if(scm_ilength (throw_args) > 1 &&
+ SCM_NFALSEP (scm_string_p (SCM_CADR (throw_args)))) {
+ message = SCM_STRING_CHARS (SCM_CADR (throw_args));
+ }
+
+ else if (SCM_NFALSEP (scm_symbol_p (tag))) {
+ message = SCM_SYMBOL_CHARS (tag);
+ }
+
+ user_interface_update_status (ui, message, -1, -1, -1);
+
+ return SCM_BOOL_F;
+}
+
+void death (GRobot *robot)
+{
+ /* We get a ref increment on a signal */
+ g_object_unref (G_OBJECT (robot));
+
+ exit_nicely ();
+}
+
+UserInterface * load_ui_module (gchar *module_name, Map *map)
+{
+ UserInterface *ui = NULL;
+ UserInterfaceInitFunc user_interface_new = NULL;
+ gchar module_full_name[MODULE_NAME_MAX];
+ gchar module_path[MODULE_PATH_MAX];
+ gchar *module_full_path;
+ gint errors = 0;
+ const char *path = getenv (MODULE_PATH_ENV);
+
+ if (!g_module_supported ()) {
+ g_printf ("load_ui_module: %s\n", g_module_error ());
+ return;
+ }
+
+ if (path != NULL) {
+ g_strlcpy (module_path, path, MODULE_PATH_MAX);
+ }
+
+ else {
+ g_strlcpy (module_path, MODULE_PATH, MODULE_PATH_MAX);
+ }
+
+ /* Load the module. */
+ g_strlcpy (module_full_name, MODULE_PREFIX, MODULE_NAME_MAX);
+
+ if (module_name != NULL) {
+ g_strlcat (module_full_name, module_name, MODULE_NAME_MAX);
+ }
+
+ else {
+ if (getenv ("DISPLAY") != NULL) {
+ /* Yuppi! we have x */
+ g_strlcat (module_full_name, X11_MODULE, MODULE_NAME_MAX);
+ }
+
+ else {
+ g_strlcat (module_full_name, CURSES_MODULE, MODULE_NAME_MAX);
+ }
+ }
+
+ module_full_path = g_module_build_path (module_path, module_full_name);
+ plugin = g_module_open (module_full_path, 0);
+ g_free (module_full_path);
+
+ /* Find our handles. */
+ if (plugin) {
+ if (!(g_module_symbol (plugin, USER_INTERFACE_INIT_FUNCTION, (gpointer) &user_interface_new))) {
+ g_printf ("load_ui_module: %s\n", g_module_error ());
+ g_module_close (plugin);
+ plugin = NULL;
+ }
+
+ else {
+ ui = user_interface_new (map, user_interface_get_type ());
+ }
+ }
+
+ else {
+ g_printf ("error loading module '%s': %s\n", module_name, g_module_error ());
+ }
+
+ return ui;
+}
+
+/************************************************************************
+ * exit_nicely() *
+ * A function that allows the program to exit nicely, after freeing all *
+ * memory pointers, etc. *
+ ************************************************************************/
+void
+exit_nicely ()
+{
+ glong score, energy, shields, shots, units;
+
+ /* Stop the UI */
+ if (ui != NULL) {
+ g_object_unref (G_OBJECT (ui));
+ }
+
+ /* Get rid of the map object */
+ if (map != NULL) {
+ g_object_unref (G_OBJECT (map));
+ }
+
+ /* Show statistics */
+ g_object_get (G_OBJECT (robot),
+ "shields", &shields,
+ "energy", &energy,
+ "units", &units,
+ "shots", &shots,
+ "score", &score,
+ NULL);
+
+ g_list_foreach (robots, g_object_unref, NULL);
+ g_list_free (robots);
+
+ /* unload the plugin */
+ if (plugin != NULL) {
+ g_module_close (plugin);
+ }
+
+ g_printf ("\n-----------------------STATISTICS-----------------------\n");
+ g_printf ("Shields: %ld\n", (shields < 0 ? 0 : shields));
+ g_printf ("Energy: %ld\n", (energy < 0 ? 0 : energy));
+ g_printf ("Units walked: %ld\n", (units < 0 ? 0 : units));
+ g_printf ("Shots: %ld\n", (shots < 0 ? 0 : shots));
+ g_printf ("Score: %ld\n", score);
+
+ /* Show results, if any */
+ if (shields < 1) {
+ g_printf ("** Robot took too much damage, and died.\n");
+ }
+
+ else if (energy < 1) {
+ g_printf ("** Robot ran out of energy.\n");
+ }
+
+ /* Quit program */
+ exit (0);
+}
+
+/************************************************************************
+ * usage() *
+ * A function that prints the usage of GNU Robots to the user. Assume *
+ * text mode for this function. We have not initialized X Windows or *
+ * curses yet. *
+ ************************************************************************/
+
+void
+usage (const gchar *argv0)
+{
+ g_printf ("%s\n", PKGINFO);
+ g_printf ("%s\n", COPYRIGHT);
+ g_printf ("Game/diversion where you construct a program for a little robot\n");
+ g_printf ("then set him loose and watch him explore a world on his own.\n\n");
+
+ g_printf ("Usage: %s [OPTION]... [FILE]\n\n", argv0);
+ g_printf (" -f, --map-file=FILE Load map file (this option is required)\n");
+ g_printf (" -p, --plugin=PLUGIN Use plugin PLUGIN\n");
+ g_printf (" -s, --shields=N Set initial shields to N\n");
+ g_printf (" -e, --energy=N Set initial energy to N\n");
+ g_printf (" -V, --version Output version information and exit\n");
+ g_printf (" -h, --help Display this help and exit\n");
+ g_printf ("\nNote: FILE refers to a scheme file and %s enters into \n", argv0);
+ g_printf (" an interactive mode if it is not specified.\n");
+
+ g_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
+}
+
+/************************************************************************
+ * is_file_readable () *
+ * Checks if a file is a readable file. We will use this function as *
+ * part of a sanity check, before we get anywhere near having to open *
+ * files. This will save on error checking later on, when we may have *
+ * already initialized another environment (Curses, X Windows, ...) *
+ ************************************************************************/
+
+gint
+is_file_readable (const gchar *filename)
+{
+ FILE *stream;
+
+ stream = fopen (filename, "r");
+ if (stream == NULL) {
+ /* Failed */
+
+ return (0);
+ }
+
+ /* Success */
+
+ fclose (stream);
+ return (1);
+}
diff --git a/src/map.c b/src/map.c
new file mode 100644
index 0000000..bae21dc
--- /dev/null
+++ b/src/map.c
@@ -0,0 +1,297 @@
+/* GNU Robots. */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <unistd.h> /* for getopt */
+#include <stdio.h>
+#include <string.h> /* for strdup */
+
+#include <glib.h>
+
+#include "configs.h"
+#include "map.h"
+
+enum
+{
+ ARG_0,
+ ARG_SIZE
+};
+
+GType _map_type = 0;
+
+static void map_class_init (MapClass * klass);
+static void map_init (GObject * object);
+
+static void map_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void map_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+map_get_type (void)
+{
+ if (!_map_type) {
+ static const GTypeInfo object_info = {
+ sizeof (MapClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) map_class_init,
+ NULL,
+ NULL,
+ sizeof (Map),
+ 0,
+ (GInstanceInitFunc) map_init,
+ NULL
+ };
+
+ _map_type =
+ g_type_register_static (G_TYPE_OBJECT,
+ "Map",
+ &object_info,
+ 0);
+ }
+
+ return _map_type;
+}
+
+static void
+map_class_init (MapClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ gobject_class->set_property = map_set_property;
+ gobject_class->get_property = map_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZE,
+ g_param_spec_pointer ("size",
+ "Size",
+ "The size of the map",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
+
+static void
+map_init (GObject * object)
+{
+ Map *map = MAP (object);
+
+ map->_map = NULL;
+ map->size.num_rows = -1;
+ map->size.num_cols = -1;
+}
+
+/* fload_map - loads a map file into memory. */
+static void
+fload_map (Map *map, FILE * stream)
+{
+ gint ch;
+ gint i, j;
+
+ /* Read the map file */
+ i = 0;
+ j = 0;
+
+ while ((ch = fgetc (stream)) != EOF) {
+ /* Add the ch to the map */
+
+ switch (ch) {
+ case SPACE:
+ case WALL:
+ case BADDIE:
+ case PRIZE:
+ case FOOD:
+ map->_map[j][i] = ch;
+ break;
+
+ case '\n':
+ /* ignore the newline */
+ break;
+
+ default:
+ /* not a valid map char, but we'll add a space anyway */
+
+ map->_map[j][i] = SPACE;
+ break;
+ } /* switch */
+
+ /* Check for newline */
+
+ if (ch == '\n') {
+ /* the line may have ended early. pad with WALL */
+
+ while (i < map->size.num_cols) {
+ map->_map[j][i++] = WALL;
+ }
+ }
+
+
+ /* if newline */
+ /* Check for limits on map */
+ if (++i >= map->size.num_cols) {
+ /* We have filled this line */
+
+ ++j;
+ i = 0;
+
+ /* Flush the buffer for this line */
+
+ while (ch != '\n') {
+ ch = fgetc (stream);
+ }
+ }
+ /* if i */
+ if (j >= map->size.num_rows) {
+ /* the map is filled */
+
+ return;
+ }
+ } /* while fgetc */
+
+ /* After the loop, we are done reading the map file. Make sure this
+ is bounded by WALL. */
+ if (i > 0) {
+ ++j;
+ }
+
+ for (i = 0; i < map->size.num_cols; i++) {
+ map->_map[j][i] = WALL;
+ }
+}
+
+static void
+cleanup_map (Map *map)
+{
+ gint i, j;
+
+ /* make sure there is a wall at top/bottom */
+
+ for (i = 0; i < map->size.num_cols; i++) {
+ map->_map[0][i] = WALL;
+ map->_map[map->size.num_rows - 1][i] = WALL;
+ }
+
+ /* make sure there is a wall at left/right */
+
+ for (j = 0; j < map->size.num_rows; j++) {
+ map->_map[j][0] = WALL;
+ map->_map[j][map->size.num_cols - 1] = WALL;
+ }
+}
+
+static void
+map_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ Map *map;
+ guint i;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_MAP (object));
+
+ map = MAP (object);
+
+ switch (prop_id) {
+ case ARG_SIZE:
+ /* Free the map if any */
+ if (map->_map != NULL) {
+ for (i = 0; i < map->size.num_rows; i++) {
+ g_free (map->_map[i]);
+ }
+
+ g_free (map->_map);
+ }
+
+ /* Get the new size of the map */
+ g_memmove (&map->size, g_value_get_pointer (value), sizeof (MapSize));
+
+ /* Allocate the according to the new size */
+ map->_map = g_malloc (map->size.num_rows * sizeof (gint **));
+
+ for (i = 0; i < map->size.num_rows; i++) {
+ map->_map[i] = g_malloc (map->size.num_cols * sizeof (gint));
+ }
+
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+map_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ Map *map;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (G_IS_MAP (object));
+
+ map = MAP (object);
+
+ switch (prop_id) {
+ case ARG_SIZE:
+ g_value_set_pointer (value, g_memdup (&map->size, sizeof (MapSize)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+Map *
+map_new_from_file (const gchar *map_file, gint num_rows, gint num_cols)
+{
+ GObject *object;
+ Map *map;
+ gint **buf;
+ guint i;
+ FILE *stream;
+ MapSize size;
+
+ size.num_rows = num_rows;
+ size.num_cols = num_cols;
+
+ stream = fopen (map_file, "r");
+
+ if (stream != NULL) {
+ map = MAP (g_object_new (map_get_type (),
+ "size", &size,
+ NULL));
+ fload_map (map, stream);
+ fclose (stream);
+ cleanup_map (map);
+
+ return map;
+ }
+
+ /* else, no file to open */
+ else {
+ g_warning ("Could not open map file: %s\n", map_file);
+ return NULL;
+ }
+}
+
diff --git a/src/sign.c b/src/sign.c
new file mode 100644
index 0000000..07c9d7a
--- /dev/null
+++ b/src/sign.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <glib.h>
+
+/* is there a standard C function to do this? */
+
+gint
+sign (gint n)
+{
+ if (n < 0) {
+ return (-1);
+ } else if (n > 0) {
+ return (+1);
+ }
+
+ return (0);
+}
diff --git a/src/userinterface.c b/src/userinterface.c
new file mode 100644
index 0000000..c55f64f
--- /dev/null
+++ b/src/userinterface.c
@@ -0,0 +1,192 @@
+/* $Id: userinterface.c,v 1.7 2004/10/21 19:24:30 zeenix Exp $ */
+
+/* GNU Robots game engine. This is the User Interface module */
+
+/* Copyright (C) 1998 Jim Hall, jhall1@isd.net */
+
+/*
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib.h>
+
+#include "configs.h"
+#include "userinterface.h"
+
+/*enum
+{
+ ARG_0,
+ ARG_MAP
+};*/
+
+GType _user_interface_type = 0;
+
+static void user_interface_base_init (UserInterfaceClass * klass);
+
+GType
+user_interface_get_type (void)
+{
+ if (!_user_interface_type) {
+ static const GTypeInfo interface_info = {
+ sizeof (UserInterfaceClass),
+ (GBaseInitFunc) user_interface_base_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ NULL
+ };
+
+ _user_interface_type = g_type_register_static (G_TYPE_INTERFACE,
+ "UserInterface",
+ &interface_info,
+ 0);
+ }
+
+ return _user_interface_type;
+}
+
+static void
+user_interface_base_init (UserInterfaceClass * klass)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized) {
+ /*GObjectClass *gobject_class =
+ g_type_class_peek (((GTypeInterface *) klass)->g_instance_type);
+
+ g_object_class_install_property (gobject_class, ARG_MAP,*/
+ g_object_interface_install_property (
+ klass,
+ g_param_spec_object ("map",
+ "Map",
+ "Reference to the Game Map object",
+ G_TYPE_MAP,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ initialized = TRUE;
+ }
+}
+
+void user_interface_add_thing (UserInterface *ui,
+ gint x,
+ gint y,
+ gint thing)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_add_thing (ui, x, y, thing);
+}
+
+void user_interface_draw (UserInterface *ui)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_draw (ui);
+}
+
+void user_interface_move_robot (UserInterface *ui,
+ gint from_x,
+ gint from_y,
+ gint to_x,
+ gint to_y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_move_robot (ui, from_x, from_y, to_x, to_y, cdir, energy, score, shields);
+}
+
+/* user_interfaces to animate the robot */
+ void user_interface_robot_smell (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_smell (ui, x, y, cdir, energy, score, shields);
+}
+
+void user_interface_robot_zap (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_zap (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_feel (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_feel (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_grab (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_grab (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+void user_interface_robot_look (UserInterface *ui,
+ gint x,
+ gint y,
+ gint cdir,
+ gint x_to,
+ gint y_to,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_robot_look (ui, x, y, cdir, x_to, y_to, energy, score, shields);
+}
+
+/* user_interfaces to get/display data from/to user */
+void user_interface_get_string (UserInterface *ui,
+ gchar *prompt,
+ gchar *buff,
+ gint len)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_get_string (ui, prompt, buff, len);
+}
+
+void user_interface_update_status (UserInterface *ui,
+ const gchar *s,
+ glong energy,
+ glong score,
+ glong shields)
+{
+ USER_INTERFACE_GET_CLASS (ui)->user_interface_update_status (ui, s, energy, score, shields);
+}
+