From: Holger Schemel Date: Sat, 30 Aug 2014 08:32:16 +0000 (+0200) Subject: Merge branch 'master' into releases X-Git-Tag: 1.2.0^0 X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=commitdiff_plain;h=372782865e5e5791701d0f2bdfaa454cf45a59c3;hp=c95428b8dc9d94d39c70acf804826150598a8bdf Merge branch 'master' into releases --- diff --git a/CHANGES b/CHANGES index 5ad2b64d..4a42a215 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,70 @@ -Prerelease Version 0.9b [4 NOV 95] ------------------------------------- +Release Version 1.2.0 [5 DEC 1998] +-------------------------------------------------------- + - DOS/Windows version + - new WAV sound loader + - new PCX graphics loader + - network multiplayer games with upto four players + - no separate network server needed; each client can + fork a network server at startup if there's no server + running at this moment + - possibility to invoke the game to act as a standalone + network server (on a separate machine, for example) + - local multiplayer games with upto four players + - support for upto four joysticks + - completely free customizable keyboard and joystick + for all four players individually + - new joystick calibration screen which can be left + (with Escape key) if no joystick is connected... ;-) + - new (working) GIF graphics loader (but still support + for the old XPM method) + - supports private colormap with extremely less flashing + on 8-bit (256 colors) displays + - soft-scrolling with 50 frames per second (which raises + the system requirements and makes it completely + unplayable on my "old reference" 486/33 (where 0.9b runs + smoothly) and running at 90% speed on my K6-200. + - completely new file format for personal setup data + in ASCII format which is human readable and easily + customizable even with a texteditor; stored in the + user's home directory and no longer somewhere in the + game's installation directory + - high score lists changed: now one file per level and + no longer one file per level series; now using readable + ASCII format + - useful command line options to specify the X11 display, + the game's base (installation) directory, an alternate + level directory, standalone server execution and verbose + execution + +Release Version 1.1 [???] [NOT RELEASED] +---------------------------------- + - new (but broken) GIF graphics loader to be independent + from the XPM library and replace all graphics by GIFs. + +Release Version 1.0 [9 APR 1997] [NOT RELEASED] +--------------------------------------------- + - the game now contains many really playable levels, + not only a few levels for testing + - the game is now even better playable by keyboard + (now you have the same gameplay functionality + compared to playing with a joystick. Especially + there are diagonal directions with keyboard playing + and the fire buttons are mapped to the shift keys) + - a lot of new elements for better emulation of levels + from the games "Boulderdash", "Emerald Mine" and + "Sokoban". New elements to build "Dynablaster" style + levels. + - enhanced functionality of the level tape recorder + to make it possible to go on with a game at any tape + position + +Prerelease Version 0.9b2 [21 NOV 1995] [NOT RELEASED] +--------------------------------------------------- + - new game elements + +Prerelease Version 0.9b [4 NOV 1995] +---------------------------------- - the game is now completely Freeware - the game is now better playable by keyboard (in the last version, the player was making more than @@ -15,6 +79,6 @@ Prerelease Version 0.9b [4 NOV 95] - FreeBSD sound and joystick support (thanks to Jean-Marc Zucconi) -Prerelease Version 0.9 [23 OCT 95] +Prerelease Version 0.9 [23 OCT 1995] ---------------------------------- - first (pre)release version diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..a43ea212 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + 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. + + + Copyright (C) 19yy + + 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. + + , 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/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index b2b7fc7d..00000000 --- a/COPYRIGHT +++ /dev/null @@ -1,25 +0,0 @@ -This program is copyrighted (c) 1995 by Holger Schemel. - -It is freely distributable as long as no profit is made with it -and as long as the package is left complete and unmodified. - -The fact that this program comes with full source does not mean -that you can do what you want with it - it is only intended to -give you the chance to build it on your own machine. - -If you want to distribute this program on CDROM, you have to ask for -permission first -- just send me E-Mail and tell me what kind of -CDROM it is. Normally I will give my permission if - - the CDROM itself contains only freely distributable software - - the author of this program (me!) gets a free copy of the CDROM - - the program is distributed in its original, unmodified package - -If the three conditions above are fulfilled, this permission will -automatically given to the following CDROM distributions: - - InfoMagic "LINUX Developer's Resource" - - The Debian Linux Distribution CDROM - - any CDROM with a mirror of sunsite.unc.edu or a mirror of another - FTP server that contains this program - -If you are in doubt (e.g., want to distribute a pre-installed version), -feel free to mail me about it (see the file 'README' in this archive). diff --git a/CREDITS b/CREDITS new file mode 100644 index 00000000..bb187417 --- /dev/null +++ b/CREDITS @@ -0,0 +1,3 @@ + +[Credits file yet to be written.] + diff --git a/DISCLAIMER b/DISCLAIMER deleted file mode 100644 index b6e06a6e..00000000 --- a/DISCLAIMER +++ /dev/null @@ -1,5 +0,0 @@ - -THIS GAME IS PROVIDED "AS IS" -- USE IT AT YOUR OWN RISK! -IF THIS GAME BLOWS UP YOUR COMPUTER OR OPERATING SYSTEM -OR ANYTHING ELSE, IT'S NOT MY FAULT! I'M NOT RESPONSIBLE -FOR ANY DAMAGE THAT MIGHT BE CAUSED BY MY PROGRAM! diff --git a/HARDWARE b/HARDWARE new file mode 100644 index 00000000..49de985a --- /dev/null +++ b/HARDWARE @@ -0,0 +1,92 @@ + +[Very outdated -- should be rewritten...] + + +Some recommendations for more fun playing Rocks'n'Diamonds: +=========================================================== + +About sound +----------- +It is highly recommended to have a decent sound interface for playing +this game (although it only comes with bad-quality 8000-Hz-samples to +save memory and to be compatible with /dev/audio). + +The best sound platform is an actual Linux system with (at least) kernel +1.2.x, because it offers some nice real-time sound features which are +needed to have background music loops in the game. + +On all other systems you don't have music loops, but you still have all +the other sounds. + + +About game speed +---------------- +You should have a relatively fast hardware. + +The game was developed on a i486/33 (which is three years old now), +and you should probably better not try to run it on a slower system. + +You should have an accelerated graphic card; I have found out that it +starts being playable on my 486/33 with an old ISA cirrus logic 5426 +graphic card, which has a blitter that is supported by XFree86[tm], +but that it was nearly unplayable on a 486/66 with old, unaccelerated +ET4000. + +If all works fine, you should have something around 30 frames per second. + +If you think that the game is to slow to play, you should try out the +following things: + +- Set "Buffered Gfx" to "off" in the setup menu. Normally (on a fast + enough system) you should use buffered graphics, which means that + all graphics is drawn into an invisible Pixmap and is then copied + to the X11 window to avoid flickering. If you disable this double + buffering, the graphic is directly drawn into the window. This can + cause some slight flickering, but makes graphic operations roughly + twice as fast compared to double buffering. + +- Set "Game Music" to "off" in the setup menu (and maybe "sound loops" + too). Where disabling buffered graphics may be required with slow + graphics hardware, disabling sound is especially recommended on slow + CPU systems (486/33 and slower), because the sound server eats up a + significant amount of CPU time when playing long sounds. + +You might also notice that bigger levels tend to be slower on slow +systems. + +About the option "Fading" in the setup menu: It gives a nice looking +fading when switching to a new screen, but you should really only try +this out if you think that you have a very fast graphics hardware. + + +About music +----------- +The background music loops are ripped out from several nice music albums. +Just have a look at the info screen to find out from which album each +sound loop came from -- they are all very well done pieces of music, but +unfortunately they don't sound better after converting them to 8 kHz +samples (to conform to standard SUN /dev/audio). Maybe I change this to +a better quality in the future, but at the moment, where the sounds +directory has a size of nearly a megabyte, I'll stay with 8 kHz samples. + +So, if you have a non-Linux system (which cannot play sound loops) or +don't like the "telephone quality" of the music loops, just get some of +these CDs and play them while your playing the game! ;-) + + +About game-play +--------------- +It is *strongly recommended* to play this game with a high-quality joystick. +That means, throw your $10 joystick out of the window and buy a decent +Competition-Pro Digital PC joystick or a high-quality CH Products Analog +joystick. Believe me, it doubles the fun of playing the game. + +If you only have a normal Unix system (and no fine Linux system), you +are forced to play with the keyboard. It works, but is not only less fun, +but also more difficult with some levels, because you cannot move in +diagonal directions with keyboard control at the moment. Another bad thing +is that you will have some problems when pressing many keys at the same +time. This might change in the future, when I implement a better keyboard +handling which not only solves these problems but allows diagonal directions, +too. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..697475a7 --- /dev/null +++ b/INSTALL @@ -0,0 +1,85 @@ + +Installation instructions for Rocks'n'Diamonds 1.2.0 +==================================================== + +Compilation +----------- + +If your system supports Linux/i386/ELF/libc5 executables (Linux package) +or if you run DOS/Windows (DOS package), you can directly use the included +precompiled binary. + +If you use a different system, just recompile the game: + +If you use Linux with gcc or DOS/Windows with djgpp, just try 'make' +which should work without problems. + +If you use SUN/Solaris with gcc and GNU make, try 'make solaris'. + +If the above doesn't work, edit the Makefile in the top level directory. +If it doesn't work either, edit the Makefile in the 'src' subdirectory. + +If you had to modify any Makefile to compile it, please drop me a note +about it to 'aeglos@valinor.owl.de'. Thanks! + + +Customization +------------- + +The following configuration options in the top level Makefile help +you to customize the game to your system and your environment: + +CC Choose your favorite ANSI C compiler. + Default is 'gcc'. + +PLATFORM Choose your platform, if auto detection fails. + Auto detection should work for Linux and DOS + (just type 'make'), on SUN/Solaris systems 'make solaris' + should work. Other systems may need additional editing + of 'src/Makefile' to set some additional compiler options. + +X11_PATH Specify the path to your X11 installation. Include files + and libraries are searched for at $(X11_PATH)/include and + $(X11_PATH)/lib, if you set this variables. If you don't + set this variable, your compiler must be able to find X11 + by itself, which works fine for Linux, for example. + +GAME_DIR Specify the directory where the program looks for all the + graphics, sounds, levels and high scores. If you leave this + commented out, the current directory ('.') is used, which + lets you use the game without installing it somewhere in + your system (although you have to 'cd' to the game directory + each time you want to play it). + +JOYSTICK Uncomment this line if your system does not support game + port hardware like joysticks (and has therefore no joystick + include file). Currently the game should work with joysticks + on Linux and FreeBSD. + +SOUNDS Uncomment this line if your system does not support audio + hardware. Currently the game should work with sound support + on Linux, FreeBSD, SUN/Solaris, HP-UX and most Unix system + that support '/dev/dsp' or '/dev/audio' devices. + +SCORE_ENTRIES Choose if you want to allow many entries in the high score + table for one player or exactly one entry. Systems with a + lot of users maybe want to limit high score entries to only + one entry for each player (and therefore set 'SCORE_ENTRIES' + to 'ONE_PER_NAME') where systems used by only one person + maybe want to use the default of 'MANY_PER_NAME' which is + automatically choosen if you leave everything commented out. + +Modifications of the Makefile in the directory 'src' are normally not needed. +If the game fails to compile out of the box, you may have to modify some +of the system variables there to get it to compile. + +SYSTEM May need to be set to some system dependend values. + +INCL, LIBS Maybe some more directories for include files and libraries + have to be added to this variables depending on your system. + + +If you have any comments, additions or modifications to the Makefile(s), +please send me mail: 'aeglos@valinor.owl.de'. Thanks! + +05-DEC-1998, Holger Schemel diff --git a/INSTALLATION b/INSTALLATION deleted file mode 100644 index 298ff6d6..00000000 --- a/INSTALLATION +++ /dev/null @@ -1,68 +0,0 @@ - -WHAT TO DO TO INSTALL "ROCKS_N_DIAMONDS-0.9" ON YOUR SYSTEM -=========================================================== - -If you have a Linux system (Intel based, a.out, kernel 1.2.x), you -can use the precompiled binary. - -If you have another Unix system, or an ELF system or just want to -compile the program by yourself, do the following: - -Edit the file "Makefile" and set the following options: - -XPM_INCLUDE_FILE - change this to the location where you - have your XPM-Library include file. - - You must have the XPM-Library "libXpm" - installed on your system to run this game. - If you don't have it, look at your local - FTP site with X11 archive to get it! :) - -GAME_DIR - You can leave these values untouched - if you use the default location for - the game directory. - If you want to move it to other places in - your directory tree, just change them - accordingly. (You can use symlinks instead, - of course.) - You might want to set GAME_DIR to the full - path of the game in your file system, so - you don't have to go to the game directory - when you want to play it. - -SOUNDS - If you never want to hear any sounds, - set this to "-DNO_SOUNDS", but be warned: - It's much less fun playing without sound! :) - (The program detects by itself if it can - play sounds or not, anyway.) - -SCORE_ENTRIES - Set this to "-DONE_PER_NAME" if you want - to allow only one entry per player in the - score file for each level. This is useful - if there are many players to prevent one - single player to "flood" the Hall Of Fame - of every level completely with his name... - On single user systems, "-DMANY_PER_NAME" - might be useful to have your name more - than once in the list. - -SYSTEM - If you have problems with the default - settings, it might be useful to uncomment - one of the defines for "SYSTEM" in the - Makefile, which defines values like - "-DSYSV" and something like that. - -CC, INCL, LIBS - Set these ones to the appropriate values - you usually use on your system to compile. - - -Now you can 'make clean' and 'make' and the game binary should be -compiled right out of the box. I have tested it with "-Wall" on my -system, so I hope that it compiles fine on other systems, too. - -The program should compile and run on Linux (of course), -HP-UX, AIX, Net-BSD, SUN and IRIX. - -Have fun! - -Holger Schemel, 22. Oktober 1995 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..3e80fafd --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +#=============================================================================# +# Makefile for Rocks'n'Diamonds 1.2 # +# (c) 1995-98 Holger Schemel, aeglos@valinor.owl.de # +#=============================================================================# + +#-----------------------------------------------------------------------------# +# configuration section # +#-----------------------------------------------------------------------------# + +# specify your favorite ANSI C compiler +CC = gcc + +# explicitely choose your platform, if defaults doesn't work right +# needed for SUN/Solaris; Linux and DOS work fine with auto detection +# PLATFORM = solaris +# PLATFORM = unix +# PLATFORM = dos + +# specify path to X11 on your system +# if undefined, use system defaults (works fine with Linux/gcc) +# X11_PATH = /usr/X11 + +# specify path to install game data (graphics, sounds, levels, scores) +# default is '.', so you can play without installing game data somewhere +# GAME_DIR = /usr/local/games + +# uncomment this if your system has no joystick include file +# JOYSTICK = -DNO_JOYSTICK + +# uncomment this if your system has no sound +# SOUNDS = -DNO_SOUNDS + +# choose if you want to allow many global score file entries for one player +# default is 'MANY_PER_NAME' +# when installing the game in a multi user environment, choose this +# SCORE_ENTRIES = ONE_PER_NAME +# when installing the game in a single user environment, choose this +# SCORE_ENTRIES = MANY_PER_NAME + +#-----------------------------------------------------------------------------# +# you should not need to change anything below # +#-----------------------------------------------------------------------------# + +.EXPORT_ALL_VARIABLES: + +MAKE = make + +SRC_DIR = src +MAKE_CMD = @$(MAKE) -C $(SRC_DIR) + + +all: + $(MAKE_CMD) + +solaris: + $(MAKE_CMD) PLATFORM=solaris + +clean: + $(MAKE_CMD) clean diff --git a/README b/README index e8933d0d..a16fd5ed 100644 --- a/README +++ b/README @@ -1,16 +1,15 @@ Welcome to - R O C K S ' N ' D I A M O N D S - ----------------------------------- + R O C K S ' N ' D I A M O N D S ' 9 8 + ------------------------------------------- -A game for Unix/X11 by Holger Schemel, (c) 1995 by Holger Schemel. +A game for Unix/X11 by Holger Schemel, (c) 1995-98 by Holger Schemel. Introduction ============ This is a nice little game with color graphics and sound for your Unix system with color X11. You need an 8-Bit color display or better. -It is not recommended on black&white systems, and maybe not on gray -scale systems. +It will not work on black&white systems, and maybe not on gray scale systems. If you know the game "Boulderdash" (Commodore C64) or "Emerald Mine" (Amiga), you know what "ROCKS'N'DIAMONDS" is about. @@ -18,48 +17,53 @@ If you know the game "Boulderdash" (Commodore C64) or "Emerald Mine" Getting started =============== -Just 'cd' to the 'rocks_n_diamonds' directory and type 'rocksndiamonds'! -This works only on Linux boxes, because the included binary was -compiled for Linux systems. If you have another Unix system like -HPUX, NetBSD or SUN, you first have to type 'make' to compile it. -This may be needed on Linux systems, too, if you have an older -system (kernel, libraries, ...) or if you have only ELF libraries. +Just 'cd' to the directory 'rocksndiamonds-*' (Unix) or 'rocks-*' (DOS) +and type 'rocksndiamonds' (Linux) or 'rocks' (DOS/Windows)! +This works only on Linux and DOS systems, because the included binary was +compiled for Linux (i386/libc5) (if you have the Unix package) and DOS +(if you have the DOS/Windows package). +If you have another Unix system like HPUX, NetBSD or SUN, you first have to +type 'make' to compile it. +This may be needed on Linux systems, too, depending on your kernel version, +your libc version, your binary format, your processor, ... (The included binary was compiled on the following system: -Kernel 1.2.13, libc 4.5.26, GCC 2.5.8, 'a.out' format) +AMD K6, kernel 2.0.35, libc5, gcc 2.7.2.1, ELF format) + The Menues ========== You can see eight blue circles on the left side of the eight green menu texts; these are buttons to activate the menu commands by simply clicking -on them with the left mouse button. The button will then change to red. +on them with a mouse. The button will then change to red. (You can control the menues over the keyboard or joystick, too. Just use the arrow keys and the 'Return' or 'Enter' key or, if you use a joystick, the appropriate direction and the fire button.) -The menu 'name' ---------------- +The menu 'name' / 'team' +------------------------ When you start the game the first time, your login name will appear in the 'NAME:' field. If you want to use a different name for playing, for example a funny player name or a name for cheating, you can click on the button and enter a new name. -If you choose a certain special name, you will be in a cheat mode where -you can choose all levels without playing the lower levels before... :) +This menu will show the text 'team' instead of 'name' if you activated +the team (local multiplayer) mode in the setup menu. See below. The menue 'level' ----------------- -If you have played some levels of this game, you can choose the already -played levels at any time, but you cannot choose the higher levels. This -means, you can choose levels from level 0 to the highest level that you -have ever won. This is known as your 'handicap'. +Choose any level from the current level series you want. The former +'handicap' limitation in choosing levels has been removed because of +beeing annoying. -If the level number is red, you have choosen a 'ready' level, if it is -yellow, you have choosen a 'user' level, which is blank and can be -edited by yourself with the built-in level editor (see below). +If the level number is red, you have choosen a 'ready' level series (which +is read-only and cannot be modified by the level editor); if it is yellow +you have choosen a 'user' level series (which is writable and can be changed +by the builf-in level editor). See below for using the level editor. To choose new level series, click on the button on the left and choose -the new level serie. +the new level series. Scroll the page up and down with the blue arrow +buttons if there are more level series than would fit on the screen. Hall of fame ------------ @@ -69,46 +73,81 @@ Click again to go back to the main menu. Level creator ------------- This brings you to the level editor, if you have switched to a 'yellow' -level, which are empty and can be filled by yourself. See below. +(writable) level series. Info screen ----------- This screen shows you all elements which appear in the game and presents you the background music loops which you can listen to while playing the -levels (only available on Linux systems). +levels (not available on all systems). Start game ---------- -This will start the game. +This will start the game. The game will be automatically recorded 'on tape' +if you have choosen this from the setup menu (see below). If you haven't +choosen auto-recording level, but want to record this certain game, press +the 'record' button on the level tape recorder to start game and recording. Setup ----- To change some things in the game, use the setup menu. You can enable/disable "Sound" (enables/disables _all_ sounds in -the game), "Sound loops" (only allowed on Linux systems with -VoxWare[tm] sound driver; don't worry if you never heard of it -- -it's the name of the standard Linux sound driver), "Game music" +the game), "Sound loops" (only useful on Linux systems), "Game music" (can always be enabled on very fast systems [exception: you don't like it], on slower systems it will take some percent of CPU time which will slow things down a bit) and "Toons", which will forbid/ permit the little animated toons. -"Buffered Gfx" can be set to "off" on slower systems, "Fading" gives -a nice fading effect when displaying new screens, but unfortunately -I haven't found a system which is fast enough to display it so far. -(Maybe this works better on highly accelerated X servers.) Better set -this to "off" if you have a normal system... +Forget about the setup options "Buffered Gfx" and "Fading" -- they +have no effect at the moment and will probably disappear in future +versions of the game. (Double-buffering is now always activated, because +systems are fast enough now compared to 1995, when the last version of the +game was released. Especially soft-scrolling needs the double-buffering. +About fading from one screen to another with silly effects: Most players +will probably deactivate it after a few minutes (see also "quick doors").) + +Enable "scroll delay" to avoid scrolling at each step, giving you an area +where you can walk without scrolling until you get near enough to the screen +border. + +Enable "soft scroll" for soft-scrolling. Looks nice, but may need a +relatively fast graphics card. Systems from 1998 and later should be fast +enough for enabling soft-scrolling. + +Enable "quick doors" if you are unpatient when switching between the +several game screens where the doors have to be opened or closed. You will +almost surely enable this if you design your own levels and therefore +often switch between game and editor screens. Set "auto-record" to "on" if you want to automatically record each game -to tape. +by the built-in level tape recorder. -If you have a Linux system with a joystick, you can choose the "1st" or -the "2nd" joystick port and use "Cal. Joystick" to calibrate it. Use -"Save and exit" after calibration to save it for later playing sessions. +For configuration of input devices like keyboard and joysticks, choose +the sub-menu "input devices". "Exit" quits the setup menu without saving the changes, "Save and exit" will save and then return to the main menu. + +Input Devices (sub-menu of the setup menu) +------------------------------------------ + +"Player" lets you choose one of the four players. + +"Device" lets you choose the input device you want for this player; +you can choose between the keyboard and one of the maximal four supported +joysticks. (Normally you won't have more than two joysticks, but the Linux +joystick driver supports more than two joysticks.) + +"Customize" / "Calibrate" lets you calibrate a joystick or customize the +keyboard keys used for moving left, right, up and down, "snapping" fields +without moving towards them and placing bombs. Just press the key you want +to use for the specified action or press Return or Enter to stay with the +already configured values. + +"Exit" brings you back to the setup screen. + + Quit ---- Exit the game. @@ -141,55 +180,39 @@ Stop/Pause/Play Game controls to stop the game, pause it and go on Music buttons The three music buttons can be used to control the background music loop, the 'looping' sounds and all other sounds. The little red light shows you - if it is enabled or disabled. On slower systems - (and a 486DX33 with Soundblaster _is_ a slower - system) it increases the game speed to turn off - background music. You can completely turn off all - sound effects in the setup menu, although it is - much more fun to have them enabled when it - doesn't eats up to much speed. - - (A little note: The sound server currently needs - about 10% CPU time on my 486DX/33/SBPro system - when playing background music. I wonder if this - would get better with a better soundcard, like - Gravis Ultrasound, or if only pure CPU power - helps in this case...) + if it is enabled or disabled. About the game itself: Of course you know Boulderdash, so you will know how to play the game. :) -If not: You can move your playing figure (the smiley) with the arrow -keys or with the joystick (if you have no joystick and even no arrow -keys on your keyboard, you can use the keys 'i', 'j', 'k' and 'm' for -the directions. To 'snap' a field near you without moving to it, you +If not: You can move your playing figure with the configured keys (which +will normally and by default be the arrow keys) or with a joystick. +To 'snap' a field near you without moving to it, you can use the left fire button on your joystick (hold it down, move the -stick to 'snap' the field, release the button) or the keys 'e', 's', -'d' and 'x'. To place a piece of dynamite, use the right fire button -on your joystick or use the 'b' key (and, after placing the dynamite, -better see to move away from this field...). +stick to 'snap' the field, release the button) or the key you have +configured for this action (by default one of the left modifier keys like +'Shift' or 'Control'). +To place a piece of dynamite, use the right fire button on your joystick or +use the key you have configured for this (by default one of the right modifier +keys, but you can change all this to what you like). +After placing the dynamite, better see to move away from this field...). Just try the levels from the 'tutorial' level serie to see what most of the elements do or have a look at the info screen! -Note: It is *highly recommended* to use a joystick for playing this -game! It is possible to play it with the keyboard, but it is *much -more fun* to play with a joystick, and some levels are very difficult -to solve with the keyboard. So, the best platform for this game is a -Linux system (which gives you background music, too). The Level Editor ================ -To build your own levels, just choose a 'yellow', empty level. If you -cannot find any 'yellow' levels, choose a different level serie or -choose the higher level numbers (if you have a small 'handicap' number, -the higher levels will be skipped to reach the 'empty' levels. - -Another way is to create your own level series. Just add a line to the -file 'levels/ROCKS.levelinfo' with the following entries: -- the name of the level directory (create this directory under 'levels') -- the name of the level serie (don't use any whitespaces within the name) -- the 'ready' (red) levels (start with zero) -- the 'empty' (yellow) levels (set this to some number of blank levels) +To create your own levels, it's a good idea to start with your personal +level series, which has been created automatically the first time you +started the game (together with some configuration files). These personal +files are stored in '~/.rocksndiamonds' on Unix systems and in 'userdata' +in the current playing directory (which normally is the game directory) +on DOS/Windows systems. + +The levels that come with the game are normally read-only, to avoid +problems on multi user systems, but you can set them to 'writable' in +the file 'levelinfo.conf' ('lvlinfo.cnf' on DOS systems) in each level +directory. To edit a level, you can use all three mouse buttons to draw in the level window. Click into the elements field with one of the three buttons @@ -217,12 +240,9 @@ played games. Just use them like a normal video recorder. Recording a game on tape: ------------------------- -Just press the 'record' button (the one with the red point on it) and -either press 'Start Game' or press on 'record' or 'pause' to end the -pause mode and start playing and recording. - -If you have set "auto record" in the setup menu to "on", you just have -to press 'Start Game' as usual. +If you have enabled "auto-record", every game will automatically be recorded, +so you just have to press "start game". Pressing the 'record' button on the +tape recorder will start game and record it in any case. Saving a game tape: ------------------- @@ -240,23 +260,38 @@ or the playing of the tape and continue by pressing 'pause' again. You can use either the tape recorder buttons or the game control buttons for this purpose. +If you want to continue a previously recorded game, press 'pause' while +playing, then 'record' to switch from 'paused playing' to 'paused recording' +and then continue the game by pressing 'record' or 'pause'. If you want +to fast-forward the tape to get faster to the point where you want to +continue playing, press 'play' again while already playing, therefore +activating 'fast forward' playing mode. Press again the 'play' button +to enter a special playing mode: 'pause before end' will stop a few seconds +before the end of the tape (which will in most cases stop a few seconds +before you get killed in the previous playing recorded on that tape) -- +after the automatic stop (which enters the 'pause' mode) you can continue +the game as described above. + And Now Have Fun! ================= Have fun playing the game, building new levels and breaking all high -scores! ;) +scores! :-) + +If you have designed new levels, mail them to me to include them in the +next version (which will be released much earlier than again after three +years like this version... ;-) If you have any comments, problems, suggestions, donations, flames, send them to aeglos@valinor.owl.de -or aeglos@uni-paderborn.de -or Snail Mail +or Snail Mail to Holger Schemel - Sennehof 28 - 33659 Bielefeld + Oststrasse 11a + 33604 Bielefeld GERMANY Have fun, diff --git a/RECOMMENDATIONS b/RECOMMENDATIONS deleted file mode 100644 index a08795b4..00000000 --- a/RECOMMENDATIONS +++ /dev/null @@ -1,89 +0,0 @@ - -Some recommendations for more fun playing Rocks'n'Diamonds: -=========================================================== - -About sound ------------ -It is highly recommended to have a decent sound interface for playing -this game (although it only comes with bad-quality 8000-Hz-samples to -save memory and to be compatible with /dev/audio). - -The best sound platform is an actual Linux system with (at least) kernel -1.2.x, because it offers some nice real-time sound features which are -needed to have background music loops in the game. - -On all other systems you don't have music loops, but you still have all -the other sounds. - - -About game speed ----------------- -You should have a relatively fast hardware. - -The game was developed on a i486/33 (which is three years old now), -and you should probably better not try to run it on a slower system. - -You should have an accelerated graphic card; I have found out that it -starts being playable on my 486/33 with an old ISA cirrus logic 5426 -graphic card, which has a blitter that is supported by XFree86[tm], -but that it was nearly unplayable on a 486/66 with old, unaccelerated -ET4000. - -If all works fine, you should have something around 30 frames per second. - -If you think that the game is to slow to play, you should try out the -following things: - -- Set "Buffered Gfx" to "off" in the setup menu. Normally (on a fast - enough system) you should use buffered graphics, which means that - all graphics is drawn into an invisible Pixmap and is then copied - to the X11 window to avoid flickering. If you disable this double - buffering, the graphic is directly drawn into the window. This can - cause some slight flickering, but makes graphic operations roughly - twice as fast compared to double buffering. - -- Set "Game Music" to "off" in the setup menu (and maybe "sound loops" - too). Where disabling buffered graphics may be required with slow - graphics hardware, disabling sound is especially recommended on slow - CPU systems (486/33 and slower), because the sound server eats up a - significant amount of CPU time when playing long sounds. - -You might also notice that bigger levels tend to be slower on slow -systems. - -About the option "Fading" in the setup menu: It gives a nice looking -fading when switching to a new screen, but you should really only try -this out if you think that you have a very fast graphics hardware. - - -About music ------------ -The background music loops are ripped out from several nice music albums. -Just have a look at the info screen to find out from which album each -sound loop came from -- they are all very well done pieces of music, but -unfortunately they don't sound better after converting them to 8 kHz -samples (to conform to standard SUN /dev/audio). Maybe I change this to -a better quality in the future, but at the moment, where the sounds -directory has a size of nearly a megabyte, I'll stay with 8 kHz samples. - -So, if you have a non-Linux system (which cannot play sound loops) or -don't like the "telephone quality" of the music loops, just get some of -these CDs and play them while your playing the game! ;-) - - -About game-play ---------------- -It is *strongly recommended* to play this game with a high-quality joystick. -That means, throw your $10 joystick out of the window and buy a decent -Competition-Pro Digital PC joystick or a high-quality CH Products Analog -joystick. Believe me, it doubles the fun of playing the game. - -If you only have a normal Unix system (and no fine Linux system), you -are forced to play with the keyboard. It works, but is not only less fun, -but also more difficult with some levels, because you cannot move in -diagonal directions with keyboard control at the moment. Another bad thing -is that you will have some problems when pressing many keys at the same -time. This might change in the future, when I implement a better keyboard -handling which not only solves these problems but allows diagonal directions, -too. - diff --git a/REGISTRATION b/REGISTRATION deleted file mode 120000 index 5f4a260c..00000000 --- a/REGISTRATION +++ /dev/null @@ -1 +0,0 @@ -THIS_IS_NOW_FREEWARE \ No newline at end of file diff --git a/THIS_IS_NOW_FREEWARE b/THIS_IS_NOW_FREEWARE deleted file mode 100644 index c0e5098a..00000000 --- a/THIS_IS_NOW_FREEWARE +++ /dev/null @@ -1,23 +0,0 @@ - -THIS GAME IS NOW COMPLETELY FREEWARE! -===================================== - -In version 0.9, I planned to offer the possibility to become a -registered user and get special level series for registered users -only and some more things. - -Now I have decided that it is better to distribute it as Freeware, -that means: Freely distributable, but still copyrighted software. - -If you like this game, please send me mail about it! - - aeglos@valinor.owl.de - -or SnailMail: - - Holger Schemel - Sennehof 28 - 33659 Bielefeld - GERMANY - -Have fun! diff --git a/src/Makefile b/src/Makefile index 7333fb28..965c0588 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,40 +1,74 @@ -# -# Makefile fuer "Rocks'n'Diamonds -- McDuffin Strikes Back" -# +#=============================================================================# +# Makefile for Rocks'n'Diamonds 1.2 # +# (c) 1995-98 Holger Schemel, aeglos@valinor.owl.de # +#=============================================================================# + +ifndef PLATFORM # platform not defined -- try auto detection +ifdef COMSPEC +PLATFORM = dos +else +PLATFORM = unix +endif +endif + +ifdef X11_PATH # path to X11 specified by top level Makefile +XINC_PATH = $(X11_PATH)/include +XLIB_PATH = $(X11_PATH)/lib +X11_INCL = -I$(XINC_PATH) +X11_LIBS = -L$(XLIB_PATH) +endif + +ifndef GAME_DIR # path to game data not defined -- try '.' +GAME_DIR = . +endif + +ifndef SCORE_ENTRIES # number of score entries per player undefined +SCORE_ENTRIES = MANY_PER_NAME +endif + + +# The Xpm library is no longer needed to build this program, +# but is used to load graphics if XPM_INCLUDE_FILE is defined. +# If you want to use the Xpm library, convert the PCX files to XPM +# files (and you need corresponding mask files in X11 Bitmap format). + +# XPM_INCLUDE_FILE = -DXPM_INCLUDE_FILE="" +# EXTRA_X11_LIBS = -lXpm -PROGNAME = rocksndiamonds + +ifeq ($(PLATFORM),dos) # DOS / Windows + +RM = del +PROGNAME = ..\rocks.exe +LIBS = -lm -lalleg + +else # Unix RM = rm -f -CC = gcc -CPP = $(CC) -E -# CC = cc # for HP-UX and others +PROGNAME = ../rocksndiamonds + +ifeq ($(PLATFORM),solaris) +EXTRA_LIBS = -lnsl -lsocket -R$(XLIB_PATH) +endif + +INCL = $(X11_INCL) +LIBS = $(X11_LIBS) $(EXTRA_X11_LIBS) -lX11 -lm $(EXTRA_LIBS) + +endif -GAME_DIR = -DGAME_DIR=\".\" # path of the game and its data -# JOYSTICK = -DNO_JOYSTICK # no joystick -# SOUNDS = -DNO_SOUNDS # no sounds -# SCORE_ENTRIES = -DONE_PER_NAME # only one score entry per name -SCORE_ENTRIES = -DMANY_PER_NAME # many score entries per name -# the XPM-Library is needed to build this program: -XPM_INCLUDE_FILE = -DXPM_INCLUDE_FILE="" +CONFIG_GAME_DIR = -DGAME_DIR="\"$(GAME_DIR)\"" +CONFIG_SCORE_ENTRIES = -D$(SCORE_ENTRIES) -CONFIG = $(GAME_DIR) $(SOUNDS) $(JOYSTICK) \ - $(SCORE_ENTRIES) $(XPM_INCLUDE_FILE) +CONFIG = $(CONFIG_GAME_DIR) $(SOUNDS) $(JOYSTICK) \ + $(CONFIG_SCORE_ENTRIES) $(XPM_INCLUDE_FILE) -# DEBUG = -DDEBUG -g -ansi -pedantic -Wall -# DEBUG = -DDEBUG -g -Wall -DEBUG = -O6 +# OPTIONS = -DDEBUG -g -Wall # only for debugging purposes +OPTIONS = -O3 -# SYSTEM = -Aa -D_HPUX_SOURCE -Dhpux # for HP-UX (obsolete) -# SYSTEM = -DSYSV -Ae # for HP-UX -# SYSTEM = -DSYSV # for systems without 'usleep()' -# INCL = -I/usr/include/X11R5 # for HP-UX and others -# LIBS = -lXpm -lX11 -lm -# LIBS = -L/usr/lib/X11R5 -lXpm -lX11 -lm # for HP-UX and others -LIBS = -lXpm -lXpm -lXpm -lX11 -lm # triple -lXpm; else I got an error... +# SYSTEM = -DSYSV -Ae # maybe needed for HP-UX -# CFLAGS = -O2 $(CONFIG) $(SYSTEM) -CFLAGS = $(DEBUG) $(CONFIG) $(SYSTEM) $(INCL) +CFLAGS = $(OPTIONS) $(SYSTEM) $(INCL) $(CONFIG) SRCS = main.c \ init.c \ @@ -46,7 +80,16 @@ SRCS = main.c \ editor.c \ buttons.c \ files.c \ - sound.c + tape.c \ + sound.c \ + joystick.c \ + cartoons.c \ + random.c \ + pcx.c \ + image.c \ + network.c \ + netserv.c \ + msdos.c OBJS = main.o \ init.o \ @@ -58,20 +101,25 @@ OBJS = main.o \ editor.o \ buttons.o \ files.o \ - sound.o + tape.o \ + sound.o \ + joystick.o \ + cartoons.o \ + random.o \ + pcx.o \ + image.o \ + network.o \ + netserv.o \ + msdos.o + +all: $(PROGNAME) -all: $(OBJS) +$(PROGNAME): $(OBJS) $(CC) $(CFLAGS) $(OBJS) $(LIBS) -o $(PROGNAME) .c.o: $(CC) $(CFLAGS) -c $*.c clean: - $(RM) $(OBJS) - -depend: - for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend - -ifeq (.depend,$(wildcard .depend)) -include .depend -endif + $(RM) *.o + $(RM) $(PROGNAME) diff --git a/src/buttons.c b/src/buttons.c index 8b825451..62c5a1c1 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * buttons.c * ***********************************************************/ @@ -16,6 +15,324 @@ #include "tools.h" #include "misc.h" #include "editor.h" +#include "tape.h" + +/* some positions in the video tape control window */ +#define VIDEO_BUTTON_EJECT_XPOS (VIDEO_CONTROL_XPOS + 0 * VIDEO_BUTTON_XSIZE) +#define VIDEO_BUTTON_STOP_XPOS (VIDEO_CONTROL_XPOS + 1 * VIDEO_BUTTON_XSIZE) +#define VIDEO_BUTTON_PAUSE_XPOS (VIDEO_CONTROL_XPOS + 2 * VIDEO_BUTTON_XSIZE) +#define VIDEO_BUTTON_REC_XPOS (VIDEO_CONTROL_XPOS + 3 * VIDEO_BUTTON_XSIZE) +#define VIDEO_BUTTON_PLAY_XPOS (VIDEO_CONTROL_XPOS + 4 * VIDEO_BUTTON_XSIZE) +#define VIDEO_BUTTON_ANY_YPOS (VIDEO_CONTROL_YPOS) +#define VIDEO_DATE_LABEL_XPOS (VIDEO_DISPLAY1_XPOS) +#define VIDEO_DATE_LABEL_YPOS (VIDEO_DISPLAY1_YPOS) +#define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE) +#define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE) +#define VIDEO_DATE_XPOS (VIDEO_DISPLAY1_XPOS+1) +#define VIDEO_DATE_YPOS (VIDEO_DISPLAY1_YPOS+14) +#define VIDEO_DATE_XSIZE (VIDEO_DISPLAY_XSIZE) +#define VIDEO_DATE_YSIZE 16 +#define VIDEO_REC_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) +#define VIDEO_REC_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) +#define VIDEO_REC_LABEL_XSIZE 20 +#define VIDEO_REC_LABEL_YSIZE 12 +#define VIDEO_REC_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+20) +#define VIDEO_REC_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) +#define VIDEO_REC_SYMBOL_XSIZE 16 +#define VIDEO_REC_SYMBOL_YSIZE 16 +#define VIDEO_PLAY_LABEL_XPOS (VIDEO_DISPLAY2_XPOS+65) +#define VIDEO_PLAY_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) +#define VIDEO_PLAY_LABEL_XSIZE 22 +#define VIDEO_PLAY_LABEL_YSIZE 12 +#define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+52) +#define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) +#define VIDEO_PLAY_SYMBOL_XSIZE 11 +#define VIDEO_PLAY_SYMBOL_YSIZE 13 +#define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) +#define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS+20) +#define VIDEO_PAUSE_LABEL_XSIZE 35 +#define VIDEO_PAUSE_LABEL_YSIZE 8 +#define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+35) +#define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) +#define VIDEO_PAUSE_SYMBOL_XSIZE 17 +#define VIDEO_PAUSE_SYMBOL_YSIZE 13 +#define VIDEO_TIME_XPOS (VIDEO_DISPLAY2_XPOS+38) +#define VIDEO_TIME_YPOS (VIDEO_DISPLAY2_YPOS+14) +#define VIDEO_TIME_XSIZE 50 +#define VIDEO_TIME_YSIZE 16 + +/* special */ +#define VIDEO_PBEND_LABEL_XPOS 6 +#define VIDEO_PBEND_LABEL_YPOS 220 +#define VIDEO_PBEND_LABEL_XSIZE 35 +#define VIDEO_PBEND_LABEL_YSIZE 30 + +#define ON_VIDEO_BUTTON(x,y) ((x)>=(VX+VIDEO_CONTROL_XPOS) && \ + (x)< (VX+VIDEO_CONTROL_XPOS + \ + VIDEO_CONTROL_XSIZE) && \ + (y)>=(VY+VIDEO_CONTROL_YPOS) && \ + (y)< (VY+VIDEO_CONTROL_YPOS + \ + VIDEO_CONTROL_YSIZE)) +#define VIDEO_BUTTON(x) (((x)-(VX+VIDEO_CONTROL_XPOS))/VIDEO_BUTTON_XSIZE) + +#define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \ + VIDEO_STATE_REC_OFF | \ + VIDEO_STATE_PAUSE_OFF | \ + VIDEO_STATE_FFWD_OFF | \ + VIDEO_STATE_PBEND_OFF | \ + VIDEO_STATE_DATE_OFF | \ + VIDEO_STATE_TIME_OFF) +#define VIDEO_PRESS_OFF (VIDEO_PRESS_PLAY_OFF | \ + VIDEO_PRESS_REC_OFF | \ + VIDEO_PRESS_PAUSE_OFF | \ + VIDEO_PRESS_STOP_OFF | \ + VIDEO_PRESS_EJECT_OFF) +#define VIDEO_ALL_OFF (VIDEO_STATE_OFF | VIDEO_PRESS_OFF) + +#define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \ + VIDEO_STATE_REC_ON | \ + VIDEO_STATE_PAUSE_ON | \ + VIDEO_STATE_FFWD_ON | \ + VIDEO_STATE_PBEND_ON | \ + VIDEO_STATE_DATE_ON | \ + VIDEO_STATE_TIME_ON) +#define VIDEO_PRESS_ON (VIDEO_PRESS_PLAY_ON | \ + VIDEO_PRESS_REC_ON | \ + VIDEO_PRESS_PAUSE_ON | \ + VIDEO_PRESS_STOP_ON | \ + VIDEO_PRESS_EJECT_ON) +#define VIDEO_ALL_ON (VIDEO_STATE_ON | VIDEO_PRESS_ON) + +#define VIDEO_STATE (VIDEO_STATE_ON | VIDEO_STATE_OFF) +#define VIDEO_PRESS (VIDEO_PRESS_ON | VIDEO_PRESS_OFF) +#define VIDEO_ALL (VIDEO_ALL_ON | VIDEO_ALL_OFF) + + +/* some positions in the sound control window */ +#define SOUND_BUTTON_XSIZE 30 +#define SOUND_BUTTON_YSIZE 30 +#define SOUND_CONTROL_XPOS 5 +#define SOUND_CONTROL_YPOS 245 +#define SOUND_CONTROL_XSIZE (3*SOUND_BUTTON_XSIZE) +#define SOUND_CONTROL_YSIZE (1*SOUND_BUTTON_YSIZE) +#define SOUND_BUTTON_MUSIC_XPOS (SOUND_CONTROL_XPOS + 0 * SOUND_BUTTON_XSIZE) +#define SOUND_BUTTON_LOOPS_XPOS (SOUND_CONTROL_XPOS + 1 * SOUND_BUTTON_XSIZE) +#define SOUND_BUTTON_SIMPLE_XPOS (SOUND_CONTROL_XPOS + 2 * SOUND_BUTTON_XSIZE) +#define SOUND_BUTTON_ANY_YPOS (SOUND_CONTROL_YPOS) + +#define ON_SOUND_BUTTON(x,y) ((x)>=(DX+SOUND_CONTROL_XPOS) && \ + (x)< (DX+SOUND_CONTROL_XPOS + \ + SOUND_CONTROL_XSIZE) && \ + (y)>=(DY+SOUND_CONTROL_YPOS) && \ + (y)< (DY+SOUND_CONTROL_YPOS + \ + SOUND_CONTROL_YSIZE)) +#define SOUND_BUTTON(x) (((x)-(DX+SOUND_CONTROL_XPOS))/SOUND_BUTTON_XSIZE) + +/* some positions in the game control window */ +#define GAME_BUTTON_STOP_XPOS (GAME_CONTROL_XPOS + 0 * GAME_BUTTON_XSIZE) +#define GAME_BUTTON_PAUSE_XPOS (GAME_CONTROL_XPOS + 1 * GAME_BUTTON_XSIZE) +#define GAME_BUTTON_PLAY_XPOS (GAME_CONTROL_XPOS + 2 * GAME_BUTTON_XSIZE) +#define GAME_BUTTON_ANY_YPOS (GAME_CONTROL_YPOS) + +#define ON_GAME_BUTTON(x,y) ((x)>=(DX+GAME_CONTROL_XPOS) && \ + (x)< (DX+GAME_CONTROL_XPOS + \ + GAME_CONTROL_XSIZE) && \ + (y)>=(DY+GAME_CONTROL_YPOS) && \ + (y)< (DY+GAME_CONTROL_YPOS + \ + GAME_CONTROL_YSIZE)) +#define GAME_BUTTON(x) (((x)-(DX+GAME_CONTROL_XPOS))/GAME_BUTTON_XSIZE) + +/* some positions in the asking window */ +#define OK_BUTTON_XPOS 2 +#define OK_BUTTON_YPOS 250 +#define OK_BUTTON_GFX_YPOS 0 +#define OK_BUTTON_XSIZE 46 +#define OK_BUTTON_YSIZE 28 +#define NO_BUTTON_XPOS 52 +#define NO_BUTTON_YPOS OK_BUTTON_YPOS +#define NO_BUTTON_XSIZE OK_BUTTON_XSIZE +#define NO_BUTTON_YSIZE OK_BUTTON_YSIZE +#define CONFIRM_BUTTON_XPOS 2 +#define CONFIRM_BUTTON_GFX_YPOS 30 +#define CONFIRM_BUTTON_YPOS OK_BUTTON_YPOS +#define CONFIRM_BUTTON_XSIZE 96 +#define CONFIRM_BUTTON_YSIZE OK_BUTTON_YSIZE + +#define ON_YESNO_BUTTON(x,y) (((x)>=(DX+OK_BUTTON_XPOS) && \ + (x)< (DX+OK_BUTTON_XPOS + \ + OK_BUTTON_XSIZE) && \ + (y)>=(DY+OK_BUTTON_YPOS) && \ + (y)< (DY+OK_BUTTON_YPOS + \ + OK_BUTTON_YSIZE)) || \ + ((x)>=(DX+NO_BUTTON_XPOS) && \ + (x)< (DX+NO_BUTTON_XPOS + \ + NO_BUTTON_XSIZE) && \ + (y)>=(DY+NO_BUTTON_YPOS) && \ + (y)< (DY+NO_BUTTON_YPOS + \ + NO_BUTTON_YSIZE))) +#define ON_CONFIRM_BUTTON(x,y) (((x)>=(DX+CONFIRM_BUTTON_XPOS) && \ + (x)< (DX+CONFIRM_BUTTON_XPOS + \ + CONFIRM_BUTTON_XSIZE) && \ + (y)>=(DY+CONFIRM_BUTTON_YPOS) && \ + (y)< (DY+CONFIRM_BUTTON_YPOS + \ + CONFIRM_BUTTON_YSIZE))) +#define YESNO_BUTTON(x) (((x)-(DX+OK_BUTTON_XPOS))/OK_BUTTON_XSIZE) + +/* some positions in the choose player window */ +#define PLAYER_BUTTON_XSIZE 30 +#define PLAYER_BUTTON_YSIZE 30 +#define PLAYER_BUTTON_GFX_XPOS 5 +#define PLAYER_BUTTON_GFX_YPOS (215-30) +#define PLAYER_CONTROL_XPOS (5 + PLAYER_BUTTON_XSIZE/2) +#define PLAYER_CONTROL_YPOS (215 - PLAYER_BUTTON_YSIZE/2) +#define PLAYER_CONTROL_XSIZE (2*PLAYER_BUTTON_XSIZE) +#define PLAYER_CONTROL_YSIZE (2*PLAYER_BUTTON_YSIZE) +#define PLAYER_BUTTON_1_XPOS (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE) +#define PLAYER_BUTTON_2_XPOS (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE) +#define PLAYER_BUTTON_3_XPOS (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE) +#define PLAYER_BUTTON_4_XPOS (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE) +#define PLAYER_BUTTON_1_YPOS (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE) +#define PLAYER_BUTTON_2_YPOS (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE) +#define PLAYER_BUTTON_3_YPOS (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE) +#define PLAYER_BUTTON_4_YPOS (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE) + +#define ON_PLAYER_BUTTON(x,y) ((x)>=(DX+PLAYER_CONTROL_XPOS) && \ + (x)< (DX+PLAYER_CONTROL_XPOS + \ + PLAYER_CONTROL_XSIZE) && \ + (y)>=(DY+PLAYER_CONTROL_YPOS) && \ + (y)< (DY+PLAYER_CONTROL_YPOS + \ + PLAYER_CONTROL_YSIZE)) +#define PLAYER_BUTTON(x,y) ((((x)-(DX+PLAYER_CONTROL_XPOS)) / \ + PLAYER_BUTTON_XSIZE) + 2 * \ + (((y)-(DY+PLAYER_CONTROL_YPOS)) / \ + PLAYER_BUTTON_YSIZE)) + + +/* some definitions for the editor control window */ + +#define ON_EDIT_BUTTON(x,y) (((x)>=(VX+ED_BUTTON_CTRL_XPOS) && \ + (x)< (VX+ED_BUTTON_CTRL_XPOS + \ + ED_BUTTON_CTRL_XSIZE) && \ + (y)>=(VY+ED_BUTTON_CTRL_YPOS) && \ + (y)< (VY+ED_BUTTON_CTRL_YPOS + \ + ED_BUTTON_CTRL_YSIZE + \ + ED_BUTTON_FILL_YSIZE)) || \ + ((x)>=(VX+ED_BUTTON_LEFT_XPOS) && \ + (x)< (VX+ED_BUTTON_LEFT_XPOS + \ + ED_BUTTON_LEFT_XSIZE + \ + ED_BUTTON_UP_XSIZE + \ + ED_BUTTON_RIGHT_XSIZE) && \ + (y)>=(VY+ED_BUTTON_LEFT_YPOS) && \ + (y)< (VY+ED_BUTTON_LEFT_YPOS + \ + ED_BUTTON_LEFT_YSIZE)) || \ + ((x)>=(VX+ED_BUTTON_UP_XPOS) && \ + (x)< (VX+ED_BUTTON_UP_XPOS + \ + ED_BUTTON_UP_XSIZE) && \ + (y)>=(VY+ED_BUTTON_UP_YPOS) && \ + (y)< (VY+ED_BUTTON_UP_YPOS + \ + ED_BUTTON_UP_YSIZE + \ + ED_BUTTON_DOWN_YSIZE))) + +#define ON_CTRL_BUTTON(x,y) ((x)>=(VX+ED_BUTTON_EDIT_XPOS) && \ + (x)< (VX+ED_BUTTON_EDIT_XPOS + \ + ED_BUTTON_EDIT_XSIZE) && \ + (y)>=(VY+ED_BUTTON_EDIT_YPOS) && \ + (y)< (VY+ED_BUTTON_EDIT_YPOS + \ + ED_BUTTON_EDIT_YSIZE + \ + ED_BUTTON_CLEAR_YSIZE + \ + ED_BUTTON_UNDO_YSIZE + \ + ED_BUTTON_EXIT_YSIZE)) + +#define ON_ELEM_BUTTON(x,y) (((x)>=(DX+ED_BUTTON_EUP_XPOS) && \ + (x)< (DX+ED_BUTTON_EUP_XPOS + \ + ED_BUTTON_EUP_XSIZE) && \ + (y)>=(DY+ED_BUTTON_EUP_YPOS) && \ + (y)< (DY+ED_BUTTON_EUP_YPOS + \ + ED_BUTTON_EUP_YSIZE)) || \ + ((x)>=(DX+ED_BUTTON_EDOWN_XPOS) && \ + (x)< (DX+ED_BUTTON_EDOWN_XPOS + \ + ED_BUTTON_EDOWN_XSIZE) && \ + (y)>=(DY+ED_BUTTON_EDOWN_YPOS) && \ + (y)< (DY+ED_BUTTON_EDOWN_YPOS + \ + ED_BUTTON_EDOWN_YSIZE)) || \ + ((x)>=(DX+ED_BUTTON_ELEM_XPOS) && \ + (x)< (DX+ED_BUTTON_ELEM_XPOS + \ + MAX_ELEM_X*ED_BUTTON_ELEM_XSIZE) && \ + (y)>=(DY+ED_BUTTON_ELEM_YPOS) && \ + (y)< (DY+ED_BUTTON_ELEM_YPOS + \ + MAX_ELEM_Y*ED_BUTTON_ELEM_YSIZE))) + +#define ON_COUNT_BUTTON(x,y) (((((x)>=ED_COUNT_GADGET_XPOS && \ + (x)<(ED_COUNT_GADGET_XPOS + \ + ED_BUTTON_MINUS_XSIZE)) || \ + ((x)>=(ED_COUNT_GADGET_XPOS + \ + (ED_BUTTON_PLUS_XPOS - \ + ED_BUTTON_MINUS_XPOS)) && \ + (x)<(ED_COUNT_GADGET_XPOS + \ + (ED_BUTTON_PLUS_XPOS - \ + ED_BUTTON_MINUS_XPOS) + \ + ED_BUTTON_PLUS_XSIZE))) && \ + ((y)>=ED_COUNT_GADGET_YPOS && \ + (y)<(ED_COUNT_GADGET_YPOS + \ + 16*ED_COUNT_GADGET_YSIZE)) && \ + (((y)-ED_COUNT_GADGET_YPOS) % \ + ED_COUNT_GADGET_YSIZE) < \ + ED_BUTTON_MINUS_YSIZE) || \ + ((((x)>=ED_SIZE_GADGET_XPOS && \ + (x)<(ED_SIZE_GADGET_XPOS + \ + ED_BUTTON_MINUS_XSIZE)) || \ + ((x)>=(ED_SIZE_GADGET_XPOS + \ + (ED_BUTTON_PLUS_XPOS - \ + ED_BUTTON_MINUS_XPOS)) && \ + (x)<(ED_SIZE_GADGET_XPOS + \ + (ED_BUTTON_PLUS_XPOS - \ + ED_BUTTON_MINUS_XPOS) + \ + ED_BUTTON_PLUS_XSIZE))) && \ + ((y)>=ED_SIZE_GADGET_YPOS && \ + (y)<(ED_SIZE_GADGET_YPOS + \ + 2*ED_SIZE_GADGET_YSIZE)) && \ + (((y)-ED_SIZE_GADGET_YPOS) % \ + ED_SIZE_GADGET_YSIZE) < \ + ED_BUTTON_MINUS_YSIZE)) + +#define EDIT_BUTTON(x,y) (((y) < (VY + ED_BUTTON_CTRL_YPOS + \ + ED_BUTTON_CTRL_YSIZE)) ? 0 : \ + ((y) < (VY + ED_BUTTON_CTRL_YPOS + \ + ED_BUTTON_CTRL_YSIZE + \ + ED_BUTTON_FILL_YSIZE)) ? 1 : \ + ((x) < (VX + ED_BUTTON_LEFT_XPOS + \ + ED_BUTTON_LEFT_XSIZE) ? 2 : \ + (x) > (VX + ED_BUTTON_LEFT_XPOS + \ + ED_BUTTON_LEFT_XSIZE + \ + ED_BUTTON_UP_XSIZE) ? 5 : \ + 3+(((y)-(VY + ED_BUTTON_CTRL_YPOS + \ + ED_BUTTON_CTRL_YSIZE + \ + ED_BUTTON_FILL_YSIZE)) / \ + ED_BUTTON_UP_YSIZE))) + +#define CTRL_BUTTON(x,y) (((y) < (VY + ED_BUTTON_EDIT_YPOS + \ + ED_BUTTON_EDIT_YSIZE)) ? 0 : \ + 1+(((y)-(VY + ED_BUTTON_EDIT_YPOS + \ + ED_BUTTON_EDIT_YSIZE)) / \ + ED_BUTTON_CLEAR_YSIZE)) + +#define ELEM_BUTTON(x,y) (((y) < (DY + ED_BUTTON_EUP_YPOS + \ + ED_BUTTON_EUP_YSIZE)) ? 0 : \ + ((y) > (DY + ED_BUTTON_EDOWN_YPOS)) ? 1 : \ + 2+(((y) - (DY + ED_BUTTON_ELEM_YPOS)) / \ + ED_BUTTON_ELEM_YSIZE)*MAX_ELEM_X + \ + ((x) - (DX + ED_BUTTON_ELEM_XPOS)) / \ + ED_BUTTON_ELEM_XSIZE) + +#define COUNT_BUTTON(x,y) ((x) < ED_SIZE_GADGET_XPOS ? \ + ((((y) - ED_COUNT_GADGET_YPOS) / \ + ED_COUNT_GADGET_YSIZE)*2 + \ + ((x) < (ED_COUNT_GADGET_XPOS + \ + ED_BUTTON_MINUS_XSIZE) ? 0 : 1)) : \ + 32+((((y) - ED_SIZE_GADGET_YPOS) / \ + ED_SIZE_GADGET_YSIZE)*2 + \ + ((x) < (ED_SIZE_GADGET_XPOS + \ + ED_BUTTON_MINUS_XSIZE) ? 0 : 1))) /****************************************************************/ /********** drawing buttons and corresponding displays **********/ @@ -24,7 +341,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value) { int i; - int part1 = 0, part2 = 1; + int part_label = 0, part_symbol = 1; int xpos = 0, ypos = 1, xsize = 2, ysize = 3; static char *monatsname[12] = { @@ -33,57 +350,70 @@ void DrawVideoDisplay(unsigned long state, unsigned long value) }; static int video_pos[10][2][4] = { - VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS, - VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE, - VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS, - VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE, - - VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS, - VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE, - VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS, - VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE, - - VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS, - VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE, - VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS, - VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE, - - VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS, - VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE, - VIDEO_DATE_XPOS, VIDEO_DATE_YPOS, - VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE, - - 0,0, - 0,0, - VIDEO_TIME_XPOS, VIDEO_TIME_YPOS, - VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE, - - VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS, - VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE, - 0,0, - 0,0, - - VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS, - VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE, - 0,0, - 0,0, - - VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS, - VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE, - 0,0, - 0,0, - - VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS, - VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE, - 0,0, - 0,0, - - VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS, - VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE, - 0,0, - 0,0 + {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS, + VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE }, + { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS, + VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }}, + + {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS, + VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE }, + { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS, + VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }}, + + {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS, + VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE }, + { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS, + VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }}, + + {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS, + VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE }, + { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS, + VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }}, + + {{ 0,0, + 0,0 }, + { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS, + VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }}, + + {{ VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS, + VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE }, + { 0,0, + 0,0 }}, + + {{ VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS, + VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE }, + { 0,0, + 0,0 }}, + + {{ VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS, + VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE }, + { 0,0, + 0,0 }}, + + {{ VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS, + VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE }, + { 0,0, + 0,0 }}, + + {{ VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS, + VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE }, + { 0,0, + 0,0 }} }; + if (state & VIDEO_STATE_PBEND_OFF) + { + int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2; + + XCopyArea(display,pix[PIX_DOOR],drawto,gc, + cx + VIDEO_REC_LABEL_XPOS, + cy + VIDEO_REC_LABEL_YPOS, + VIDEO_PBEND_LABEL_XSIZE, + VIDEO_PBEND_LABEL_YSIZE, + VX + VIDEO_REC_LABEL_XPOS, + VY + VIDEO_REC_LABEL_YPOS); + } + for(i=0;i<20;i++) { if (state & (1< STATE_OFF / PRESS_ON */ - if (video_pos[pos][part1][0]) + if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY) XCopyArea(display,pix[PIX_DOOR],drawto,gc, - cx + video_pos[pos][part1][xpos], - cy + video_pos[pos][part1][ypos], - video_pos[pos][part1][xsize], - video_pos[pos][part1][ysize], - VX + video_pos[pos][part1][xpos], - VY + video_pos[pos][part1][ypos]); - if (video_pos[pos][part2][0]) + cx + video_pos[pos][part_label][xpos], + cy + video_pos[pos][part_label][ypos], + video_pos[pos][part_label][xsize], + video_pos[pos][part_label][ysize], + VX + video_pos[pos][part_label][xpos], + VY + video_pos[pos][part_label][ypos]); + if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY) XCopyArea(display,pix[PIX_DOOR],drawto,gc, - cx + video_pos[pos][part2][xpos], - cy + video_pos[pos][part2][ypos], - video_pos[pos][part2][xsize], - video_pos[pos][part2][ysize], - VX + video_pos[pos][part2][xpos], - VY + video_pos[pos][part2][ypos]); + cx + video_pos[pos][part_symbol][xpos], + cy + video_pos[pos][part_symbol][ypos], + video_pos[pos][part_symbol][xsize], + video_pos[pos][part_symbol][ysize], + VX + video_pos[pos][part_symbol][xpos], + VY + video_pos[pos][part_symbol][ypos]); } } + if (state & VIDEO_STATE_FFWD_ON) + { + int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2; + + XCopyArea(display,pix[PIX_DOOR],drawto,gc, + cx + VIDEO_PLAY_SYMBOL_XPOS, + cy + VIDEO_PLAY_SYMBOL_YPOS, + VIDEO_PLAY_SYMBOL_XSIZE - 2, + VIDEO_PLAY_SYMBOL_YSIZE, + VX + VIDEO_PLAY_SYMBOL_XPOS - 9, + VY + VIDEO_PLAY_SYMBOL_YPOS); + } + + if (state & VIDEO_STATE_PBEND_ON) + { + int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1; + + XCopyArea(display,pix[PIX_DOOR],drawto,gc, + cx + VIDEO_PBEND_LABEL_XPOS, + cy + VIDEO_PBEND_LABEL_YPOS, + VIDEO_PBEND_LABEL_XSIZE, + VIDEO_PBEND_LABEL_YSIZE, + VX + VIDEO_REC_LABEL_XPOS, + VY + VIDEO_REC_LABEL_YPOS); + } + if (state & VIDEO_STATE_DATE_ON) { int tag = value % 100; @@ -161,7 +517,7 @@ void DrawCompleteVideoDisplay() if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date); - DrawVideoDisplay(VIDEO_STATE_TIME_ON,0); + DrawVideoDisplay(VIDEO_STATE_TIME_ON,tape.length_seconds); } XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc, @@ -174,7 +530,7 @@ void DrawSoundDisplay(unsigned long state) pos = (state & BUTTON_SOUND_MUSIC ? SOUND_BUTTON_MUSIC_XPOS : state & BUTTON_SOUND_LOOPS ? SOUND_BUTTON_LOOPS_XPOS : - SOUND_BUTTON_SOUND_XPOS); + SOUND_BUTTON_SIMPLE_XPOS); if (state & BUTTON_ON) cy -= SOUND_BUTTON_YSIZE; @@ -209,34 +565,119 @@ void DrawGameButton(unsigned long state) redraw_mask |= REDRAW_DOOR_1; } -void DrawChooseButton(unsigned long state) +void DrawYesNoButton(unsigned long state, int mode) { - int pos, cx = DOOR_GFX_PAGEX4, cy = 0; + Drawable dest_drawto; + int dest_xoffset, dest_yoffset; + int xpos, cx = DOOR_GFX_PAGEX4; - pos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS); + if (mode == DB_INIT) + { + dest_drawto = pix[PIX_DB_DOOR]; + dest_xoffset = DOOR_GFX_PAGEX1; + dest_yoffset = 0; + } + else + { + dest_drawto = drawto; + dest_xoffset = DX; + dest_yoffset = DY; + } + + xpos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS); if (state & BUTTON_PRESSED) cx = DOOR_GFX_PAGEX3; - XCopyArea(display,pix[PIX_DOOR],drawto,gc, - cx + pos,cy + OK_BUTTON_GFX_YPOS, - OK_BUTTON_XSIZE,OK_BUTTON_YSIZE, - DX + pos,DY + OK_BUTTON_YPOS); + XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc, + cx + xpos, OK_BUTTON_GFX_YPOS, + OK_BUTTON_XSIZE, OK_BUTTON_YSIZE, + dest_xoffset + xpos, dest_yoffset + OK_BUTTON_YPOS); redraw_mask |= REDRAW_DOOR_1; } -void DrawConfirmButton(unsigned long state) +void DrawConfirmButton(unsigned long state, int mode) { + Drawable dest_drawto; + int dest_xoffset, dest_yoffset; + int cx = DOOR_GFX_PAGEX4; + + if (mode == DB_INIT) + { + dest_drawto = pix[PIX_DB_DOOR]; + dest_xoffset = DOOR_GFX_PAGEX1; + dest_yoffset = 0; + } + else + { + dest_drawto = drawto; + dest_xoffset = DX; + dest_yoffset = DY; + } + + if (state & BUTTON_PRESSED) + cx = DOOR_GFX_PAGEX3; + + XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc, + cx + CONFIRM_BUTTON_XPOS, CONFIRM_BUTTON_GFX_YPOS, + CONFIRM_BUTTON_XSIZE, CONFIRM_BUTTON_YSIZE, + dest_xoffset + CONFIRM_BUTTON_XPOS, + dest_yoffset + CONFIRM_BUTTON_YPOS); + + redraw_mask |= REDRAW_DOOR_1; +} + +void DrawPlayerButton(unsigned long state, int mode) +{ + Drawable dest_drawto; + int dest_xoffset, dest_yoffset; + int graphic = GFX_SPIELER1; /* default */ + int graphic_offset = (PLAYER_BUTTON_XSIZE - TILEX/2)/2; + int xpos, ypos; int cx = DOOR_GFX_PAGEX4, cy = 0; + if (mode == DB_INIT) + { + dest_drawto = pix[PIX_DB_DOOR]; + dest_xoffset = DOOR_GFX_PAGEX1; + dest_yoffset = 0; + } + else + { + dest_drawto = drawto; + dest_xoffset = DX; + dest_yoffset = DY; + } + + if (state & BUTTON_PLAYER_1) + graphic = GFX_SPIELER1; + else if (state & BUTTON_PLAYER_2) + graphic = GFX_SPIELER2; + else if (state & BUTTON_PLAYER_3) + graphic = GFX_SPIELER3; + else if (state & BUTTON_PLAYER_4) + graphic = GFX_SPIELER4; + + xpos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_3 ? + PLAYER_BUTTON_1_XPOS : PLAYER_BUTTON_2_XPOS); + ypos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_2 ? + PLAYER_BUTTON_1_YPOS : PLAYER_BUTTON_3_YPOS); + if (state & BUTTON_PRESSED) + { cx = DOOR_GFX_PAGEX3; + graphic_offset += 1; + } - XCopyArea(display,pix[PIX_DOOR],drawto,gc, - cx + CONFIRM_BUTTON_XPOS,cy + CONFIRM_BUTTON_GFX_YPOS, - CONFIRM_BUTTON_XSIZE,CONFIRM_BUTTON_YSIZE, - DX + CONFIRM_BUTTON_XPOS,DY + CONFIRM_BUTTON_YPOS); + XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc, + cx + PLAYER_BUTTON_GFX_XPOS, cy + PLAYER_BUTTON_GFX_YPOS, + PLAYER_BUTTON_XSIZE, PLAYER_BUTTON_YSIZE, + dest_xoffset + xpos, dest_yoffset + ypos); + DrawMiniGraphicExt(dest_drawto,gc, + dest_xoffset + xpos + graphic_offset, + dest_yoffset + ypos + graphic_offset, + graphic); redraw_mask |= REDRAW_DOOR_1; } @@ -250,23 +691,23 @@ void DrawEditButton(unsigned long state) int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY2; static int edit_pos[6][4] = { - ED_BUTTON_CTRL_XPOS,ED_BUTTON_CTRL_YPOS, - ED_BUTTON_CTRL_XSIZE,ED_BUTTON_CTRL_YSIZE, + {ED_BUTTON_CTRL_XPOS,ED_BUTTON_CTRL_YPOS, + ED_BUTTON_CTRL_XSIZE,ED_BUTTON_CTRL_YSIZE}, - ED_BUTTON_FILL_XPOS,ED_BUTTON_FILL_YPOS, - ED_BUTTON_FILL_XSIZE,ED_BUTTON_FILL_YSIZE, + {ED_BUTTON_FILL_XPOS,ED_BUTTON_FILL_YPOS, + ED_BUTTON_FILL_XSIZE,ED_BUTTON_FILL_YSIZE}, - ED_BUTTON_LEFT_XPOS,ED_BUTTON_LEFT_YPOS, - ED_BUTTON_LEFT_XSIZE,ED_BUTTON_LEFT_YSIZE, + {ED_BUTTON_LEFT_XPOS,ED_BUTTON_LEFT_YPOS, + ED_BUTTON_LEFT_XSIZE,ED_BUTTON_LEFT_YSIZE}, - ED_BUTTON_UP_XPOS,ED_BUTTON_UP_YPOS, - ED_BUTTON_UP_XSIZE,ED_BUTTON_UP_YSIZE, + {ED_BUTTON_UP_XPOS,ED_BUTTON_UP_YPOS, + ED_BUTTON_UP_XSIZE,ED_BUTTON_UP_YSIZE}, - ED_BUTTON_DOWN_XPOS,ED_BUTTON_DOWN_YPOS, - ED_BUTTON_DOWN_XSIZE,ED_BUTTON_DOWN_YSIZE, + {ED_BUTTON_DOWN_XPOS,ED_BUTTON_DOWN_YPOS, + ED_BUTTON_DOWN_XSIZE,ED_BUTTON_DOWN_YSIZE}, - ED_BUTTON_RIGHT_XPOS,ED_BUTTON_RIGHT_YPOS, - ED_BUTTON_RIGHT_XSIZE,ED_BUTTON_RIGHT_YSIZE + {ED_BUTTON_RIGHT_XPOS,ED_BUTTON_RIGHT_YPOS, + ED_BUTTON_RIGHT_XSIZE,ED_BUTTON_RIGHT_YSIZE} }; if (state & ED_BUTTON_PRESSED) @@ -294,17 +735,17 @@ void DrawCtrlButton(unsigned long state) int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY1+80; static int edit_pos[4][4] = { - ED_BUTTON_EDIT_XPOS,ED_BUTTON_EDIT_YPOS, - ED_BUTTON_EDIT_XSIZE,ED_BUTTON_EDIT_YSIZE, + {ED_BUTTON_EDIT_XPOS,ED_BUTTON_EDIT_YPOS, + ED_BUTTON_EDIT_XSIZE,ED_BUTTON_EDIT_YSIZE}, - ED_BUTTON_CLEAR_XPOS,ED_BUTTON_CLEAR_YPOS, - ED_BUTTON_CLEAR_XSIZE,ED_BUTTON_CLEAR_YSIZE, + {ED_BUTTON_CLEAR_XPOS,ED_BUTTON_CLEAR_YPOS, + ED_BUTTON_CLEAR_XSIZE,ED_BUTTON_CLEAR_YSIZE}, - ED_BUTTON_UNDO_XPOS,ED_BUTTON_UNDO_YPOS, - ED_BUTTON_UNDO_XSIZE,ED_BUTTON_UNDO_YSIZE, + {ED_BUTTON_UNDO_XPOS,ED_BUTTON_UNDO_YPOS, + ED_BUTTON_UNDO_XSIZE,ED_BUTTON_UNDO_YSIZE}, - ED_BUTTON_EXIT_XPOS,ED_BUTTON_EXIT_YPOS, - ED_BUTTON_EXIT_XSIZE,ED_BUTTON_EXIT_YSIZE + {ED_BUTTON_EXIT_XPOS,ED_BUTTON_EXIT_YPOS, + ED_BUTTON_EXIT_XSIZE,ED_BUTTON_EXIT_YSIZE} }; if (state & ED_BUTTON_PRESSED) @@ -332,14 +773,14 @@ void DrawElemButton(int button_nr, int button_state) int from_x, from_y, to_x,to_y, size_x, size_y; static int edit_pos[3][4] = { - ED_BUTTON_EUP_XPOS,ED_BUTTON_EUP_YPOS, - ED_BUTTON_EUP_XSIZE,ED_BUTTON_EUP_YSIZE, + {ED_BUTTON_EUP_XPOS,ED_BUTTON_EUP_YPOS, + ED_BUTTON_EUP_XSIZE,ED_BUTTON_EUP_YSIZE}, - ED_BUTTON_EDOWN_XPOS,ED_BUTTON_EDOWN_YPOS, - ED_BUTTON_EDOWN_XSIZE,ED_BUTTON_EDOWN_YSIZE, + {ED_BUTTON_EDOWN_XPOS,ED_BUTTON_EDOWN_YPOS, + ED_BUTTON_EDOWN_XSIZE,ED_BUTTON_EDOWN_YSIZE}, - ED_BUTTON_ELEM_XPOS,ED_BUTTON_ELEM_YPOS, - ED_BUTTON_ELEM_XSIZE,ED_BUTTON_ELEM_YSIZE + {ED_BUTTON_ELEM_XPOS,ED_BUTTON_ELEM_YPOS, + ED_BUTTON_ELEM_XSIZE,ED_BUTTON_ELEM_YSIZE} }; if (button_nr=0 && pressed) { pressed = FALSE; - DrawChooseButton(choose_button[choice] | BUTTON_RELEASED); + DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL); } - else if (ON_CHOOSE_BUTTON(mx,my) &&CHOOSE_BUTTON(mx)==choice && !pressed) + else if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && !pressed) { pressed = TRUE; - DrawChooseButton(choose_button[choice] | BUTTON_PRESSED); + DrawYesNoButton(yesno_button[choice] | BUTTON_PRESSED, DB_NORMAL); } } } else /* Maustaste wieder losgelassen */ { - if (ON_CHOOSE_BUTTON(mx,my) && CHOOSE_BUTTON(mx)==choice && pressed) + if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && pressed) { - DrawChooseButton(choose_button[choice] | BUTTON_RELEASED); + DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL); return_code = choice+1; choice = -1; pressed = FALSE; @@ -669,7 +1110,7 @@ int CheckConfirmButton(int mx, int my, int button) { int return_code = 0; static int choice = -1; - static BOOL pressed = FALSE; + static boolean pressed = FALSE; if (button) { @@ -679,7 +1120,7 @@ int CheckConfirmButton(int mx, int my, int button) { choice = 0; pressed = TRUE; - DrawConfirmButton(BUTTON_PRESSED); + DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL); } } else /* Mausbewegung bei gedrückter Maustaste */ @@ -687,12 +1128,12 @@ int CheckConfirmButton(int mx, int my, int button) if (!ON_CONFIRM_BUTTON(mx,my) && choice>=0 && pressed) { pressed = FALSE; - DrawConfirmButton(BUTTON_RELEASED); + DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL); } else if (ON_CONFIRM_BUTTON(mx,my) && !pressed) { pressed = TRUE; - DrawConfirmButton(BUTTON_PRESSED); + DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL); } } } @@ -700,7 +1141,7 @@ int CheckConfirmButton(int mx, int my, int button) { if (ON_CONFIRM_BUTTON(mx,my) && pressed) { - DrawConfirmButton(BUTTON_RELEASED); + DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL); return_code = BUTTON_CONFIRM; choice = -1; pressed = FALSE; @@ -716,13 +1157,72 @@ int CheckConfirmButton(int mx, int my, int button) return(return_code); } +int CheckPlayerButtons(int mx, int my, int button) +{ + int return_code = 0; + static int choice = -1; + static boolean pressed = FALSE; + int player_state[4] = + { + BUTTON_PLAYER_1, + BUTTON_PLAYER_2, + BUTTON_PLAYER_3, + BUTTON_PLAYER_4 + }; + + if (button) + { + if (!motion_status) /* Maustaste neu gedrückt */ + { + if (ON_PLAYER_BUTTON(mx,my)) + { + choice = PLAYER_BUTTON(mx,my); + pressed = TRUE; + DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL); + } + } + else /* Mausbewegung bei gedrückter Maustaste */ + { + if ((!ON_PLAYER_BUTTON(mx,my) || PLAYER_BUTTON(mx,my)!=choice) && + choice>=0 && pressed) + { + pressed = FALSE; + DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL); + } + else if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && !pressed) + { + pressed = TRUE; + DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL); + } + } + } + else /* Maustaste wieder losgelassen */ + { + if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && pressed) + { + DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL); + return_code = player_state[choice]; + choice = -1; + pressed = FALSE; + } + else + { + choice = -1; + pressed = FALSE; + } + } + + BackToFront(); + return(return_code); +} + /* several buttons in the level editor */ int CheckEditButtons(int mx, int my, int button) { int return_code = 0; static int choice = -1; - static BOOL pressed = FALSE; + static boolean pressed = FALSE; static int edit_button[6] = { ED_BUTTON_CTRL, @@ -792,7 +1292,7 @@ int CheckCtrlButtons(int mx, int my, int button) { int return_code = 0; static int choice = -1; - static BOOL pressed = FALSE; + static boolean pressed = FALSE; static int ctrl_button[4] = { ED_BUTTON_EDIT, @@ -851,7 +1351,7 @@ int CheckElemButtons(int mx, int my, int button) { int return_code = -1; static int choice = -1; - static BOOL pressed = FALSE; + static boolean pressed = FALSE; if (button) { @@ -912,7 +1412,7 @@ int CheckCountButtons(int mx, int my, int button) { int return_code = -1; static int choice = -1; - static BOOL pressed = FALSE; + static boolean pressed = FALSE; if (button) { diff --git a/src/buttons.h b/src/buttons.h index 98ac5caf..8111aaeb 100644 --- a/src/buttons.h +++ b/src/buttons.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * buttons.h * ***********************************************************/ @@ -17,6 +16,8 @@ #include "main.h" +/* the following definitions are also used by tools.c */ + /* some positions in the video tape control window */ #define VIDEO_DISPLAY1_XPOS 5 #define VIDEO_DISPLAY1_YPOS 5 @@ -30,56 +31,30 @@ #define VIDEO_CONTROL_YPOS 77 #define VIDEO_CONTROL_XSIZE (VIDEO_DISPLAY_XSIZE) #define VIDEO_CONTROL_YSIZE (VIDEO_BUTTON_YSIZE) -#define VIDEO_BUTTON_EJECT_XPOS (VIDEO_CONTROL_XPOS + 0 * VIDEO_BUTTON_XSIZE) -#define VIDEO_BUTTON_STOP_XPOS (VIDEO_CONTROL_XPOS + 1 * VIDEO_BUTTON_XSIZE) -#define VIDEO_BUTTON_PAUSE_XPOS (VIDEO_CONTROL_XPOS + 2 * VIDEO_BUTTON_XSIZE) -#define VIDEO_BUTTON_REC_XPOS (VIDEO_CONTROL_XPOS + 3 * VIDEO_BUTTON_XSIZE) -#define VIDEO_BUTTON_PLAY_XPOS (VIDEO_CONTROL_XPOS + 4 * VIDEO_BUTTON_XSIZE) -#define VIDEO_BUTTON_ANY_YPOS (VIDEO_CONTROL_YPOS) -#define VIDEO_DATE_LABEL_XPOS (VIDEO_DISPLAY1_XPOS) -#define VIDEO_DATE_LABEL_YPOS (VIDEO_DISPLAY1_YPOS) -#define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE) -#define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE) -#define VIDEO_DATE_XPOS (VIDEO_DISPLAY1_XPOS+1) -#define VIDEO_DATE_YPOS (VIDEO_DISPLAY1_YPOS+14) -#define VIDEO_DATE_XSIZE (VIDEO_DISPLAY_XSIZE) -#define VIDEO_DATE_YSIZE 16 -#define VIDEO_REC_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) -#define VIDEO_REC_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) -#define VIDEO_REC_LABEL_XSIZE 20 -#define VIDEO_REC_LABEL_YSIZE 12 -#define VIDEO_REC_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+20) -#define VIDEO_REC_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) -#define VIDEO_REC_SYMBOL_XSIZE 16 -#define VIDEO_REC_SYMBOL_YSIZE 16 -#define VIDEO_PLAY_LABEL_XPOS (VIDEO_DISPLAY2_XPOS+65) -#define VIDEO_PLAY_LABEL_YPOS (VIDEO_DISPLAY2_YPOS) -#define VIDEO_PLAY_LABEL_XSIZE 22 -#define VIDEO_PLAY_LABEL_YSIZE 12 -#define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+50) -#define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) -#define VIDEO_PLAY_SYMBOL_XSIZE 13 -#define VIDEO_PLAY_SYMBOL_YSIZE 13 -#define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS) -#define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS+20) -#define VIDEO_PAUSE_LABEL_XSIZE 35 -#define VIDEO_PAUSE_LABEL_YSIZE 8 -#define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+35) -#define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS) -#define VIDEO_PAUSE_SYMBOL_XSIZE 13 -#define VIDEO_PAUSE_SYMBOL_YSIZE 13 -#define VIDEO_TIME_XPOS (VIDEO_DISPLAY2_XPOS+38) -#define VIDEO_TIME_YPOS (VIDEO_DISPLAY2_YPOS+14) -#define VIDEO_TIME_XSIZE 50 -#define VIDEO_TIME_YSIZE 16 -#define ON_VIDEO_BUTTON(x,y) ((x)>=(VX+VIDEO_CONTROL_XPOS) && \ - (x)< (VX+VIDEO_CONTROL_XPOS + \ - VIDEO_CONTROL_XSIZE) && \ - (y)>=(VY+VIDEO_CONTROL_YPOS) && \ - (y)< (VY+VIDEO_CONTROL_YPOS + \ - VIDEO_CONTROL_YSIZE)) -#define VIDEO_BUTTON(x) (((x)-(VX+VIDEO_CONTROL_XPOS))/VIDEO_BUTTON_XSIZE) +/* values for requests */ +#define BUTTON_OK (1L<<0) +#define BUTTON_NO (1L<<1) +#define BUTTON_CONFIRM (1L<<2) + +/* values for choosing network player */ +#define BUTTON_PLAYER_1 (1L<<10) +#define BUTTON_PLAYER_2 (1L<<11) +#define BUTTON_PLAYER_3 (1L<<12) +#define BUTTON_PLAYER_4 (1L<<13) + +/* for DrawPlayerButton() */ +#define DB_INIT 0 +#define DB_NORMAL 1 + +/* the following definitions are also used by screens.c */ + +/* buttons of the video tape player */ +#define BUTTON_VIDEO_EJECT 1 +#define BUTTON_VIDEO_STOP 2 +#define BUTTON_VIDEO_PAUSE 3 +#define BUTTON_VIDEO_REC 4 +#define BUTTON_VIDEO_PLAY 5 /* values for video tape control */ #define VIDEO_STATE_PLAY_OFF (1L<<0) @@ -113,144 +88,50 @@ #define VIDEO_PRESS_EJECT_OFF (1L<<19) #define VIDEO_PRESS_EJECT (VIDEO_PRESS_EJECT_OFF | VIDEO_PRESS_EJECT_ON) -#define BUTTON_VIDEO_EJECT 1 -#define BUTTON_VIDEO_STOP 2 -#define BUTTON_VIDEO_PAUSE 3 -#define BUTTON_VIDEO_REC 4 -#define BUTTON_VIDEO_PLAY 5 - -#define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \ - VIDEO_STATE_REC_OFF | \ - VIDEO_STATE_PAUSE_OFF | \ - VIDEO_STATE_DATE_OFF | \ - VIDEO_STATE_TIME_OFF) -#define VIDEO_PRESS_OFF (VIDEO_PRESS_PLAY_OFF | \ - VIDEO_PRESS_REC_OFF | \ - VIDEO_PRESS_PAUSE_OFF | \ - VIDEO_PRESS_STOP_OFF | \ - VIDEO_PRESS_EJECT_OFF) -#define VIDEO_ALL_OFF (VIDEO_STATE_OFF | VIDEO_PRESS_OFF) - -#define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \ - VIDEO_STATE_REC_ON | \ - VIDEO_STATE_PAUSE_ON | \ - VIDEO_STATE_DATE_ON | \ - VIDEO_STATE_TIME_ON) -#define VIDEO_PRESS_ON (VIDEO_PRESS_PLAY_ON | \ - VIDEO_PRESS_REC_ON | \ - VIDEO_PRESS_PAUSE_ON | \ - VIDEO_PRESS_STOP_ON | \ - VIDEO_PRESS_EJECT_ON) -#define VIDEO_ALL_ON (VIDEO_STATE_ON | VIDEO_PRESS_ON) +/* special */ +#define VIDEO_STATE_FFWD_OFF ((1L<<20) | VIDEO_STATE_PAUSE_OFF) +#define VIDEO_STATE_FFWD_ON (1L<<21) +#define VIDEO_STATE_FFWD (VIDEO_STATE_FFWD_OFF | VIDEO_STATE_FFWD_ON) +#define VIDEO_STATE_PBEND_OFF (1L<<22) +#define VIDEO_STATE_PBEND_ON (1L<<23) +#define VIDEO_STATE_PBEND (VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PBEND_ON) -#define VIDEO_STATE (VIDEO_STATE_ON | VIDEO_STATE_OFF) -#define VIDEO_PRESS (VIDEO_PRESS_ON | VIDEO_PRESS_OFF) -#define VIDEO_ALL (VIDEO_ALL_ON | VIDEO_ALL_OFF) - - -/* some positions in the sound control window */ -#define SOUND_BUTTON_XSIZE 30 -#define SOUND_BUTTON_YSIZE 30 -#define SOUND_CONTROL_XPOS 5 -#define SOUND_CONTROL_YPOS 245 -#define SOUND_CONTROL_XSIZE 90 -#define SOUND_CONTROL_YSIZE (SOUND_BUTTON_YSIZE) -#define SOUND_BUTTON_MUSIC_XPOS (SOUND_CONTROL_XPOS + 0 * SOUND_BUTTON_XSIZE) -#define SOUND_BUTTON_LOOPS_XPOS (SOUND_CONTROL_XPOS + 1 * SOUND_BUTTON_XSIZE) -#define SOUND_BUTTON_SOUND_XPOS (SOUND_CONTROL_XPOS + 2 * SOUND_BUTTON_XSIZE) -#define SOUND_BUTTON_ANY_YPOS (SOUND_CONTROL_YPOS) - -#define ON_SOUND_BUTTON(x,y) ((x)>=(DX+SOUND_CONTROL_XPOS) && \ - (x)< (DX+SOUND_CONTROL_XPOS + \ - SOUND_CONTROL_XSIZE) && \ - (y)>=(DY+SOUND_CONTROL_YPOS) && \ - (y)< (DY+SOUND_CONTROL_YPOS + \ - SOUND_CONTROL_YSIZE)) -#define SOUND_BUTTON(x) (((x)-(DX+SOUND_CONTROL_XPOS))/SOUND_BUTTON_XSIZE) +/* tags to draw video display labels or symbols only */ +#define VIDEO_DISPLAY_DEFAULT 0 +#define VIDEO_DISPLAY_LABEL_ONLY 1 +#define VIDEO_DISPLAY_SYMBOL_ONLY 2 /* values for sound control */ #define BUTTON_SOUND_MUSIC (1L<<0) #define BUTTON_SOUND_LOOPS (1L<<1) -#define BUTTON_SOUND_SOUND (1L<<2) +#define BUTTON_SOUND_SIMPLE (1L<<2) #define BUTTON_RELEASED 0 #define BUTTON_PRESSED (1L<<3) #define BUTTON_OFF 0 #define BUTTON_ON (1L<<4) -#define BUTTON_SOUND_MUSIC_OFF (BUTTON_SOUND_MUSIC | BUTTON_OFF) -#define BUTTON_SOUND_LOOPS_OFF (BUTTON_SOUND_LOOPS | BUTTON_OFF) -#define BUTTON_SOUND_SOUND_OFF (BUTTON_SOUND_SOUND | BUTTON_OFF) -#define BUTTON_SOUND_MUSIC_ON (BUTTON_SOUND_MUSIC | BUTTON_ON) -#define BUTTON_SOUND_LOOPS_ON (BUTTON_SOUND_LOOPS | BUTTON_ON) -#define BUTTON_SOUND_SOUND_ON (BUTTON_SOUND_SOUND | BUTTON_ON) - - -/* some positions in the game control window */ -#define GAME_BUTTON_XSIZE 30 -#define GAME_BUTTON_YSIZE 30 -#define GAME_CONTROL_XPOS 5 -#define GAME_CONTROL_YPOS 215 -#define GAME_CONTROL_XSIZE 90 -#define GAME_CONTROL_YSIZE (GAME_BUTTON_YSIZE) -#define GAME_BUTTON_STOP_XPOS (GAME_CONTROL_XPOS + 0 * GAME_BUTTON_XSIZE) -#define GAME_BUTTON_PAUSE_XPOS (GAME_CONTROL_XPOS + 1 * GAME_BUTTON_XSIZE) -#define GAME_BUTTON_PLAY_XPOS (GAME_CONTROL_XPOS + 2 * GAME_BUTTON_XSIZE) -#define GAME_BUTTON_ANY_YPOS (GAME_CONTROL_YPOS) - -#define ON_GAME_BUTTON(x,y) ((x)>=(DX+GAME_CONTROL_XPOS) && \ - (x)< (DX+GAME_CONTROL_XPOS + \ - GAME_CONTROL_XSIZE) && \ - (y)>=(DY+GAME_CONTROL_YPOS) && \ - (y)< (DY+GAME_CONTROL_YPOS + \ - GAME_CONTROL_YSIZE)) -#define GAME_BUTTON(x) (((x)-(DX+GAME_CONTROL_XPOS))/GAME_BUTTON_XSIZE) +#define BUTTON_SOUND_MUSIC_OFF (BUTTON_SOUND_MUSIC | BUTTON_OFF) +#define BUTTON_SOUND_LOOPS_OFF (BUTTON_SOUND_LOOPS | BUTTON_OFF) +#define BUTTON_SOUND_SIMPLE_OFF (BUTTON_SOUND_SIMPLE | BUTTON_OFF) +#define BUTTON_SOUND_MUSIC_ON (BUTTON_SOUND_MUSIC | BUTTON_ON) +#define BUTTON_SOUND_LOOPS_ON (BUTTON_SOUND_LOOPS | BUTTON_ON) +#define BUTTON_SOUND_SIMPLE_ON (BUTTON_SOUND_SIMPLE | BUTTON_ON) /* values for game control */ #define BUTTON_GAME_STOP (1L<<0) #define BUTTON_GAME_PAUSE (1L<<1) #define BUTTON_GAME_PLAY (1L<<2) +/* the following definitions are also used by game.c */ -/* some positions in the asking window */ -#define OK_BUTTON_XPOS 2 -#define OK_BUTTON_YPOS 250 -#define OK_BUTTON_GFX_YPOS 0 -#define OK_BUTTON_XSIZE 46 -#define OK_BUTTON_YSIZE 28 -#define NO_BUTTON_XPOS 52 -#define NO_BUTTON_YPOS OK_BUTTON_YPOS -#define NO_BUTTON_XSIZE OK_BUTTON_XSIZE -#define NO_BUTTON_YSIZE OK_BUTTON_YSIZE -#define CONFIRM_BUTTON_XPOS 2 -#define CONFIRM_BUTTON_GFX_YPOS 30 -#define CONFIRM_BUTTON_YPOS OK_BUTTON_YPOS -#define CONFIRM_BUTTON_XSIZE 96 -#define CONFIRM_BUTTON_YSIZE OK_BUTTON_YSIZE - -#define ON_CHOOSE_BUTTON(x,y) (((x)>=(DX+OK_BUTTON_XPOS) && \ - (x)< (DX+OK_BUTTON_XPOS + \ - OK_BUTTON_XSIZE) && \ - (y)>=(DY+OK_BUTTON_YPOS) && \ - (y)< (DY+OK_BUTTON_YPOS + \ - OK_BUTTON_YSIZE)) || \ - ((x)>=(DX+NO_BUTTON_XPOS) && \ - (x)< (DX+NO_BUTTON_XPOS + \ - NO_BUTTON_XSIZE) && \ - (y)>=(DY+NO_BUTTON_YPOS) && \ - (y)< (DY+NO_BUTTON_YPOS + \ - NO_BUTTON_YSIZE))) -#define ON_CONFIRM_BUTTON(x,y) (((x)>=(DX+CONFIRM_BUTTON_XPOS) && \ - (x)< (DX+CONFIRM_BUTTON_XPOS + \ - CONFIRM_BUTTON_XSIZE) && \ - (y)>=(DY+CONFIRM_BUTTON_YPOS) && \ - (y)< (DY+CONFIRM_BUTTON_YPOS + \ - CONFIRM_BUTTON_YSIZE))) -#define CHOOSE_BUTTON(x) (((x)-(DX+OK_BUTTON_XPOS))/OK_BUTTON_XSIZE) - -/* values for asking control */ -#define BUTTON_OK (1L<<0) -#define BUTTON_NO (1L<<1) -#define BUTTON_CONFIRM (1L<<2) +/* some positions in the game control window */ +#define GAME_BUTTON_XSIZE 30 +#define GAME_BUTTON_YSIZE 30 +#define GAME_CONTROL_XPOS 5 +#define GAME_CONTROL_YPOS 215 +#define GAME_CONTROL_XSIZE (3*GAME_BUTTON_XSIZE) +#define GAME_CONTROL_YSIZE (1*GAME_BUTTON_YSIZE) +/* the following definitions are also used by editor.c */ /* some positions in the editor control window */ #define ED_BUTTON_EUP_XPOS 35 @@ -342,130 +223,6 @@ #define ED_SIZE_VALUE_XPOS (ED_SIZE_GADGET_XPOS+ED_BUTTON_MINUS_XSIZE+7) #define ED_SIZE_VALUE_YPOS ED_SIZE_TEXT_YPOS -#define ON_EDIT_BUTTON(x,y) (((x)>=(VX+ED_BUTTON_CTRL_XPOS) && \ - (x)< (VX+ED_BUTTON_CTRL_XPOS + \ - ED_BUTTON_CTRL_XSIZE) && \ - (y)>=(VY+ED_BUTTON_CTRL_YPOS) && \ - (y)< (VY+ED_BUTTON_CTRL_YPOS + \ - ED_BUTTON_CTRL_YSIZE + \ - ED_BUTTON_FILL_YSIZE)) || \ - ((x)>=(VX+ED_BUTTON_LEFT_XPOS) && \ - (x)< (VX+ED_BUTTON_LEFT_XPOS + \ - ED_BUTTON_LEFT_XSIZE + \ - ED_BUTTON_UP_XSIZE + \ - ED_BUTTON_RIGHT_XSIZE) && \ - (y)>=(VY+ED_BUTTON_LEFT_YPOS) && \ - (y)< (VY+ED_BUTTON_LEFT_YPOS + \ - ED_BUTTON_LEFT_YSIZE)) || \ - ((x)>=(VX+ED_BUTTON_UP_XPOS) && \ - (x)< (VX+ED_BUTTON_UP_XPOS + \ - ED_BUTTON_UP_XSIZE) && \ - (y)>=(VY+ED_BUTTON_UP_YPOS) && \ - (y)< (VY+ED_BUTTON_UP_YPOS + \ - ED_BUTTON_UP_YSIZE + \ - ED_BUTTON_DOWN_YSIZE))) - -#define ON_CTRL_BUTTON(x,y) ((x)>=(VX+ED_BUTTON_EDIT_XPOS) && \ - (x)< (VX+ED_BUTTON_EDIT_XPOS + \ - ED_BUTTON_EDIT_XSIZE) && \ - (y)>=(VY+ED_BUTTON_EDIT_YPOS) && \ - (y)< (VY+ED_BUTTON_EDIT_YPOS + \ - ED_BUTTON_EDIT_YSIZE + \ - ED_BUTTON_CLEAR_YSIZE + \ - ED_BUTTON_UNDO_YSIZE + \ - ED_BUTTON_EXIT_YSIZE)) - -#define ON_ELEM_BUTTON(x,y) (((x)>=(DX+ED_BUTTON_EUP_XPOS) && \ - (x)< (DX+ED_BUTTON_EUP_XPOS + \ - ED_BUTTON_EUP_XSIZE) && \ - (y)>=(DY+ED_BUTTON_EUP_YPOS) && \ - (y)< (DY+ED_BUTTON_EUP_YPOS + \ - ED_BUTTON_EUP_YSIZE)) || \ - ((x)>=(DX+ED_BUTTON_EDOWN_XPOS) && \ - (x)< (DX+ED_BUTTON_EDOWN_XPOS + \ - ED_BUTTON_EDOWN_XSIZE) && \ - (y)>=(DY+ED_BUTTON_EDOWN_YPOS) && \ - (y)< (DY+ED_BUTTON_EDOWN_YPOS + \ - ED_BUTTON_EDOWN_YSIZE)) || \ - ((x)>=(DX+ED_BUTTON_ELEM_XPOS) && \ - (x)< (DX+ED_BUTTON_ELEM_XPOS + \ - MAX_ELEM_X*ED_BUTTON_ELEM_XSIZE) && \ - (y)>=(DY+ED_BUTTON_ELEM_YPOS) && \ - (y)< (DY+ED_BUTTON_ELEM_YPOS + \ - MAX_ELEM_Y*ED_BUTTON_ELEM_YSIZE))) - -#define ON_COUNT_BUTTON(x,y) (((((x)>=ED_COUNT_GADGET_XPOS && \ - (x)<(ED_COUNT_GADGET_XPOS + \ - ED_BUTTON_MINUS_XSIZE)) || \ - ((x)>=(ED_COUNT_GADGET_XPOS + \ - (ED_BUTTON_PLUS_XPOS - \ - ED_BUTTON_MINUS_XPOS)) && \ - (x)<(ED_COUNT_GADGET_XPOS + \ - (ED_BUTTON_PLUS_XPOS - \ - ED_BUTTON_MINUS_XPOS) + \ - ED_BUTTON_PLUS_XSIZE))) && \ - ((y)>=ED_COUNT_GADGET_YPOS && \ - (y)<(ED_COUNT_GADGET_YPOS + \ - 16*ED_COUNT_GADGET_YSIZE)) && \ - (((y)-ED_COUNT_GADGET_YPOS) % \ - ED_COUNT_GADGET_YSIZE) < \ - ED_BUTTON_MINUS_YSIZE) || \ - ((((x)>=ED_SIZE_GADGET_XPOS && \ - (x)<(ED_SIZE_GADGET_XPOS + \ - ED_BUTTON_MINUS_XSIZE)) || \ - ((x)>=(ED_SIZE_GADGET_XPOS + \ - (ED_BUTTON_PLUS_XPOS - \ - ED_BUTTON_MINUS_XPOS)) && \ - (x)<(ED_SIZE_GADGET_XPOS + \ - (ED_BUTTON_PLUS_XPOS - \ - ED_BUTTON_MINUS_XPOS) + \ - ED_BUTTON_PLUS_XSIZE))) && \ - ((y)>=ED_SIZE_GADGET_YPOS && \ - (y)<(ED_SIZE_GADGET_YPOS + \ - 2*ED_SIZE_GADGET_YSIZE)) && \ - (((y)-ED_SIZE_GADGET_YPOS) % \ - ED_SIZE_GADGET_YSIZE) < \ - ED_BUTTON_MINUS_YSIZE)) - -#define EDIT_BUTTON(x,y) (((y) < (VY + ED_BUTTON_CTRL_YPOS + \ - ED_BUTTON_CTRL_YSIZE)) ? 0 : \ - ((y) < (VY + ED_BUTTON_CTRL_YPOS + \ - ED_BUTTON_CTRL_YSIZE + \ - ED_BUTTON_FILL_YSIZE)) ? 1 : \ - ((x) < (VX + ED_BUTTON_LEFT_XPOS + \ - ED_BUTTON_LEFT_XSIZE) ? 2 : \ - (x) > (VX + ED_BUTTON_LEFT_XPOS + \ - ED_BUTTON_LEFT_XSIZE + \ - ED_BUTTON_UP_XSIZE) ? 5 : \ - 3+(((y)-(VY + ED_BUTTON_CTRL_YPOS + \ - ED_BUTTON_CTRL_YSIZE + \ - ED_BUTTON_FILL_YSIZE)) / \ - ED_BUTTON_UP_YSIZE))) - -#define CTRL_BUTTON(x,y) (((y) < (VY + ED_BUTTON_EDIT_YPOS + \ - ED_BUTTON_EDIT_YSIZE)) ? 0 : \ - 1+(((y)-(VY + ED_BUTTON_EDIT_YPOS + \ - ED_BUTTON_EDIT_YSIZE)) / \ - ED_BUTTON_CLEAR_YSIZE)) - -#define ELEM_BUTTON(x,y) (((y) < (DY + ED_BUTTON_EUP_YPOS + \ - ED_BUTTON_EUP_YSIZE)) ? 0 : \ - ((y) > (DY + ED_BUTTON_EDOWN_YPOS)) ? 1 : \ - 2+(((y) - (DY + ED_BUTTON_ELEM_YPOS)) / \ - ED_BUTTON_ELEM_YSIZE)*MAX_ELEM_X + \ - ((x) - (DX + ED_BUTTON_ELEM_XPOS)) / \ - ED_BUTTON_ELEM_XSIZE) - -#define COUNT_BUTTON(x,y) ((x) < ED_SIZE_GADGET_XPOS ? \ - ((((y) - ED_COUNT_GADGET_YPOS) / \ - ED_COUNT_GADGET_YSIZE)*2 + \ - ((x) < (ED_COUNT_GADGET_XPOS + \ - ED_BUTTON_MINUS_XSIZE) ? 0 : 1)) : \ - 32+((((y) - ED_SIZE_GADGET_YPOS) / \ - ED_SIZE_GADGET_YSIZE)*2 + \ - ((x) < (ED_SIZE_GADGET_XPOS + \ - ED_BUTTON_MINUS_XSIZE) ? 0 : 1))) - /* values for asking control */ #define ED_BUTTON_CTRL (1L<<0) #define ED_BUTTON_FILL (1L<<1) @@ -485,13 +242,13 @@ #define ED_BUTTON_EDOWN 1 #define ED_BUTTON_ELEM 2 - void DrawVideoDisplay(unsigned long, unsigned long); void DrawCompleteVideoDisplay(void); void DrawSoundDisplay(unsigned long); void DrawGameButton(unsigned long); -void DrawChooseButton(unsigned long); -void DrawConfirmButton(unsigned long); +void DrawYesNoButton(unsigned long, int); +void DrawConfirmButton(unsigned long, int); +void DrawPlayerButton(unsigned long, int); void DrawEditButton(unsigned long state); void DrawCtrlButton(unsigned long state); void DrawElemButton(int, int); @@ -499,8 +256,9 @@ void DrawCountButton(int, int); int CheckVideoButtons(int, int, int); int CheckSoundButtons(int, int, int); int CheckGameButtons(int, int, int); -int CheckChooseButtons(int, int, int); +int CheckYesNoButtons(int, int, int); int CheckConfirmButton(int, int, int); +int CheckPlayerButtons(int, int, int); int CheckEditButtons(int, int, int); int CheckCtrlButtons(int, int, int); int CheckElemButtons(int, int, int); diff --git a/src/cartoons.c b/src/cartoons.c new file mode 100644 index 00000000..834996b7 --- /dev/null +++ b/src/cartoons.c @@ -0,0 +1,563 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* cartoons.c * +***********************************************************/ + +#include "cartoons.h" +#include "main.h" +#include "misc.h" +#include "tools.h" + +static void HandleAnimation(int); +static boolean AnimateToon(int, boolean); +static void DrawAnim(Pixmap, GC, int, int, int, int, int, int, int, int); + +struct AnimInfo +{ + int width, height; + int src_x, src_y; + int frames; + int frames_per_second; + int stepsize; + boolean pingpong; + int direction; + int position; +}; + +/* values for cartoon figures */ +#define NUM_TOONS 18 + +#define DWARF_XSIZE 40 +#define DWARF_YSIZE 48 +#define DWARF_X 2 +#define DWARF_Y 72 +#define DWARF2_Y 186 +#define DWARF_FRAMES 8 +#define DWARF_FPS 10 +#define DWARF_STEPSIZE 4 +#define JUMPER_XSIZE 48 +#define JUMPER_YSIZE 56 +#define JUMPER_X 2 +#define JUMPER_Y 125 +#define JUMPER_FRAMES 8 +#define JUMPER_FPS 10 +#define JUMPER_STEPSIZE 4 +#define CLOWN_XSIZE 80 +#define CLOWN_YSIZE 110 +#define CLOWN_X 327 +#define CLOWN_Y 10 +#define CLOWN_FRAMES 1 +#define CLOWN_FPS 10 +#define CLOWN_STEPSIZE 4 +#define BIRD_XSIZE 32 +#define BIRD_YSIZE 30 +#define BIRD1_X 2 +#define BIRD1_Y 2 +#define BIRD2_X 2 +#define BIRD2_Y 37 +#define BIRD_FRAMES 8 +#define BIRD_FPS 20 +#define BIRD_STEPSIZE 4 + +#define GAMETOON_XSIZE TILEX +#define GAMETOON_YSIZE TILEY +#define GAMETOON_FRAMES_4 4 +#define GAMETOON_FRAMES_8 8 +#define GAMETOON_FPS 20 +#define GAMETOON_STEPSIZE 4 + +#define ANIMDIR_LEFT 1 +#define ANIMDIR_RIGHT 2 +#define ANIMDIR_UP 4 +#define ANIMDIR_DOWN 8 + +#define ANIMPOS_ANY 0 +#define ANIMPOS_LEFT 1 +#define ANIMPOS_RIGHT 2 +#define ANIMPOS_UP 4 +#define ANIMPOS_DOWN 8 +#define ANIMPOS_UPPER 16 + +#define ANIM_START 0 +#define ANIM_CONTINUE 1 +#define ANIM_STOP 2 + +void InitAnimation() +{ + HandleAnimation(ANIM_START); +} + +void StopAnimation() +{ + HandleAnimation(ANIM_STOP); +} + +void DoAnimation() +{ + HandleAnimation(ANIM_CONTINUE); +} + +void HandleAnimation(int mode) +{ + static unsigned long animstart_delay = -1; + static unsigned long animstart_delay_value = 0; + static boolean anim_restart = TRUE; + static boolean reset_delay = TRUE; + static int toon_nr = 0; + int draw_mode; + + if (!setup.toons) + return; + + switch(mode) + { + case ANIM_START: + anim_restart = TRUE; + reset_delay = TRUE; + + /* Fill empty backbuffer for animation functions */ + if (setup.direct_draw && game_status == PLAYING) + { + int xx,yy; + + SetDrawtoField(DRAW_BACKBUFFER); + + for(xx=0; xxdirection & (ANIMDIR_LEFT | ANIMDIR_RIGHT)); + vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN)); + anim_delay_value = 1000/anim->frames_per_second; + frame = 0; + + if (horiz_move) + { + if (anim->position==ANIMPOS_UP) + pos_y = 0; + else if (anim->position==ANIMPOS_DOWN) + pos_y = FULL_SYSIZE-anim->height; + else if (anim->position==ANIMPOS_UPPER) + pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2); + else + pos_y = SimpleRND(FULL_SYSIZE-anim->height); + + if (anim->direction==ANIMDIR_RIGHT) + { + delta_x = anim->stepsize; + pos_x = -anim->width+delta_x; + } + else + { + delta_x = -anim->stepsize; + pos_x = FULL_SXSIZE+delta_x; + } + delta_y = 0; + } + else + { + if (anim->position==ANIMPOS_LEFT) + pos_x = 0; + else if (anim->position==ANIMPOS_RIGHT) + pos_x = FULL_SXSIZE-anim->width; + else + pos_x = SimpleRND(FULL_SXSIZE-anim->width); + + if (anim->direction==ANIMDIR_DOWN) + { + delta_y = anim->stepsize; + pos_y = -anim->height+delta_y; + } + else + { + delta_y = -anim->stepsize; + pos_y = FULL_SYSIZE+delta_y; + } + delta_x = 0; + } + } + + if (pos_x <= -anim->width - anim->stepsize || + pos_x >= FULL_SXSIZE + anim->stepsize || + pos_y <= -anim->height - anim->stepsize || + pos_y >= FULL_SYSIZE + anim->stepsize) + return(TRUE); + + if (!DelayReached(&anim_delay, anim_delay_value)) + { + if (game_status==HELPSCREEN && !restart) + DrawAnim(anim_pixmap,anim_clip_gc, + src_x+cut_x,src_y+cut_y, width,height, + REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y); + + return(FALSE); + } + + if (pos_x<-anim->width) + pos_x = -anim->width; + else if (pos_x>FULL_SXSIZE) + pos_x = FULL_SXSIZE; + if (pos_y<-anim->height) + pos_y = -anim->height; + else if (pos_y>FULL_SYSIZE) + pos_y = FULL_SYSIZE; + + pad_x = (horiz_move ? anim->stepsize : 0); + pad_y = (vert_move ? anim->stepsize : 0); + src_x = anim->src_x + frame * anim->width; + src_y = anim->src_y; + dest_x = pos_x; + dest_y = pos_y; + cut_x = cut_y = 0; + width = anim->width; + height = anim->height; + + if (pos_x<0) + { + dest_x = 0; + width += pos_x; + cut_x = -pos_x; + } + else if (pos_x>FULL_SXSIZE-anim->width) + width -= (pos_x - (FULL_SXSIZE-anim->width)); + + if (pos_y<0) + { + dest_y = 0; + height += pos_y; + cut_y = -pos_y; + } + else if (pos_y>FULL_SYSIZE-anim->height) + height -= (pos_y - (FULL_SYSIZE-anim->height)); + + DrawAnim(anim_pixmap,anim_clip_gc, + src_x+cut_x,src_y+cut_y, width,height, + REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y); + + pos_x += delta_x; + pos_y += delta_y; + frame += frame_step; + + if (frame<0 || frame>=anim->frames) + { + if (anim->pingpong) + { + frame_step *= -1; + frame = (frame<0 ? 1 : anim->frames-2); + } + else + frame = (frame<0 ? anim->frames-1 : 0); + } + + return(FALSE); +} + +void DrawAnim(Pixmap toon_pixmap, GC toon_clip_gc, + int src_x, int src_y, int width, int height, + int dest_x, int dest_y, int pad_x, int pad_y) +{ + int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1; + +#if 1 + /* special method to avoid flickering interference with BackToFront() */ + XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y, + width+2*pad_x,height+2*pad_y, buf_x,buf_y); + XSetClipOrigin(display,toon_clip_gc,dest_x-src_x,dest_y-src_y); + XCopyArea(display,toon_pixmap,backbuffer,toon_clip_gc, + src_x,src_y, width,height, dest_x,dest_y); + XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y, + width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); + BackToFront(); + XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y, + width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); +#else + /* normal method, causing flickering interference with BackToFront() */ + XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y, + width+2*pad_x,height+2*pad_y, buf_x,buf_y); + XSetClipOrigin(display,toon_clip_gc, + buf_x-src_x+pad_x,buf_y-src_y+pad_y); + XCopyArea(display,toon_pixmap,pix[PIX_DB_DOOR],toon_clip_gc, + src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y); + XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y, + width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); +#endif + + XFlush(display); +} diff --git a/src/cartoons.h b/src/cartoons.h new file mode 100644 index 00000000..fdde0cbc --- /dev/null +++ b/src/cartoons.h @@ -0,0 +1,21 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* cartoons.h * +***********************************************************/ + +#ifndef CARTOONS_H +#define CARTOONS_H + +void InitAnimation(void); +void StopAnimation(void); +void DoAnimation(void); + +#endif diff --git a/src/editor.c b/src/editor.c index 454fb74e..2955faec 100644 --- a/src/editor.c +++ b/src/editor.c @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * editor.c * ***********************************************************/ @@ -19,9 +18,29 @@ #include "buttons.h" #include "files.h" +/* positions in the level editor */ +#define ED_WIN_MB_LEFT_XPOS 7 +#define ED_WIN_MB_LEFT_YPOS 6 +#define ED_WIN_LEVELNR_XPOS 77 +#define ED_WIN_LEVELNR_YPOS 7 +#define ED_WIN_MB_MIDDLE_XPOS 7 +#define ED_WIN_MB_MIDDLE_YPOS 258 +#define ED_WIN_MB_RIGHT_XPOS 77 +#define ED_WIN_MB_RIGHT_YPOS 258 + +/* other constants for the editor */ +#define ED_SCROLL_NO 0 +#define ED_SCROLL_LEFT 1 +#define ED_SCROLL_RIGHT 2 +#define ED_SCROLL_UP 4 +#define ED_SCROLL_DOWN 8 + +/* delay value to avoid too fast scrolling etc. */ +#define CHOICE_DELAY_VALUE 100 + static int level_xpos,level_ypos; -static BOOL edit_mode; -static BOOL name_typing; +static boolean edit_mode; +static boolean name_typing; static int new_element1 = EL_MAUERWERK; static int new_element2 = EL_LEERRAUM; static int new_element3 = EL_ERDREICH; @@ -29,6 +48,66 @@ static int new_element3 = EL_ERDREICH; int element_shift; int editor_element[] = { + EL_CHAR_A + ('B' - 'A'), + EL_CHAR_A + ('O' - 'A'), + EL_CHAR_A + ('U' - 'A'), + EL_CHAR_A + ('L' - 'A'), + + EL_CHAR_MINUS, + EL_CHAR_A + ('D' - 'A'), + EL_CHAR_A + ('E' - 'A'), + EL_CHAR_A + ('R' - 'A'), + + EL_CHAR_A + ('D' - 'A'), + EL_CHAR_A + ('A' - 'A'), + EL_CHAR_A + ('S' - 'A'), + EL_CHAR_A + ('H' - 'A'), + + EL_SPIELFIGUR, + EL_LEERRAUM, + EL_ERDREICH, + EL_BETON, + + EL_FELSBODEN, + EL_SIEB2_LEER, + EL_AUSGANG_ZU, + EL_AUSGANG_AUF, + + EL_EDELSTEIN_BD, + EL_BUTTERFLY_O, + EL_FIREFLY_O, + EL_FELSBROCKEN, + + EL_BUTTERFLY_L, + EL_FIREFLY_L, + EL_BUTTERFLY_R, + EL_FIREFLY_R, + + EL_AMOEBE_BD, + EL_BUTTERFLY_U, + EL_FIREFLY_U, + EL_LEERRAUM, + + EL_CHAR_A + ('E' - 'A'), + EL_CHAR_A + ('M' - 'A'), + EL_CHAR_A + ('E' - 'A'), + EL_CHAR_MINUS, + + EL_CHAR_A + ('R' - 'A'), + EL_CHAR_A + ('A' - 'A'), + EL_CHAR_A + ('L' - 'A'), + EL_CHAR_A + ('D' - 'A'), + + EL_CHAR_A + ('M' - 'A'), + EL_CHAR_A + ('I' - 'A'), + EL_CHAR_A + ('N' - 'A'), + EL_CHAR_A + ('E' - 'A'), + + EL_SPIELER1, + EL_SPIELER2, + EL_SPIELER3, + EL_SPIELER4, + EL_SPIELFIGUR, EL_LEERRAUM, EL_ERDREICH, @@ -44,51 +123,46 @@ int editor_element[] = EL_KOKOSNUSS, EL_BOMBE, + EL_ERZ_EDEL, + EL_ERZ_DIAM, EL_MORAST_LEER, EL_MORAST_VOLL, + + EL_DYNAMIT_AUS, + EL_DYNAMIT, EL_AUSGANG_ZU, EL_AUSGANG_AUF, - EL_KAEFER, - EL_FLIEGER, EL_MAMPFER, - EL_ZOMBIE, + EL_KAEFER_O, + EL_FLIEGER_O, + EL_ROBOT, + + EL_KAEFER_L, + EL_FLIEGER_L, + EL_KAEFER_R, + EL_FLIEGER_R, - EL_PACMAN, - EL_DYNAMIT_AUS, - EL_DYNAMIT, EL_ABLENK_AUS, + EL_KAEFER_U, + EL_FLIEGER_U, + EL_UNSICHTBAR, EL_BADEWANNE1, EL_SALZSAEURE, EL_BADEWANNE2, - EL_BADEWANNE, + EL_LEERRAUM, EL_BADEWANNE3, EL_BADEWANNE4, EL_BADEWANNE5, - EL_UNSICHTBAR, + EL_LEERRAUM, EL_TROPFEN, EL_AMOEBE_TOT, EL_AMOEBE_NASS, EL_AMOEBE_NORM, - EL_AMOEBE_VOLL, - -/* - EL_LIFE, -*/ - EL_LIFE_ASYNC, - - EL_ERZ_EDEL, - EL_ERZ_DIAM, - - EL_ZEIT_VOLL, - EL_ZEIT_LEER, - EL_BIRNE_AUS, - EL_BIRNE_EIN, - EL_SCHLUESSEL1, EL_SCHLUESSEL2, EL_SCHLUESSEL3, @@ -104,20 +178,92 @@ int editor_element[] = EL_PFORTE3X, EL_PFORTE4X, - EL_KAEFER_R, - EL_KAEFER_O, - EL_KAEFER_L, - EL_KAEFER_U, + EL_CHAR_A + ('M' - 'A'), + EL_CHAR_A + ('O' - 'A'), + EL_CHAR_A + ('R' - 'A'), + EL_CHAR_A + ('E' - 'A'), - EL_FLIEGER_R, - EL_FLIEGER_O, - EL_FLIEGER_L, - EL_FLIEGER_U, + EL_PFEIL_L, + EL_PFEIL_R, + EL_PFEIL_O, + EL_PFEIL_U, - EL_PACMAN_R, + EL_AMOEBE_VOLL, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, + + EL_ERZ_EDEL_BD, + EL_ERZ_EDEL_GELB, + EL_ERZ_EDEL_ROT, + EL_ERZ_EDEL_LILA, + + EL_LIFE, EL_PACMAN_O, + EL_ZEIT_VOLL, + EL_ZEIT_LEER, + EL_PACMAN_L, + EL_MAMPFER2, + EL_PACMAN_R, + EL_MAUER_LEBT, + + EL_LIFE_ASYNC, EL_PACMAN_U, + EL_BIRNE_AUS, + EL_BIRNE_EIN, + + EL_DYNABOMB_NR, + EL_DYNABOMB_SZ, + EL_DYNABOMB_XL, + EL_BADEWANNE, + + EL_MAULWURF, + EL_PINGUIN, + EL_SCHWEIN, + EL_DRACHE, + + EL_SONDE, + EL_MAUER_X, + EL_MAUER_Y, + EL_MAUER_XY, + + EL_CHAR_A + ('S' - 'A'), + EL_CHAR_A + ('O' - 'A'), + EL_CHAR_A + ('K' - 'A'), + EL_CHAR_A + ('O' - 'A'), + + EL_CHAR_MINUS, + EL_CHAR_A + ('B' - 'A'), + EL_CHAR_A + ('A' - 'A'), + EL_CHAR_A + ('N' - 'A'), + + EL_SOKOBAN_OBJEKT, + EL_SOKOBAN_FELD_LEER, + EL_SOKOBAN_FELD_VOLL, + EL_BETON, + +/* + EL_CHAR_A + ('D' - 'A'), + EL_CHAR_A + ('Y' - 'A'), + EL_CHAR_A + ('N' - 'A'), + EL_CHAR_A + ('A' - 'A'), + + EL_CHAR_A + ('B' - 'A'), + EL_CHAR_A + ('L' - 'A'), + EL_CHAR_A + ('A' - 'A'), + EL_CHAR_A + ('S' - 'A'), + + EL_CHAR_MINUS, + EL_CHAR_A + ('T' - 'A'), + EL_CHAR_A + ('E' - 'A'), + EL_CHAR_A + ('R' - 'A'), +*/ + + EL_LEERRAUM, + EL_LEERRAUM, + EL_LEERRAUM, + EL_LEERRAUM, EL_CHAR_AUSRUF, EL_CHAR_ZOLL, @@ -228,26 +374,26 @@ void DrawLevelEd() else graphic = GFX_LEERRAUM; - DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 + - (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE, - DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 + - (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE, - graphic); + DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc, + DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 + + (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE, + DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 + + (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE, + graphic); } - DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS, - DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS, - el2gfx(new_element1)); - DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS, - DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS, - el2gfx(new_element2)); - DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS, - DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS, - el2gfx(new_element3)); + DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc, + DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS, + DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS, + el2gfx(new_element1)); + DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc, + DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS, + DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS, + el2gfx(new_element2)); + DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc, + DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS, + DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS, + el2gfx(new_element3)); DrawTextExt(pix[PIX_DB_DOOR],gc, DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS, DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS, @@ -479,27 +625,28 @@ void FloodFill(int from_x, int from_y, int fill_element) { int i,x,y; int old_element; - static int check[4][2] = { -1,0, 0,-1, 1,0, 0,1 }; + static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} }; static int safety = 0; + /* check if starting field still has the desired content */ + if (Feld[from_x][from_y] == fill_element) + return; + safety++; - if (safety>lev_fieldx*lev_fieldy) - { - fprintf(stderr,"Something went wrong in 'FloodFill()'. Please debug.\n"); - exit(-1); - } + if (safety > lev_fieldx*lev_fieldy) + Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug."); old_element = Feld[from_x][from_y]; Feld[from_x][from_y] = fill_element; for(i=0;i<4;i++) { - x = from_x+check[i][0]; - y = from_y+check[i][1]; + x = from_x + check[i][0]; + y = from_y + check[i][1]; - if (IN_LEV_FIELD(x,y) && Feld[x][y]==old_element) - FloodFill(x,y,fill_element); + if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element) + FloodFill(x, y, fill_element); } safety--; @@ -509,7 +656,7 @@ void LevelEd(int mx, int my, int button) { static int last_button = 0; static int in_field_pressed = FALSE; - static BOOL use_floodfill = FALSE; + static boolean use_floodfill = FALSE; int x = (mx-SX)/MINI_TILEX; int y = (my-SY)/MINI_TILEY; @@ -547,69 +694,61 @@ void LevelEd(int mx, int my, int button) } else /********** EDIT/CTRL-FENSTER **********/ { + static unsigned long choice_delay = 0; int choice = CheckElemButtons(mx,my,button); int elem_pos = choice-ED_BUTTON_ELEM; - switch(choice) + if (((choice == ED_BUTTON_EUP && element_shift>0) || + (choice == ED_BUTTON_EDOWN && + element_shift0) || - (choice==ED_BUTTON_EDOWN && - element_shiftelements_in_list-MAX_ELEM_X*MAX_ELEM_Y) - element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y; - if (element_shift % MAX_ELEM_X) - element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X); - - for(i=0;i=0 && elem_poselements_in_list-MAX_ELEM_X*MAX_ELEM_Y) + element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y; + if (element_shift % MAX_ELEM_X) + element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X); + + for(i=0;i=0 && elem_pos=0) { + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -642,13 +783,13 @@ void LevelEd(int mx, int my, int button) ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT); else DrawMiniLevel(level_xpos,level_ypos); - BackToFront(); - Delay(100000); } break; case ED_BUTTON_RIGHT: if (level_xpos<=lev_fieldx-2*SCR_FIELDX) { + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + break; if (lev_fieldx<2*SCR_FIELDX-2) break; @@ -659,13 +800,13 @@ void LevelEd(int mx, int my, int button) ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT); else DrawMiniLevel(level_xpos,level_ypos); - BackToFront(); - Delay(100000); } break; case ED_BUTTON_UP: if (level_ypos>=0) { + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -676,13 +817,13 @@ void LevelEd(int mx, int my, int button) ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN); else DrawMiniLevel(level_xpos,level_ypos); - BackToFront(); - Delay(100000); } break; case ED_BUTTON_DOWN: if (level_ypos<=lev_fieldy-2*SCR_FIELDY) { + if (!DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) + break; if (lev_fieldy<2*SCR_FIELDY-2) break; @@ -693,8 +834,6 @@ void LevelEd(int mx, int my, int button) ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP); else DrawMiniLevel(level_xpos,level_ypos); - BackToFront(); - Delay(100000); } break; default: @@ -747,11 +886,11 @@ void LevelEd(int mx, int my, int button) } else /********** KONTROLL-FENSTER **********/ { - static long choice_delay = 0; int choice = CheckCountButtons(mx,my,button); int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0); - if (choice>=0 && choice<36 && DelayReached(&choice_delay,10)) + if (choice >= 0 && choice < 36 && + DelayReached(&choice_delay, CHOICE_DELAY_VALUE)) { if (!(choice % 2)) step = -step; @@ -890,7 +1029,7 @@ void LevelEd(int mx, int my, int button) edit_mode = TRUE; break; case ED_BUTTON_CLEAR: - if (AreYouSure("Are you sure to clear this level ?",AYS_ASK)) + if (Request("Are you sure to clear this level ?",REQ_ASK)) { for(x=0;x0) + else if ((key==XK_Delete || key==XK_BackSpace) && len>0) { level.name[len-1] = 0; len--; diff --git a/src/editor.h b/src/editor.h index b4ebfed2..dae87c12 100644 --- a/src/editor.h +++ b/src/editor.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * editor.h * ***********************************************************/ @@ -17,32 +16,15 @@ #include "main.h" -/* positions in the level editor */ -#define ED_WIN_MB_LEFT_XPOS 7 -#define ED_WIN_MB_LEFT_YPOS 6 -#define ED_WIN_LEVELNR_XPOS 77 -#define ED_WIN_LEVELNR_YPOS 7 -#define ED_WIN_MB_MIDDLE_XPOS 7 -#define ED_WIN_MB_MIDDLE_YPOS 258 -#define ED_WIN_MB_RIGHT_XPOS 77 -#define ED_WIN_MB_RIGHT_YPOS 258 - +/* number of element button columns and rows in the edit window */ #define MAX_ELEM_X 4 #define MAX_ELEM_Y 10 -/* other constants for the editor */ -#define ED_SCROLL_NO 0 -#define ED_SCROLL_LEFT 1 -#define ED_SCROLL_RIGHT 2 -#define ED_SCROLL_UP 4 -#define ED_SCROLL_DOWN 8 - extern int element_shift; extern int editor_element[]; extern int elements_in_list; void DrawLevelEd(void); -void ScrollMiniLevel(int, int, int); void LevelEd(int, int, int); void LevelNameTyping(KeySym); diff --git a/src/events.c b/src/events.c index 9eb8d623..2d8eca3e 100644 --- a/src/events.c +++ b/src/events.c @@ -1,29 +1,37 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * events.c * ***********************************************************/ #include "events.h" +#include "init.h" #include "screens.h" #include "tools.h" #include "game.h" #include "editor.h" #include "misc.h" +#include "tape.h" +#include "joystick.h" +#include "network.h" + +/* values for key_status */ +#define KEY_NOT_PRESSED FALSE +#define KEY_RELEASED FALSE +#define KEY_PRESSED TRUE void EventLoop(void) { while(1) { - if (XPending(display)) /* got an event */ + if (XPending(display)) /* got event from X server */ { XEvent event; @@ -31,52 +39,68 @@ void EventLoop(void) switch(event.type) { - case Expose: - HandleExposeEvent((XExposeEvent *) &event); - break; - case UnmapNotify: - SleepWhileUnmapped(); - break; case ButtonPress: - HandleButtonEvent((XButtonEvent *) &event); - break; case ButtonRelease: HandleButtonEvent((XButtonEvent *) &event); break; + case MotionNotify: HandleMotionEvent((XMotionEvent *) &event); break; + case KeyPress: - HandleKeyEvent((XKeyEvent *) &event); - break; case KeyRelease: HandleKeyEvent((XKeyEvent *) &event); break; - case FocusIn: - HandleFocusEvent(FOCUS_IN); - break; - case FocusOut: - HandleFocusEvent(FOCUS_OUT); - break; + default: + HandleOtherEvents(&event); break; } } - else /* got no event, but don't be lazy... */ - { - HandleNoXEvent(); - XSync(display,FALSE); + HandleNoXEvent(); + + /* don't use all CPU time when idle; the main loop while playing + has its own synchronization and is CPU friendly, too */ - if (game_status!=PLAYING) - Delay(10000); /* don't use all CPU time when idle */ + if (game_status != PLAYING) + { + XSync(display, FALSE); + Delay(10); } - if (game_status==EXITGAME) + if (game_status == EXITGAME) return; } } +void HandleOtherEvents(XEvent *event) +{ + switch(event->type) + { + case Expose: + HandleExposeEvent((XExposeEvent *) event); + break; + + case UnmapNotify: + SleepWhileUnmapped(); + break; + + case FocusIn: + case FocusOut: + HandleFocusEvent((XFocusChangeEvent *) event); + break; + + case ClientMessage: + HandleClientMessageEvent((XClientMessageEvent *) event); + break; + + default: + break; + } +} + void ClearEventQueue() { while(XPending(display)) @@ -87,25 +111,16 @@ void ClearEventQueue() switch(event.type) { - case Expose: - HandleExposeEvent((XExposeEvent *) &event); - break; - case UnmapNotify: - SleepWhileUnmapped(); - break; case ButtonRelease: button_status = MB_RELEASED; break; + case KeyRelease: - key_status = KEY_RELEASED; - break; - case FocusIn: - HandleFocusEvent(FOCUS_IN); - break; - case FocusOut: - HandleFocusEvent(FOCUS_OUT); + key_joystick_mapping = 0; break; + default: + HandleOtherEvents(&event); break; } } @@ -113,7 +128,7 @@ void ClearEventQueue() void SleepWhileUnmapped() { - BOOL window_unmapped = TRUE; + boolean window_unmapped = TRUE; XAutoRepeatOn(display); @@ -125,19 +140,27 @@ void SleepWhileUnmapped() switch(event.type) { - case Expose: - HandleExposeEvent((XExposeEvent *) &event); - break; case ButtonRelease: button_status = MB_RELEASED; break; + case KeyRelease: - key_status = KEY_RELEASED; + key_joystick_mapping = 0; break; + case MapNotify: window_unmapped = FALSE; break; + + case UnmapNotify: + /* this is only to surely prevent the 'should not happen' case + * of recursively looping between 'SleepWhileUnmapped()' and + * 'HandleOtherEvents()' which usually calls this funtion. + */ + break; + default: + HandleOtherEvents(&event); break; } } @@ -151,21 +174,37 @@ void HandleExposeEvent(XExposeEvent *event) int x = event->x, y = event->y; int width = event->width, height = event->height; - XCopyArea(display,drawto,window,gc, x,y, width,height, x,y); - - if (direct_draw_on && game_status==PLAYING) + if (setup.direct_draw && game_status==PLAYING) { int xx,yy; int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY; int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY; - for(xx=0;xx=x1 && xx<=x2 && yy>=y1 && yy<=y2) DrawScreenField(xx,yy); - DrawLevelElement(JX,JY,EL_SPIELFIGUR); + DrawAllPlayers(); + + SetDrawtoField(DRAW_DIRECT); } + if (setup.soft_scrolling && game_status == PLAYING) + { + int fx = FX, fy = FY; + + fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0); + fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0); + + XCopyArea(display,fieldbuffer,backbuffer,gc, + fx,fy, SXSIZE,SYSIZE, + SX,SY); + } + + XCopyArea(display,drawto,window,gc, x,y, width,height, x,y); + XFlush(display); } @@ -190,34 +229,40 @@ void HandleMotionEvent(XMotionEvent *event) void HandleKeyEvent(XKeyEvent *event) { - static KeySym old_keycode = 0; - int new_keycode = event->keycode; - KeySym new_key = XLookupKeysym(event,event->state); - int new_key_status = (event->type==KeyPress ? KEY_PRESSED : KEY_RELEASED); + int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED); + unsigned int event_state = (game_status != PLAYING ? event->state : 0); + KeySym key = XLookupKeysym(event, event_state); + + HandleKey(key, key_status); +} - if (game_status==PLAYING && - (old_keycode!=new_keycode || key_status!=new_key_status)) +void HandleFocusEvent(XFocusChangeEvent *event) +{ + static int old_joystick_status = -1; + + if (event->type == FocusOut) { - DigField(0,0,DF_NO_PUSH); - SnapField(0,0); + XAutoRepeatOn(display); + old_joystick_status = joystick_status; + joystick_status = JOYSTICK_OFF; + key_joystick_mapping = 0; } - - if (event->type==KeyPress) + else if (event->type == FocusIn) { - key_status = KEY_PRESSED; - HandleKey(new_key); - old_keycode = new_keycode; + if (game_status == PLAYING) + XAutoRepeatOff(display); + if (old_joystick_status != -1) + joystick_status = old_joystick_status; } - else if (key_status==KEY_PRESSED && old_keycode==new_keycode) - key_status = KEY_RELEASED; } -void HandleFocusEvent(int focus_status) +void HandleClientMessageEvent(XClientMessageEvent *event) { - if (focus_status==FOCUS_OUT) - XAutoRepeatOn(display); - else if (game_status==PLAYING) - XAutoRepeatOff(display); +#ifndef MSDOS + if ((event->window == window) && + (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE))) + CloseAllAndExit(0); +#endif } void HandleButton(int mx, int my, int button) @@ -234,72 +279,153 @@ void HandleButton(int mx, int my, int button) old_mx = mx; old_my = my; - HandleVideoButtons(mx,my,button); - HandleSoundButtons(mx,my,button); - HandleGameButtons(mx,my,button); + HandleVideoButtons(mx,my, button); + HandleSoundButtons(mx,my, button); + HandleGameButtons(mx,my, button); } switch(game_status) { case MAINMENU: - HandleMainMenu(mx,my,0,0,button); + HandleMainMenu(mx,my, 0,0, button); break; + case TYPENAME: - HandleTypeName(0,XK_Return); + HandleTypeName(0, XK_Return); break; + case CHOOSELEVEL: - HandleChooseLevel(mx,my,0,0,button); + HandleChooseLevel(mx,my, 0,0, button); break; + case HALLOFFAME: HandleHallOfFame(button); break; + case LEVELED: - LevelEd(mx,my,button); + LevelEd(mx,my, button); break; + case HELPSCREEN: HandleHelpScreen(button); break; + case SETUP: - HandleSetupScreen(mx,my,0,0,button); + HandleSetupScreen(mx,my, 0,0, button); + break; + + case SETUPINPUT: + HandleSetupInputScreen(mx,my, 0,0, button); break; + case PLAYING: - if (!LevelSolved) +#ifdef DEBUG + if (button == MB_RELEASED) { - switch(GameActions(mx,my,button)) + int sx = (mx - SX) / TILEX; + int sy = (my - SY) / TILEY; + + if (IN_VIS_FIELD(sx,sy)) { - case ACT_GAME_OVER: - game_status = MAINMENU; - DrawMainMenu(); - BackToFront(); - break; - case ACT_NEW_GAME: - game_status = PLAYING; - InitGame(); - break; - case ACT_GO_ON: - break; - default: - break; + int x = LEVELX(sx); + int y = LEVELY(sy); + + printf("INFO: Feld[%d][%d] == %d\n", x,y, Feld[x][y]); + printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]); + printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]); + printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]); + printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]); + printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]); + printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]); + printf("\n"); } } - BackToFront(); - Delay(10000); +#endif break; + default: break; } } -void HandleKey(KeySym key) +void HandleKey(KeySym key, int key_status) { - static KeySym old_key = 0; + int joy = 0; + static struct SetupKeyboardInfo custom_key; + static struct + { + KeySym *keysym_custom; + KeySym keysym_default; + byte action; + } key_info[] = + { + { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT }, + { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT }, + { &custom_key.up, DEFAULT_KEY_UP, JOY_UP }, + { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN }, + { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 }, + { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 } + }; + + if (game_status == PLAYING) + { + int pnr; + + for (pnr=0; pnrdynamite = 1000; break; -#ifdef XK_KP_End - case XK_KP_End: -#endif - case XK_KP_1: - mvx = -1; - mvy = 1; - joy = JOY_DOWN | JOY_LEFT; + + + +#if 0 + + case XK_z: + { + int i; + + for(i=0; i +#include +#include +#include + #include "files.h" #include "tools.h" #include "misc.h" - -BOOL CreateNewScoreFile() +#include "tape.h" +#include "joystick.h" + +#define MAX_FILENAME_LEN 256 /* maximal filename length */ +#define MAX_LINE_LEN 1000 /* maximal input line length */ +#define CHUNK_ID_LEN 4 /* IFF style chunk id length */ +#define LEVEL_HEADER_SIZE 80 /* size of level file header */ +#define LEVEL_HEADER_UNUSED 18 /* unused level header bytes */ +#define TAPE_HEADER_SIZE 20 /* size of tape file header */ +#define TAPE_HEADER_UNUSED 7 /* unused tape header bytes */ +#define FILE_VERSION_1_0 10 /* old 1.0 file version */ +#define FILE_VERSION_1_2 12 /* actual file version */ + +/* file identifier strings */ +#define LEVEL_COOKIE "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2" +#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" +#define TAPE_COOKIE "ROCKSNDIAMONDS_TAPE_FILE_VERSION_1.2" +#define SETUP_COOKIE "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2" +#define LEVELSETUP_COOKIE "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2" +#define LEVELINFO_COOKIE "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2" +/* old file identifiers for backward compatibility */ +#define LEVEL_COOKIE_10 "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.0" +#define TAPE_COOKIE_10 "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0" + +/* file names and filename extensions */ +#ifndef MSDOS +#define USERDATA_DIRECTORY ".rocksndiamonds" +#define SETUP_FILENAME "setup.conf" +#define LEVELSETUP_FILENAME "levelsetup.conf" +#define LEVELINFO_FILENAME "levelinfo.conf" +#define LEVELFILE_EXTENSION "level" +#define TAPEFILE_EXTENSION "tape" +#define SCOREFILE_EXTENSION "score" +#else +#define USERDATA_DIRECTORY "userdata" +#define SETUP_FILENAME "setup.cnf" +#define LEVELSETUP_FILENAME "lvlsetup.cnf" +#define LEVELINFO_FILENAME "lvlinfo.cnf" +#define LEVELFILE_EXTENSION "lvl" +#define TAPEFILE_EXTENSION "tap" +#define SCOREFILE_EXTENSION "sco" +#define ERROR_FILENAME "error.out" +#endif + +/* file permissions for newly written files */ +#define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) +#define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) +#define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) +#define USERDATA_DIR_MODE (MODE_R_ALL | MODE_X_ALL | S_IWUSR) +#define LEVEL_PERMS (MODE_R_ALL | MODE_W_ALL) +#define SCORE_PERMS LEVEL_PERMS +#define TAPE_PERMS LEVEL_PERMS +#define SETUP_PERMS LEVEL_PERMS + +static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ +static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ + +static char *getGlobalDataDir() { - int i,j,k; - char filename[MAX_FILENAME]; - char empty_alias[MAX_NAMELEN]; - FILE *file; - - sprintf(filename,"%s/%s/%s", - SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME); - - if (!(file=fopen(filename,"w"))) - return(FALSE); + return GAME_DIR; +} - for(i=0;i 0) + userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); + else + userlevel_dir = getPath2(data_dir, userlevel_subdir); - chmod(filename, NAMES_PERMS); - return(TRUE); + return userlevel_dir; } -BOOL LoadLevelInfo() +static char *getTapeDir(char *level_subdir) { - int i; - char filename[MAX_FILENAME]; - char cookie[MAX_FILENAME]; - FILE *file; + static char *tape_dir = NULL; + char *data_dir = getUserDataDir(); + char *tape_subdir = TAPES_DIRECTORY; - sprintf(filename,"%s/%s",LEVEL_PATH,LEVDIR_FILENAME); + if (tape_dir) + free(tape_dir); - if (!(file=fopen(filename,"r"))) - { - fprintf(stderr,"%s: cannot load level info '%s'!\n",progname,filename); - return(FALSE); - } + if (strlen(level_subdir) > 0) + tape_dir = getPath3(data_dir, tape_subdir, level_subdir); + else + tape_dir = getPath2(data_dir, tape_subdir); - fscanf(file,"%s\n",cookie); - if (strcmp(cookie,LEVELDIR_COOKIE)) /* ungültiges Format? */ - { - fprintf(stderr,"%s: wrong format of level info file!\n",progname); - fclose(file); - return(FALSE); - } + return tape_dir; +} - num_leveldirs = 0; - leveldir_nr = 0; - for(i=0;i 0) + score_dir = getPath3(data_dir, score_subdir, level_subdir); + else + score_dir = getPath2(data_dir, score_subdir); - return(TRUE); + return score_dir; } -void LoadLevel(int level_nr) +static char *getLevelFilename(int nr) { - int i,x,y; - char filename[MAX_FILENAME]; - char cookie[MAX_FILENAME]; - FILE *file; + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; - sprintf(filename,"%s/%s/%d", - LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr); + if (filename != NULL) + free(filename); - if (!(file=fopen(filename,"r"))) - { -/* - fprintf(stderr,"%s: cannot load level '%s'!\n",progname,filename); -*/ - } - else - { - fgets(cookie,LEVEL_COOKIE_LEN,file); - fgetc(file); - if (strcmp(cookie,LEVEL_COOKIE)) /* ungültiges Format? */ - { - fprintf(stderr,"%s: wrong format of level file '%s'!\n", - progname,filename); - fclose(file); - file = NULL; - } - } + sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION); + filename = getPath3((leveldir[leveldir_nr].user_defined ? + getUserLevelDir("") : + options.level_directory), + leveldir[leveldir_nr].filename, + basename); - if (file) - { - lev_fieldx = level.fieldx = fgetc(file); - lev_fieldy = level.fieldy = fgetc(file); + return filename; +} - level.time = (fgetc(file)<<8) | fgetc(file); - level.edelsteine = (fgetc(file)<<8) | fgetc(file); - for(i=0;i=MAX_TAPELEN) - break; - tape.pos[i].joystickdata = fgetc(file); - tape.pos[i].delay = fgetc(file); - if (feof(file)) - break; - } + level.time = 100; + level.edelsteine = 0; + level.tempo_amoebe = 10; + level.dauer_sieb = 10; + level.dauer_ablenk = 10; + level.amoebe_inhalt = EL_DIAMANT; - if (i != tape.length) - fprintf(stderr,"%s: level recording file '%s' corrupted!\n", - progname,filename); + strcpy(level.name, "Nameless Level"); - fclose(file); + for(i=0; i 0 && cookie[strlen(cookie) - 1] == '\n') + cookie[strlen(cookie) - 1] = '\0'; + + if (strcmp(cookie, LEVEL_COOKIE_10) == 0) /* old 1.0 level format */ + file_version = FILE_VERSION_1_0; + else if (strcmp(cookie, LEVEL_COOKIE) != 0) /* unknown level format */ + { + Error(ERR_WARN, "wrong file identifier of level file '%s'", filename); + fclose(file); + return; } - if (file) + /* read chunk "HEAD" */ + if (file_version >= FILE_VERSION_1_2) { - fgets(cookie,SCORE_COOKIE_LEN,file); - if (strcmp(cookie,SCORE_COOKIE)) /* ungültiges Format? */ + /* first check header chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + if (strcmp(chunk, "HEAD") || chunk_length != LEVEL_HEADER_SIZE) { - fprintf(stderr,"%s: wrong format of score file!\n",progname); + Error(ERR_WARN, "wrong 'HEAD' chunk of level file '%s'", filename); fclose(file); - file = NULL; + return; } } - if (file) + lev_fieldx = level.fieldx = fgetc(file); + lev_fieldy = level.fieldy = fgetc(file); + + level.time = (fgetc(file)<<8) | fgetc(file); + level.edelsteine = (fgetc(file)<<8) | fgetc(file); + + for(i=0; i= FILE_VERSION_1_2) { - fseek(file, - SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)), - SEEK_SET); - for(i=0;i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); + + fputc(level.fieldx, file); + fputc(level.fieldy, file); + fputc(level.time / 256, file); + fputc(level.time % 256, file); + fputc(level.edelsteine / 256, file); + fputc(level.edelsteine % 256, file); + + for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); + + for(y=0; y 0 && cookie[strlen(cookie) - 1] == '\n') + cookie[strlen(cookie) - 1] = '\0'; + + if (strcmp(cookie, TAPE_COOKIE_10) == 0) /* old 1.0 tape format */ + file_version = FILE_VERSION_1_0; + else if (strcmp(cookie, TAPE_COOKIE) != 0) /* unknown tape format */ { - if (!CreateNewNamesFile(mode)) - { - fprintf(stderr,"%s: cannot create names file '%s'!\n", - progname,filename); - } - else if (!(file=fopen(filename,"r"))) - { - fprintf(stderr,"%s: cannot load player information '%s'!\n", - progname,filename); - } + Error(ERR_WARN, "wrong file identifier of tape file '%s'", filename); + fclose(file); + return; } - if (file) + /* read chunk "HEAD" */ + if (file_version >= FILE_VERSION_1_2) { - fgets(cookie,NAMES_COOKIE_LEN,file); - if (strcmp(cookie,NAMES_COOKIE)) /* ungültiges Format? */ + /* first check header chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + + if (strcmp(chunk, "HEAD") || chunk_length != TAPE_HEADER_SIZE) { - fprintf(stderr,"%s: wrong format of names file '%s'!\n", - progname,filename); + Error(ERR_WARN, "wrong 'HEAD' chunk of tape file '%s'", filename); fclose(file); - file = NULL; + return; } } - if (!file) - { - player = default_player; - level_nr = default_player.handicap; - return; - } + tape.random_seed = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + tape.date = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + tape.length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); - while(1) + /* read header fields that are new since version 1.2 */ + if (file_version >= FILE_VERSION_1_2) { - for(i=0;i= FILE_VERSION_1_2) { - player = new_player; - if (player.leveldir_nr < num_leveldirs) - leveldir_nr = player.leveldir_nr; - else - leveldir_nr = 0; + /* next check body chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + if (strcmp(chunk, "BODY") || + chunk_length != (num_participating_players + 1) * tape.length) + { + Error(ERR_WARN, "wrong 'BODY' chunk of tape file '%s'", filename); + fclose(file); + return; + } } - else - player.handicap = new_player.handicap; - level_nr = player.handicap; - fclose(file); -} + for(i=0; i= MAX_TAPELEN) + break; -void SaveLevel(int level_nr) -{ - int i,x,y; - char filename[MAX_FILENAME]; - FILE *file; + for(j=0; j 0) + tape.pos[i + num_moves].delay = 0; + num_moves++; + } + } + + if (num_moves > 1) + { + num_moves--; + i += num_moves; + tape.length += num_moves; + } + } - fputs(LEVEL_COOKIE,file); /* Formatkennung */ - fputc(0x0a,file); - - fputc(level.fieldx,file); - fputc(level.fieldy,file); - fputc(level.time / 256,file); - fputc(level.time % 256,file); - fputc(level.edelsteine / 256,file); - fputc(level.edelsteine % 256,file); - - for(i=0;i> 24) & 0xff,file); - fputc((tape.random_seed >> 16) & 0xff,file); - fputc((tape.random_seed >> 8) & 0xff,file); - fputc((tape.random_seed >> 0) & 0xff,file); + chunk_length = TAPE_HEADER_SIZE; - fputc((tape.date >> 24) & 0xff,file); - fputc((tape.date >> 16) & 0xff,file); - fputc((tape.date >> 8) & 0xff,file); - fputc((tape.date >> 0) & 0xff,file); + fputc((chunk_length >> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); - fputc((tape.length >> 24) & 0xff,file); - fputc((tape.length >> 16) & 0xff,file); - fputc((tape.length >> 8) & 0xff,file); - fputc((tape.length >> 0) & 0xff,file); + fputc((tape.random_seed >> 24) & 0xff, file); + fputc((tape.random_seed >> 16) & 0xff, file); + fputc((tape.random_seed >> 8) & 0xff, file); + fputc((tape.random_seed >> 0) & 0xff, file); - for(i=0;i> 24) & 0xff, file); + fputc((tape.date >> 16) & 0xff, file); + fputc((tape.date >> 8) & 0xff, file); + fputc((tape.date >> 0) & 0xff, file); - fclose(file); + fputc((tape.length >> 24) & 0xff, file); + fputc((tape.length >> 16) & 0xff, file); + fputc((tape.length >> 8) & 0xff, file); + fputc((tape.length >> 0) & 0xff, file); - chmod(filename, LEVREC_PERMS); + fputc(store_participating_players, file); - if (new_tape) - AreYouSure("tape saved !",AYS_CONFIRM); -} + for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); - if (!(file=fopen(filename,"r+"))) + for(i=0; i 0 && cookie[strlen(cookie) - 1] == '\n') + cookie[strlen(cookie) - 1] = '\0'; + + if (strcmp(cookie, SCORE_COOKIE) != 0) { - fprintf(stderr,"%s: wrong format of names file '%s'!\n", - progname,filename); + Error(ERR_WARN, "wrong file identifier of score file '%s'", filename); fclose(file); return; } - while(1) + for(i=0; i= 100) + return s; + + strcpy(s_lower, s); + + for (i=0; itoken) + free(setup_file_list->token); + if (setup_file_list->value) + free(setup_file_list->value); + if (setup_file_list->next) + freeSetupFileList(setup_file_list->next); + free(setup_file_list); +} + +static struct SetupFileList *newSetupFileList(char *token, char *value) +{ + struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList)); + + new->token = checked_malloc(strlen(token) + 1); + strcpy(new->token, token); + + new->value = checked_malloc(strlen(value) + 1); + strcpy(new->value, value); + + new->next = NULL; + + return new; +} + +static char *getTokenValue(struct SetupFileList *setup_file_list, + char *token) +{ + if (!setup_file_list) + return NULL; + + if (strcmp(setup_file_list->token, token) == 0) + return setup_file_list->value; + else + return getTokenValue(setup_file_list->next, token); +} + +static void setTokenValue(struct SetupFileList *setup_file_list, + char *token, char *value) +{ + if (!setup_file_list) + return; + + if (strcmp(setup_file_list->token, token) == 0) + { + free(setup_file_list->value); + setup_file_list->value = checked_malloc(strlen(value) + 1); + strcpy(setup_file_list->value, value); + } + else if (setup_file_list->next == NULL) + setup_file_list->next = newSetupFileList(token, value); + else + setTokenValue(setup_file_list->next, token, value); +} + +#ifdef DEBUG +static void printSetupFileList(struct SetupFileList *setup_file_list) +{ + if (!setup_file_list) + return; + + printf("token: '%s'\n", setup_file_list->token); + printf("value: '%s'\n", setup_file_list->value); + + printSetupFileList(setup_file_list->next); +} +#endif + +static struct SetupFileList *loadSetupFileList(char *filename) +{ + int line_len; + char line[MAX_LINE_LEN]; + char *token, *value, *line_ptr; + struct SetupFileList *setup_file_list = newSetupFileList("", ""); + struct SetupFileList *first_valid_list_entry; + FILE *file; - if (joystick_status==JOYSTICK_OFF) + if (!(file = fopen(filename, "r"))) + { + Error(ERR_WARN, "cannot open configuration file '%s'", filename); + return NULL; + } + + while(!feof(file)) + { + /* read next line of input file */ + if (!fgets(line, MAX_LINE_LEN, file)) + break; + + /* cut trailing comment or whitespace from input line */ + for (line_ptr = line; *line_ptr; line_ptr++) + { + if (*line_ptr == '#' || *line_ptr == '\n') + { + *line_ptr = '\0'; + break; + } + } + + /* cut trailing whitespaces from input line */ + for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--) + if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0') + *line_ptr = '\0'; + + /* ignore empty lines */ + if (*line == '\0') + continue; + + line_len = strlen(line); + + /* cut leading whitespaces from token */ + for (token = line; *token; token++) + if (*token != ' ' && *token != '\t') + break; + + /* find end of token */ + for (line_ptr = token; *line_ptr; line_ptr++) + { + if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') + { + *line_ptr = '\0'; + break; + } + } + + if (line_ptr < line + line_len) + value = line_ptr + 1; + else + value = "\0"; + + /* cut leading whitespaces from value */ + for (; *value; value++) + if (*value != ' ' && *value != '\t') + break; + + if (*token && *value) + setTokenValue(setup_file_list, token, value); + } + + fclose(file); + + first_valid_list_entry = setup_file_list->next; + + /* free empty list header */ + setup_file_list->next = NULL; + freeSetupFileList(setup_file_list); + + if (first_valid_list_entry == NULL) + Error(ERR_WARN, "configuration file '%s' is empty", filename); + + return first_valid_list_entry; +} + +static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, + char *identifier) +{ + if (!setup_file_list) return; - CheckJoystickData(); + if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0) + { + if (strcmp(setup_file_list->value, identifier) != 0) + { + Error(ERR_WARN, "configuration file has wrong version"); + return; + } + else + return; + } - if (!(file=fopen(JOYDAT_FILE,"w"))) + if (setup_file_list->next) + checkSetupFileListIdentifier(setup_file_list->next, identifier); + else { - fprintf(stderr,"%s: cannot save joystick calibration data!\n",progname); + Error(ERR_WARN, "configuration file has no version information"); + return; + } +} + +static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) +{ + ldi->name = getStringCopy("non-existing"); + ldi->levels = 0; + ldi->sort_priority = 999; /* default: least priority */ + ldi->readonly = TRUE; +} + +static void setSetupInfoToDefaults(struct SetupInfo *si) +{ + int i; + + si->player_name = getStringCopy(getLoginName()); + + si->sound = TRUE; + si->sound_loops = TRUE; + si->sound_music = TRUE; + si->sound_simple = TRUE; + si->toons = TRUE; + si->double_buffering = TRUE; + si->direct_draw = !si->double_buffering; + si->scroll_delay = TRUE; + si->soft_scrolling = TRUE; + si->fading = FALSE; + si->autorecord = TRUE; + si->quick_doors = FALSE; + + for (i=0; iinput[i].use_joystick = FALSE; + si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]); + si->input[i].joy.xleft = JOYSTICK_XLEFT; + si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE; + si->input[i].joy.xright = JOYSTICK_XRIGHT; + si->input[i].joy.yupper = JOYSTICK_YUPPER; + si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE; + si->input[i].joy.ylower = JOYSTICK_YLOWER; + si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0); + si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0); + si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KEY_UNDEFINDED); + si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED); + si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KEY_UNDEFINDED); + si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KEY_UNDEFINDED); + si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KEY_UNDEFINDED); + si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KEY_UNDEFINDED); + } +} + +static void setSetupInfo(int token_nr, char *token_value) +{ + int token_type = token_info[token_nr].type; + void *setup_value = token_info[token_nr].value; + + if (token_value == NULL) + return; + + /* set setup field to corresponding token value */ + switch (token_type) + { + case TYPE_BOOLEAN: + case TYPE_SWITCH: + *(boolean *)setup_value = get_string_boolean_value(token_value); + break; + + case TYPE_KEYSYM: + *(KeySym *)setup_value = getKeySymFromX11KeyName(token_value); + break; + + case TYPE_INTEGER: + *(int *)setup_value = get_string_integer_value(token_value); + break; + + case TYPE_STRING: + if (*(char **)setup_value != NULL) + free(*(char **)setup_value); + *(char **)setup_value = getStringCopy(token_value); + break; + + default: + break; + } +} + +static void decodeSetupFileList(struct SetupFileList *setup_file_list) +{ + int i, pnr; + + if (!setup_file_list) return; + + /* handle global setup values */ + si = setup; + for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++) + setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); + setup = si; + + /* handle player specific setup values */ + for (pnr=0; pnr highest_level_nr) + last_level_nr = highest_level_nr; } + + return last_level_nr; +} + +static int compareLevelDirInfoEntries(const void *object1, const void *object2) +{ + const struct LevelDirInfo *entry1 = object1; + const struct LevelDirInfo *entry2 = object2; + int compare_result; + + if (entry1->sort_priority != entry2->sort_priority) + compare_result = entry1->sort_priority - entry2->sort_priority; + else + { + char *name1 = getStringToLower(entry1->name); + char *name2 = getStringToLower(entry2->name); + + compare_result = strcmp(name1, name2); + + free(name1); + free(name2); + } + + return compare_result; +} + +static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry) +{ + DIR *dir; + struct stat file_status; + char *directory = NULL; + char *filename = NULL; + struct SetupFileList *setup_file_list = NULL; + struct dirent *dir_entry; + int i, current_entry = start_entry; + + if ((dir = opendir(level_directory)) == NULL) + { + Error(ERR_WARN, "cannot read level directory '%s'", level_directory); + return current_entry; + } + + while (current_entry < MAX_LEVDIR_ENTRIES) + { + if ((dir_entry = readdir(dir)) == NULL) /* last directory entry */ + break; + + /* skip entries for current and parent directory */ + if (strcmp(dir_entry->d_name, ".") == 0 || + strcmp(dir_entry->d_name, "..") == 0) + continue; + + /* find out if directory entry is itself a directory */ + directory = getPath2(level_directory, dir_entry->d_name); + if (stat(directory, &file_status) != 0 || /* cannot stat file */ + (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ + { + free(directory); + continue; + } + + filename = getPath2(directory, LEVELINFO_FILENAME); + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list) + { + checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); + setLevelDirInfoToDefaults(&leveldir[current_entry]); + + ldi = leveldir[current_entry]; + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); + leveldir[current_entry] = ldi; + + leveldir[current_entry].filename = getStringCopy(dir_entry->d_name); + leveldir[current_entry].user_defined = + (level_directory == options.level_directory ? FALSE : TRUE); + + freeSetupFileList(setup_file_list); + current_entry++; + } + else + Error(ERR_WARN, "ignoring level directory '%s'", directory); + + free(directory); + free(filename); + } + + if (current_entry == MAX_LEVDIR_ENTRIES) + Error(ERR_WARN, "using %d level directories -- ignoring the rest", + current_entry); + + closedir(dir); + + if (current_entry == start_entry) + Error(ERR_WARN, "cannot find any valid level series in directory '%s'", + level_directory); + + return current_entry; +} + +void LoadLevelInfo() +{ + InitUserLevelDirectory(getLoginName()); + + num_leveldirs = 0; + leveldir_nr = 0; + + num_leveldirs = LoadLevelInfoFromLevelDir(options.level_directory, + num_leveldirs); + num_leveldirs = LoadLevelInfoFromLevelDir(getUserLevelDir(""), + num_leveldirs); + + if (num_leveldirs == 0) + Error(ERR_EXIT, "cannot find any valid level series in any directory"); + + if (num_leveldirs > 1) + qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo), + compareLevelDirInfoEntries); +} + +static void SaveUserLevelInfo() +{ + char *filename; + FILE *file; + int i; + + filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + + if (!(file = fopen(filename, "w"))) + { + Error(ERR_WARN, "cannot write level info file '%s'", filename); + free(filename); + return; + } + + ldi.name = getLoginName(); + ldi.levels = 100; + ldi.sort_priority = 300; + ldi.readonly = FALSE; + + fprintf(file, "%s\n\n", + getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); + + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + fprintf(file, "%s\n", getSetupLine("", i)); + + fclose(file); + free(filename); + + chmod(filename, SETUP_PERMS); +} + +void LoadSetup() +{ + char *filename; + struct SetupFileList *setup_file_list = NULL; + + /* always start with reliable default values */ + setSetupInfoToDefaults(&setup); + + filename = getPath2(getSetupDir(), SETUP_FILENAME); + + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list) + { + checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE); + decodeSetupFileList(setup_file_list); + + setup.direct_draw = !setup.double_buffering; + + freeSetupFileList(setup_file_list); + + /* needed to work around problems with fixed length strings */ + if (strlen(setup.player_name) >= MAX_NAMELEN) + setup.player_name[MAX_NAMELEN - 1] = '\0'; + else if (strlen(setup.player_name) < MAX_NAMELEN - 1) + { + char *new_name = checked_malloc(MAX_NAMELEN); + + strcpy(new_name, setup.player_name); + free(setup.player_name); + setup.player_name = new_name; + } + } + else + Error(ERR_WARN, "using default setup values"); + + free(filename); +} + +static char *getSetupLine(char *prefix, int token_nr) +{ + int i; + static char entry[MAX_LINE_LEN]; + int token_type = token_info[token_nr].type; + void *setup_value = token_info[token_nr].value; + char *token_text = token_info[token_nr].text; + + /* start with the prefix, token and some spaces to format output line */ + sprintf(entry, "%s%s:", prefix, token_text); + for (i=strlen(entry); itoken, TOKEN_STR_FILE_IDENTIFIER) != 0) + fprintf(file, "%s\n", + getFormattedSetupEntry(list_entry->token, list_entry->value)); + + /* just to make things nicer :) */ + if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0) + fprintf(file, "\n"); + + list_entry = list_entry->next; + } + fclose(file); + free(filename); + + chmod(filename, SETUP_PERMS); +} + +#ifdef MSDOS +static boolean initErrorFile() +{ + char *filename; + FILE *error_file; - chmod(JOYDAT_FILE, JOYDAT_PERMS); + InitUserDataDirectory(); + + filename = getPath2(getUserDataDir(), ERROR_FILENAME); + error_file = fopen(filename, "w"); + free(filename); + + if (error_file == NULL) + return FALSE; + + fclose(error_file); + + return TRUE; +} + +FILE *openErrorFile() +{ + static boolean first_access = TRUE; + char *filename; + FILE *error_file; + + if (first_access) + { + if (!initErrorFile()) + return NULL; + + first_access = FALSE; + } + + filename = getPath2(getUserDataDir(), ERROR_FILENAME); + error_file = fopen(filename, "a"); + free(filename); + + return error_file; +} + +void dumpErrorFile() +{ + char *filename; + FILE *error_file; + + filename = getPath2(getUserDataDir(), ERROR_FILENAME); + error_file = fopen(filename, "r"); + free(filename); + + if (error_file != NULL) + { + while (!feof(error_file)) + fputc(fgetc(error_file), stderr); + + fclose(error_file); + } } +#endif diff --git a/src/files.h b/src/files.h index aee5e421..d95cce18 100644 --- a/src/files.h +++ b/src/files.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * files.h * ***********************************************************/ @@ -17,49 +16,26 @@ #include "main.h" -/* names file mode: level or setup */ -#define PLAYER_LEVEL 0 -#define PLAYER_SETUP 1 - -/* Setup-Bits */ -#define SETUP_TOONS (1<<0) -#define SETUP_SOUND (1<<1) -#define SETUP_SOUND_LOOPS (1<<2) -#define SETUP_SOUND_MUSIC (1<<3) -#define SETUP_DIRECT_DRAW (1<<4) -#define SETUP_FADING (1<<5) -#define SETUP_RECORD_EACH_GAME (1<<6) -#define SETUP_2ND_JOYSTICK (1<<7) -#define SETUP_QUICK_DOORS (1<<8) - -#define DEFAULT_SETUP (SETUP_TOONS | \ - SETUP_SOUND | \ - SETUP_SOUND_LOOPS | \ - SETUP_SOUND_MUSIC) +void LoadLevel(int); +void SaveLevel(int); -/* Setup-Voreinstellungen */ -#define SETUP_TOONS_ON(x) (((x) & SETUP_TOONS) != 0) -#define SETUP_SOUND_ON(x) (((x) & SETUP_SOUND) != 0) -#define SETUP_SOUND_LOOPS_ON(x) (((x) & SETUP_SOUND_LOOPS) != 0) -#define SETUP_SOUND_MUSIC_ON(x) (((x) & SETUP_SOUND_MUSIC) != 0) -#define SETUP_DIRECT_DRAW_ON(x) (((x) & SETUP_DIRECT_DRAW) != 0) -#define SETUP_FADING_ON(x) (((x) & SETUP_FADING) != 0) -#define SETUP_RECORD_EACH_GAME_ON(x) (((x) & SETUP_RECORD_EACH_GAME) != 0) -#define SETUP_2ND_JOYSTICK_ON(x) (((x) & SETUP_2ND_JOYSTICK) != 0) -#define SETUP_QUICK_DOORS_ON(x) (((x) & SETUP_QUICK_DOORS) != 0) +void LoadTape(int); +void SaveTape(int); -BOOL CreateNewScoreFile(void); -BOOL CreateNewNamesFile(int); -BOOL LoadLevelInfo(void); -void LoadLevel(int); -void LoadLevelTape(int); void LoadScore(int); -void LoadPlayerInfo(int); -void SaveLevel(int); -void SaveLevelTape(int); void SaveScore(int); -void SavePlayerInfo(int); -void LoadJoystickData(void); -void SaveJoystickData(void); +int getLastPlayedLevelOfLevelSeries(char *); + +void LoadLevelInfo(void); +void LoadSetup(void); +void SaveSetup(void); +void LoadLevelSetup(void); +void SaveLevelSetup(void); + +#ifdef MSDOS +FILE *openErrorFile(); +void dumpErrorFile(); #endif + +#endif /* FILES_H */ diff --git a/src/game.c b/src/game.c index 8d88167b..26cc84cc 100644 --- a/src/game.c +++ b/src/game.c @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * game.c * ***********************************************************/ @@ -20,90 +19,268 @@ #include "init.h" #include "buttons.h" #include "files.h" +#include "tape.h" +#include "joystick.h" +#include "network.h" + +/* for DigField() */ +#define DF_NO_PUSH 0 +#define DF_DIG 1 +#define DF_SNAP 2 + +/* for MoveFigure() */ +#define MF_NO_ACTION 0 +#define MF_MOVING 1 +#define MF_ACTION 2 + +/* for ScrollFigure() */ +#define SCROLL_INIT 0 +#define SCROLL_GO_ON 1 + +/* for Explode() */ +#define EX_PHASE_START 0 +#define EX_NORMAL 0 +#define EX_CENTER 1 +#define EX_BORDER 2 + +/* special positions in the game control window (relative to control window) */ +#define XX_LEVEL 37 +#define YY_LEVEL 20 +#define XX_EMERALDS 29 +#define YY_EMERALDS 54 +#define XX_DYNAMITE 29 +#define YY_DYNAMITE 89 +#define XX_KEYS 18 +#define YY_KEYS 123 +#define XX_SCORE 15 +#define YY_SCORE 159 +#define XX_TIME 29 +#define YY_TIME 194 + +/* special positions in the game control window (relative to main window) */ +#define DX_LEVEL (DX + XX_LEVEL) +#define DY_LEVEL (DY + YY_LEVEL) +#define DX_EMERALDS (DX + XX_EMERALDS) +#define DY_EMERALDS (DY + YY_EMERALDS) +#define DX_DYNAMITE (DX + XX_DYNAMITE) +#define DY_DYNAMITE (DY + YY_DYNAMITE) +#define DX_KEYS (DX + XX_KEYS) +#define DY_KEYS (DY + YY_KEYS) +#define DX_SCORE (DX + XX_SCORE) +#define DY_SCORE (DY + YY_SCORE) +#define DX_TIME (DX + XX_TIME) +#define DY_TIME (DY + YY_TIME) + +#define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \ + (s)==SND_NJAM || (s)==SND_MIEP) +#define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \ + (s)==SND_NETWORK || (s)==SND_CZARDASZ || \ + (s)==SND_TYGER || (s)==SND_VOYAGER || \ + (s)==SND_TWILIGHT) + +/* score for elements */ +#define SC_EDELSTEIN 0 +#define SC_DIAMANT 1 +#define SC_KAEFER 2 +#define SC_FLIEGER 3 +#define SC_MAMPFER 4 +#define SC_ROBOT 5 +#define SC_PACMAN 6 +#define SC_KOKOSNUSS 7 +#define SC_DYNAMIT 8 +#define SC_SCHLUESSEL 9 +#define SC_ZEITBONUS 10 + +/* values for game_emulation */ +#define EMU_NONE 0 +#define EMU_BOULDERDASH 1 +#define EMU_SOKOBAN 2 + +/* to control special behaviour of certain game elements */ +int game_emulation = EMU_NONE; void GetPlayerConfig() { - int old_joystick_nr = joystick_nr; + if (sound_status == SOUND_OFF) + setup.sound = FALSE; - if (sound_status==SOUND_OFF) - player.setup &= ~SETUP_SOUND; if (!sound_loops_allowed) { - player.setup &= ~SETUP_SOUND_LOOPS; - player.setup &= ~SETUP_SOUND_MUSIC; + setup.sound_loops = FALSE; + setup.sound_music = FALSE; } - sound_on = SETUP_SOUND_ON(player.setup); - sound_loops_on = SETUP_SOUND_LOOPS_ON(player.setup); - sound_music_on = SETUP_SOUND_MUSIC_ON(player.setup); - toons_on = SETUP_TOONS_ON(player.setup); - direct_draw_on = SETUP_DIRECT_DRAW_ON(player.setup); - fading_on = SETUP_FADING_ON(player.setup); - autorecord_on = SETUP_RECORD_EACH_GAME_ON(player.setup); - joystick_nr = SETUP_2ND_JOYSTICK_ON(player.setup); - quick_doors = SETUP_QUICK_DOORS_ON(player.setup); + setup.sound_simple = setup.sound; - if (joystick_nr != old_joystick_nr) - { - if (joystick_device) - close(joystick_device); - InitJoystick(); - } + InitJoysticks(); } void InitGame() { - int i,x,y; + int i, j, x, y; + boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ + boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ + + /* don't play tapes over network */ + network_playing = (options.network && !tape.playing); + + for (i=0; iindex_nr = i; + player->element_nr = EL_SPIELER1 + i; + + player->present = FALSE; + player->active = FALSE; + + player->action = 0; + player->effective_action = 0; + + player->score = 0; + player->gems_still_needed = level.edelsteine; + player->sokobanfields_still_needed = 0; + player->lights_still_needed = 0; + player->friends_still_needed = 0; + + for (j=0; j<4; j++) + player->key[j] = FALSE; + + player->dynamite = 0; + player->dynabomb_count = 0; + player->dynabomb_size = 0; + player->dynabombs_left = 0; + player->dynabomb_xl = FALSE; + + player->MovDir = MV_NO_MOVING; + player->MovPos = 0; + player->Pushing = FALSE; + player->GfxPos = 0; + player->Frame = 0; + + player->actual_frame_counter = 0; + + player->frame_reset_delay = 0; + + player->push_delay = 0; + player->push_delay_value = 5; + + player->move_delay = 0; + player->last_move_dir = MV_NO_MOVING; + + player->snapped = FALSE; + + player->gone = FALSE; + + player->last_jx = player->last_jy = 0; + player->jx = player->jy = 0; + + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); + SnapField(player, 0, 0); + + player->LevelSolved = FALSE; + player->GameOver = FALSE; + } + + network_player_action_received = FALSE; + +#ifndef MSDOS + /* initial null action */ + if (network_playing) + SendToServer_MovePlayer(MV_NO_MOVING); +#endif + + ZX = ZY = -1; - Dynamite = Score = 0; - Gems = level.edelsteine; - Key[0] = Key[1] = Key[2] = Key[3] = FALSE; MampferNr = 0; + FrameCounter = 0; + TimeFrames = 0; TimeLeft = level.time; - CheckMoving = TRUE; - CheckExploding = FALSE; - LevelSolved = GameOver = SiebAktiv = FALSE; - JX = JY = 0; - ZX = ZY = -1; - if (tape.recording) - TapeStartRecording(); - else if (tape.playing) - TapeStartPlaying(); + ScreenMovDir = MV_NO_MOVING; + ScreenMovPos = 0; + ScreenGfxPos = 0; - DigField(0,0,DF_NO_PUSH); - SnapField(0,0); + AllPlayersGone = SiebAktiv = FALSE; - for(i=0;ijx, jy = player->jy; + + player->present = TRUE; + + /* + if (!network_playing || player->connected) + */ + + if (!options.network || player->connected) + { + player->active = TRUE; + + /* remove potentially duplicate players */ + if (StorePlayer[jx][jy] == Feld[x][y]) + StorePlayer[jx][jy] = 0; + + StorePlayer[x][y] = Feld[x][y]; + + if (options.verbose) + { + printf("Player %d activated.\n", player->element_nr); + printf("[Local player is %d and currently %s.]\n", + local_player->element_nr, + local_player->active ? "active" : "not active"); + } + } + Feld[x][y] = EL_LEERRAUM; + player->jx = player->last_jx = x; + player->jy = player->last_jy = y; + break; + } case EL_BADEWANNE: - if (x0 && Feld[x-1][y]==EL_SALZSAEURE) + else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE) Feld[x][y] = EL_BADEWANNE2; - else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1) + else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1) Feld[x][y] = EL_BADEWANNE3; - else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE) + else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE) Feld[x][y] = EL_BADEWANNE4; - else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2) + else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2) Feld[x][y] = EL_BADEWANNE5; break; case EL_KAEFER_R: @@ -116,79 +293,216 @@ void InitGame() case EL_FLIEGER_L: case EL_FLIEGER_U: case EL_FLIEGER: + case EL_BUTTERFLY_R: + case EL_BUTTERFLY_O: + case EL_BUTTERFLY_L: + case EL_BUTTERFLY_U: + case EL_BUTTERFLY: + case EL_FIREFLY_R: + case EL_FIREFLY_O: + case EL_FIREFLY_L: + case EL_FIREFLY_U: + case EL_FIREFLY: case EL_PACMAN_R: case EL_PACMAN_O: case EL_PACMAN_L: case EL_PACMAN_U: case EL_MAMPFER: - case EL_ZOMBIE: + case EL_MAMPFER2: + case EL_ROBOT: case EL_PACMAN: - InitMovDir(x,y); + InitMovDir(x, y); break; case EL_AMOEBE_VOLL: - InitAmoebaNr(x,y); + case EL_AMOEBE_BD: + InitAmoebaNr(x, y); break; case EL_TROPFEN: - if (y==lev_fieldy-1) + if (y == lev_fieldy - 1) { Feld[x][y] = EL_AMOEBING; Store[x][y] = EL_AMOEBE_NASS; } break; + case EL_DYNAMIT: + MovDelay[x][y] = 96; + break; + case EL_BIRNE_AUS: + local_player->lights_still_needed++; + break; + case EL_SOKOBAN_FELD_LEER: + local_player->sokobanfields_still_needed++; + break; + case EL_MAULWURF: + case EL_PINGUIN: + local_player->friends_still_needed++; + break; + case EL_SCHWEIN: + case EL_DRACHE: + MovDir[x][y] = 1 << RND(4); + break; default: break; } } + /* check if any connected player was not found in playfield */ + for (i=0; iconnected && !player->present) + { + for (j=0; jjx, jy = some_player->jy; + + /* assign first free player found that is present in the playfield */ + if (some_player->present && !some_player->connected) + { + player->present = TRUE; + player->active = TRUE; + some_player->present = FALSE; + + StorePlayer[jx][jy] = player->element_nr; + player->jx = player->last_jx = jx; + player->jy = player->last_jy = jy; + + break; + } + } + } + } + + if (tape.playing) + { + /* when playing a tape, eliminate all players who do not participate */ + + for (i=0; ijx, jy = player->jy; + + player->active = FALSE; + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_LEERRAUM; + } + } + } + else if (!options.network && !setup.team_mode) /* && !tape.playing */ + { + /* when in single player mode, eliminate all but the first active player */ + + for (i=0; ijx, jy = player->jy; + + player->active = FALSE; + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_LEERRAUM; + } + } + } + } + } + + /* when recording the game, store which players take part in the game */ + if (tape.recording) + { + for (i=0; ipresent, + player->connected, + player->active); + if (local_player == player) + printf("Player %d is local player.\n", i+1); + } + } + + game_emulation = (emulate_bd ? EMU_BOULDERDASH : + emulate_sb ? EMU_SOKOBAN : EMU_NONE); + scroll_x = scroll_y = -1; - if (JX>=MIDPOSX-1) - scroll_x = - (JX<=lev_fieldx-MIDPOSX ? JX-MIDPOSX : lev_fieldx-SCR_FIELDX+1); - if (JY>=MIDPOSY-1) - scroll_y = - (JY<=lev_fieldy-MIDPOSY ? JY-MIDPOSY : lev_fieldy-SCR_FIELDY+1); + if (local_player->jx >= MIDPOSX-1) + scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ? + local_player->jx - MIDPOSX : + lev_fieldx - SCR_FIELDX + 1); + if (local_player->jy >= MIDPOSY-1) + scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ? + local_player->jy - MIDPOSY : + lev_fieldy - SCR_FIELDY + 1); + + CloseDoor(DOOR_CLOSE_1); DrawLevel(); - DrawLevelElement(JX,JY,EL_SPIELFIGUR); + DrawAllPlayers(); FadeToFront(); - XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1); - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL, - int2str(level_nr,2),FS_SMALL,FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS, - int2str(Gems,3),FS_SMALL,FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE, - int2str(Dynamite,3),FS_SMALL,FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE, - int2str(Score,5),FS_SMALL,FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME, - int2str(TimeLeft,3),FS_SMALL,FC_YELLOW); + XCopyArea(display, pix[PIX_DOOR], pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + XX_LEVEL, DOOR_GFX_PAGEY1 + YY_LEVEL, + int2str(level_nr, 2), FS_SMALL, FC_YELLOW); + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + XX_EMERALDS, DOOR_GFX_PAGEY1 + YY_EMERALDS, + int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW); + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + XX_DYNAMITE, DOOR_GFX_PAGEY1 + YY_DYNAMITE, + int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + XX_SCORE, DOOR_GFX_PAGEY1 + YY_SCORE, + int2str(local_player->score, 5), FS_SMALL, FC_YELLOW); + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + XX_TIME, DOOR_GFX_PAGEY1 + YY_TIME, + int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); DrawGameButton(BUTTON_GAME_STOP); DrawGameButton(BUTTON_GAME_PAUSE); DrawGameButton(BUTTON_GAME_PLAY); - DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on)); - DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on)); - DrawSoundDisplay(BUTTON_SOUND_SOUND | (BUTTON_ON * sound_on)); - XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc, - DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS, - GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE, - DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS, - DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS); + DrawSoundDisplay(BUTTON_SOUND_MUSIC | (setup.sound_music ? BUTTON_ON : 0)); + DrawSoundDisplay(BUTTON_SOUND_LOOPS | (setup.sound_loops ? BUTTON_ON : 0)); + DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (setup.sound_simple ? BUTTON_ON : 0)); + XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc, + DX + GAME_CONTROL_XPOS, DY + GAME_CONTROL_YPOS, + GAME_CONTROL_XSIZE, 2 * GAME_CONTROL_YSIZE, + DOOR_GFX_PAGEX1 + GAME_CONTROL_XPOS, + DOOR_GFX_PAGEY1 + GAME_CONTROL_YPOS); OpenDoor(DOOR_OPEN_1); - if (sound_music_on) + if (setup.sound_music) PlaySoundLoop(background_loop[level_nr % num_bg_loops]); XAutoRepeatOff(display); + + if (options.verbose) + { + for (i=0; i<4; i++) + printf("Spieler %d %saktiv.\n", + i+1, (stored_player[i].active ? "" : "nicht ")); + } } void InitMovDir(int x, int y) @@ -196,15 +510,15 @@ void InitMovDir(int x, int y) int i, element = Feld[x][y]; static int xy[4][2] = { - 0,+1, - +1,0, - 0,-1, - -1,0 + { 0, +1 }, + { +1, 0 }, + { 0, -1 }, + { -1, 0 } }; static int direction[2][4] = { - MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN, - MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP + { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN }, + { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP } }; switch(element) @@ -214,42 +528,57 @@ void InitMovDir(int x, int y) case EL_KAEFER_L: case EL_KAEFER_U: Feld[x][y] = EL_KAEFER; - MovDir[x][y] = direction[0][element-EL_KAEFER_R]; + MovDir[x][y] = direction[0][element - EL_KAEFER_R]; break; case EL_FLIEGER_R: case EL_FLIEGER_O: case EL_FLIEGER_L: case EL_FLIEGER_U: Feld[x][y] = EL_FLIEGER; - MovDir[x][y] = direction[0][element-EL_FLIEGER_R]; + MovDir[x][y] = direction[0][element - EL_FLIEGER_R]; + break; + case EL_BUTTERFLY_R: + case EL_BUTTERFLY_O: + case EL_BUTTERFLY_L: + case EL_BUTTERFLY_U: + Feld[x][y] = EL_BUTTERFLY; + MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R]; + break; + case EL_FIREFLY_R: + case EL_FIREFLY_O: + case EL_FIREFLY_L: + case EL_FIREFLY_U: + Feld[x][y] = EL_FIREFLY; + MovDir[x][y] = direction[0][element - EL_FIREFLY_R]; break; case EL_PACMAN_R: case EL_PACMAN_O: case EL_PACMAN_L: case EL_PACMAN_U: Feld[x][y] = EL_PACMAN; - MovDir[x][y] = direction[0][element-EL_PACMAN_R]; + MovDir[x][y] = direction[0][element - EL_PACMAN_R]; break; default: - MovDir[x][y] = 1<MovPos) + return; + + local_player->LevelSolved = FALSE; - if (TimeLeft>0) + if (TimeLeft) { - for(;TimeLeft>=0;TimeLeft--) + if (setup.sound_loops) + PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP); + + while(TimeLeft > 0) { - if (!sound_loops_on) - PlaySoundStereo(SND_SIRR,PSND_MAX_RIGHT); + if (!setup.sound_loops) + PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT); if (TimeLeft && !(TimeLeft % 10)) RaiseScore(level.score[SC_ZEITBONUS]); - DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW); + if (TimeLeft > 100 && !(TimeLeft % 10)) + TimeLeft -= 10; + else + TimeLeft--; + DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); BackToFront(); - Delay(10000); + Delay(10); } + + if (setup.sound_loops) + StopSound(SND_SIRR); } - if (sound_loops_on) - StopSound(SND_SIRR); FadeSounds(); + /* Hero disappears */ + DrawLevelField(ExitX, ExitY); + BackToFront(); + if (tape.playing) return; CloseDoor(DOOR_CLOSE_1); - if (level_nr==player.handicap && - level_nr=0) + if ((hi_pos = NewHiScore()) >= 0) { game_status = HALLOFFAME; DrawHallOfFame(hi_pos); @@ -334,82 +676,85 @@ void GameWon() level_nr++; DrawMainMenu(); } + BackToFront(); } -BOOL NewHiScore() +boolean NewHiScore() { - int k,l; + int k, l; int position = -1; LoadScore(level_nr); - if (!strcmp(player.alias_name,EMPTY_ALIAS) || - Scorescore < highscore[MAX_SCORE_ENTRIES - 1].Score) + return -1; - for(k=0;khighscore[k].Score) /* Spieler kommt in Highscore-Liste */ + if (local_player->score > highscore[k].Score) { - if (kk;l--) + for (l=m; l>k; l--) { - strcpy(highscore[l].Name,highscore[l-1].Name); - highscore[l].Score = highscore[l-1].Score; + strcpy(highscore[l].Name, highscore[l - 1].Name); + highscore[l].Score = highscore[l - 1].Score; } } #ifdef ONE_PER_NAME put_into_list: #endif - sprintf(highscore[k].Name,player.alias_name); - highscore[k].Score = Score; + strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1); + highscore[k].Name[MAX_NAMELEN - 1] = '\0'; + highscore[k].Score = local_player->score; position = k; break; } #ifdef ONE_PER_NAME - else if (!strcmp(player.alias_name,highscore[k].Name)) - break; /* Spieler schon mit besserer Punktzahl in der Liste */ + else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1)) + break; /* player already there with a higher score */ #endif } - if (position>=0) + if (position >= 0) SaveScore(level_nr); - return(position); + return position; } void InitMovingField(int x, int y, int direction) { - int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0); - int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0); + int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); + int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); - CheckMoving = TRUE; MovDir[x][y] = direction; MovDir[newx][newy] = direction; - if (Feld[newx][newy]==EL_LEERRAUM) + if (Feld[newx][newy] == EL_LEERRAUM) Feld[newx][newy] = EL_BLOCKED; } void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) { int direction = MovDir[x][y]; - int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0); - int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0); + int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); + int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); *goes_to_x = newx; *goes_to_y = newy; @@ -420,13 +765,13 @@ void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y) int oldx = x, oldy = y; int direction = MovDir[x][y]; - if (direction==MV_LEFT) + if (direction == MV_LEFT) oldx++; - else if (direction==MV_RIGHT) + else if (direction == MV_RIGHT) oldx--; - else if (direction==MV_UP) + else if (direction == MV_UP) oldy++; - else if (direction==MV_DOWN) + else if (direction == MV_DOWN) oldy--; *comes_from_x = oldx; @@ -437,140 +782,213 @@ int MovingOrBlocked2Element(int x, int y) { int element = Feld[x][y]; - if (element==EL_BLOCKED) + if (element == EL_BLOCKED) { - int oldx,oldy; + int oldx, oldy; - Blocked2Moving(x,y,&oldx,&oldy); - return(Feld[oldx][oldy]); + Blocked2Moving(x, y, &oldx, &oldy); + return Feld[oldx][oldy]; } else - return(element); + return element; +} + +static void RemoveField(int x, int y) +{ + Feld[x][y] = EL_LEERRAUM; + MovPos[x][y] = 0; + MovDir[x][y] = 0; + MovDelay[x][y] = 0; } void RemoveMovingField(int x, int y) { - int oldx=x,oldy=y, newx=x,newy=y; + int oldx = x, oldy = y, newx = x, newy = y; - if (Feld[x][y]!=EL_BLOCKED && !IS_MOVING(x,y)) + if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y)) return; - if (IS_MOVING(x,y)) + if (IS_MOVING(x, y)) { - Moving2Blocked(x,y,&newx,&newy); - if (Feld[newx][newy]!=EL_BLOCKED) + Moving2Blocked(x, y, &newx, &newy); + if (Feld[newx][newy] != EL_BLOCKED) return; } - else if (Feld[x][y]==EL_BLOCKED) + else if (Feld[x][y] == EL_BLOCKED) { - Blocked2Moving(x,y,&oldx,&oldy); - if (!IS_MOVING(oldx,oldy)) + Blocked2Moving(x, y, &oldx, &oldy); + if (!IS_MOVING(oldx, oldy)) return; } - Feld[oldx][oldy] = EL_LEERRAUM; + if (Feld[x][y] == EL_BLOCKED && + (Store[oldx][oldy] == EL_MORAST_LEER || + Store[oldx][oldy] == EL_SIEB_LEER || + Store[oldx][oldy] == EL_SIEB2_LEER || + Store[oldx][oldy] == EL_AMOEBE_NASS)) + { + Feld[oldx][oldy] = Store[oldx][oldy]; + Store[oldx][oldy] = Store2[oldx][oldy] = 0; + } + else + Feld[oldx][oldy] = EL_LEERRAUM; + Feld[newx][newy] = EL_LEERRAUM; MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0; MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0; - DrawLevelField(oldx,oldy); - DrawLevelField(newx,newy); + + DrawLevelField(oldx, oldy); + DrawLevelField(newx, newy); } void DrawDynamite(int x, int y) { - int phase = (48-MovDelay[x][y])/6; + int sx = SCREENX(x), sy = SCREENY(y); + int graphic = el2gfx(Feld[x][y]); + int phase; - if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) + if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y)) return; - if (phase>6) - phase = 6; - if (Store[x][y]) + DrawGraphic(sx, sy, el2gfx(Store[x][y])); + + if (Feld[x][y] == EL_DYNAMIT) { - DrawGraphic(SCROLLX(x),SCROLLY(y),el2gfx(Store[x][y])); - if (PLAYER(x,y)) - DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR); + if ((phase = (96 - MovDelay[x][y]) / 12) > 6) + phase = 6; + } + else + { + if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3) + phase = 7 - phase; } - else if (PLAYER(x,y)) - DrawGraphic(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR); - if (Store[x][y] || PLAYER(x,y)) - DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase); + if (Store[x][y]) + DrawGraphicThruMask(sx, sy, graphic + phase); else - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase); + DrawGraphic(sx, sy, graphic + phase); } void CheckDynamite(int x, int y) { - CheckExploding=TRUE; - - if (MovDelay[x][y]) /* neues Dynamit / in Wartezustand */ + if (MovDelay[x][y]) /* dynamite is still waiting to explode */ { MovDelay[x][y]--; if (MovDelay[x][y]) { - if (!(MovDelay[x][y] % 6)) - { - DrawDynamite(x,y); - PlaySoundLevel(x,y,SND_ZISCH); - } + if (!(MovDelay[x][y] % 12)) + PlaySoundLevel(x, y, SND_ZISCH); + + if (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12)) + DrawDynamite(x, y); + else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6)) + DrawDynamite(x, y); return; } } StopSound(SND_ZISCH); - Bang(x,y); + Bang(x, y); } -void Explode(int ex, int ey, int phase) +void Explode(int ex, int ey, int phase, int mode) { - int x,y; - int num_phase = 9, delay = 1; - int last_phase = num_phase*delay; - int half_phase = (num_phase/2)*delay; + int x, y; + int num_phase = 9, delay = 2; + int last_phase = num_phase * delay; + int half_phase = (num_phase / 2) * delay; - if (phase==0) /* Feld 'Store' initialisieren */ + if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ { int center_element = Feld[ex][ey]; - if (center_element==EL_BLOCKED) - center_element = MovingOrBlocked2Element(ex,ey); + if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) + { + center_element = MovingOrBlocked2Element(ex, ey); + RemoveMovingField(ex, ey); + } - for(y=ey-1;ydynabomb_size; j++) + { + int x = ex+j*xy[i%4][0]; + int y = ey+j*xy[i%4][1]; + int element; - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_EXPLOSION+(phase/delay-1)); + if (!IN_LEV_FIELD(x, y) || IS_MASSIV(Feld[x][y])) + break; + + element = Feld[x][y]; + Explode(x, y, EX_PHASE_START, EX_BORDER); + + if (element != EL_LEERRAUM && + element != EL_ERDREICH && + element != EL_EXPLODING && + !player->dynabomb_xl) + break; + } } - CheckExploding=TRUE; + player->dynabombs_left++; } void Bang(int x, int y) { int element = Feld[x][y]; - CheckExploding=TRUE; - PlaySoundLevel(x,y,SND_ROAAAR); + PlaySoundLevel(x, y, SND_ROAAAR); + + if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */ + element = EL_LEERRAUM; switch(element) { case EL_KAEFER: - RaiseScore(level.score[SC_KAEFER]); - break; case EL_FLIEGER: - RaiseScore(level.score[SC_FLIEGER]); - break; + case EL_BUTTERFLY: + case EL_FIREFLY: case EL_MAMPFER: - RaiseScore(level.score[SC_MAMPFER]); + case EL_MAMPFER2: + case EL_ROBOT: + case EL_PACMAN: + RaiseScoreElement(element); + Explode(x, y, EX_PHASE_START, EX_NORMAL); break; - case EL_ZOMBIE: - RaiseScore(level.score[SC_ZOMBIE]); + case EL_DYNABOMB: + case EL_DYNABOMB_NR: + case EL_DYNABOMB_SZ: + case EL_DYNABOMB_XL: + DynaExplode(x, y); break; - case EL_PACMAN: - RaiseScore(level.score[SC_PACMAN]); + case EL_MAULWURF: + case EL_PINGUIN: + case EL_BIRNE_AUS: + case EL_BIRNE_EIN: + Explode(x, y, EX_PHASE_START, EX_CENTER); break; default: + Explode(x, y, EX_PHASE_START, EX_NORMAL); break; } - - Explode(x,y,0); } void Blurb(int x, int y) { int element = Feld[x][y]; - if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */ + if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT) /* start */ { - PlaySoundLevel(x,y,SND_BLURB); - if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) && - (!IN_LEV_FIELD(x-1,y-1) || - !CAN_FALL(MovingOrBlocked2Element(x-1,y-1)))) + PlaySoundLevel(x, y, SND_BLURB); + if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) && + (!IN_LEV_FIELD(x-1, y-1) || + !CAN_FALL(MovingOrBlocked2Element(x-1, y-1)))) { Feld[x-1][y] = EL_BLURB_LEFT; } - if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) && - (!IN_LEV_FIELD(x+1,y-1) || - !CAN_FALL(MovingOrBlocked2Element(x+1,y-1)))) + if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) && + (!IN_LEV_FIELD(x+1, y-1) || + !CAN_FALL(MovingOrBlocked2Element(x+1, y-1)))) { Feld[x+1][y] = EL_BLURB_RIGHT; } } - else /* Blubbern */ + else /* go on */ { int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT); - CheckExploding=TRUE; - - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 5; + if (!MovDelay[x][y]) /* initialize animation counter */ + MovDelay[x][y] = 9; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* continue animation */ { MovDelay[x][y]--; - if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),graphic+4-MovDelay[x][y]); + if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2); if (!MovDelay[x][y]) { Feld[x][y] = EL_LEERRAUM; - DrawLevelField(x,y); + DrawLevelField(x, y); } } } @@ -710,35 +1171,41 @@ void Blurb(int x, int y) void Impact(int x, int y) { - BOOL lastline = (y==lev_fieldy-1); - BOOL object_hit = FALSE; + boolean lastline = (y == lev_fieldy-1); + boolean object_hit = FALSE; int element = Feld[x][y]; + int smashed = 0; + + if (!lastline) /* check if element below was hit */ + { + if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING) + return; - /* Element darunter berührt? */ - if (!lastline) - object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) || + object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) || MovDir[x][y+1]!=MV_DOWN || MovPos[x][y+1]<=TILEY/2)); + if (object_hit) + smashed = MovingOrBlocked2Element(x, y+1); + } - /* Auftreffendes Element fällt in Salzsäure */ - if (!lastline && Feld[x][y+1]==EL_SALZSAEURE) + if (!lastline && smashed == EL_SALZSAEURE) /* element falls into acid */ { - Blurb(x,y); + Blurb(x, y); return; } - /* Auftreffendes Element ist Bombe */ - if (element==EL_BOMBE && (lastline || object_hit)) + if (element == EL_BOMBE && (lastline || object_hit)) /* element is bomb */ { - Bang(x,y); + Bang(x, y); return; } - /* Auftreffendes Element ist Säuretropfen */ - if (element==EL_TROPFEN && (lastline || object_hit)) + if (element == EL_TROPFEN && (lastline || object_hit)) /* acid drop */ { - if (object_hit && PLAYER(x,y+1)) - KillHero(); + if (object_hit && IS_PLAYER(x, y+1)) + KillHero(PLAYERINFO(x, y+1)); + else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN)) + Bang(x, y+1); else { Feld[x][y] = EL_AMOEBING; @@ -747,52 +1214,71 @@ void Impact(int x, int y) return; } - /* Welches Element kriegt was auf die Rübe? */ - if (!lastline && object_hit) + if (!lastline && object_hit) /* check which object was hit */ { - int smashed = Feld[x][y+1]; + if (CAN_CHANGE(element) && + (smashed == EL_SIEB_LEER || smashed == EL_SIEB2_LEER) && !SiebAktiv) + SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND; - if (PLAYER(x,y+1)) + if (IS_PLAYER(x, y+1)) + { + KillHero(PLAYERINFO(x, y+1)); + return; + } + else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN) { - KillHero(); + Bang(x, y+1); return; } - else if (element==EL_FELSBROCKEN) + else if (element == EL_EDELSTEIN_BD) + { + if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed)) + { + Bang(x, y+1); + return; + } + } + else if (element == EL_FELSBROCKEN) { - if (IS_ENEMY(MovingOrBlocked2Element(x,y+1))) + if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SONDE || + smashed == EL_SCHWEIN || smashed == EL_DRACHE) { - Bang(x,y+1); + Bang(x, y+1); return; } - else if (!IS_MOVING(x,y+1)) + else if (!IS_MOVING(x, y+1)) { - if (smashed==EL_BOMBE) + if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN) { - Bang(x,y+1); + Bang(x, y+1); return; } - else if (smashed==EL_KOKOSNUSS) + else if (smashed == EL_KOKOSNUSS) { Feld[x][y+1] = EL_CRACKINGNUT; - PlaySoundLevel(x,y,SND_KNACK); - RaiseScore(level.score[SC_KOKOSNUSS]); + PlaySoundLevel(x, y, SND_KNACK); + RaiseScoreElement(EL_KOKOSNUSS); return; } - else if (smashed==EL_DIAMANT) + else if (smashed == EL_DIAMANT) { Feld[x][y+1] = EL_LEERRAUM; - PlaySoundLevel(x,y,SND_QUIRK); + PlaySoundLevel(x, y, SND_QUIRK); return; } } } } - /* Kein Geräusch beim Durchqueren des Siebes */ - if (!lastline && Feld[x][y+1]==EL_SIEB_LEER) + /* play sound of magic wall / mill */ + if (!lastline && + (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER)) + { + PlaySoundLevel(x, y, SND_QUIRK); return; + } - /* Geräusch beim Auftreffen */ + /* play sound of object that hits the ground */ if (lastline || object_hit) { int sound; @@ -800,6 +1286,10 @@ void Impact(int x, int y) switch(element) { case EL_EDELSTEIN: + case EL_EDELSTEIN_BD: + case EL_EDELSTEIN_GELB: + case EL_EDELSTEIN_ROT: + case EL_EDELSTEIN_LILA: case EL_DIAMANT: sound = SND_PLING; break; @@ -826,169 +1316,405 @@ void Impact(int x, int y) } if (sound>=0) - PlaySoundLevel(x,y,sound); + PlaySoundLevel(x, y, sound); } } void TurnRound(int x, int y) { + static struct + { + int x, y; + } move_xy[] = + { + { 0, 0 }, + {-1, 0 }, + {+1, 0 }, + { 0, 0 }, + { 0, -1 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, +1 } + }; + static struct + { + int left, right, back; + } turn[] = + { + { 0, 0, 0 }, + { MV_DOWN, MV_UP, MV_RIGHT }, + { MV_UP, MV_DOWN, MV_LEFT }, + { 0, 0, 0 }, + { MV_LEFT, MV_RIGHT, MV_DOWN }, + { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, + { MV_RIGHT, MV_LEFT, MV_UP } + }; + int element = Feld[x][y]; - int direction = MovDir[x][y]; + int old_move_dir = MovDir[x][y]; + int left_dir = turn[old_move_dir].left; + int right_dir = turn[old_move_dir].right; + int back_dir = turn[old_move_dir].back; - if (element==EL_KAEFER) + int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y; + int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y; + int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y; + int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y; + + int left_x = x+left_dx, left_y = y+left_dy; + int right_x = x+right_dx, right_y = y+right_dy; + int move_x = x+move_dx, move_y = y+move_dy; + + if (element == EL_KAEFER || element == EL_BUTTERFLY) + { + TestIfBadThingHitsOtherBadThing(x, y); + + if (IN_LEV_FIELD(right_x, right_y) && + IS_FREE_OR_PLAYER(right_x, right_y)) + MovDir[x][y] = right_dir; + else if (!IN_LEV_FIELD(move_x, move_y) || + !IS_FREE_OR_PLAYER(move_x, move_y)) + MovDir[x][y] = left_dir; + + if (element == EL_KAEFER && MovDir[x][y] != old_move_dir) + MovDelay[x][y] = 9; + else if (element == EL_BUTTERFLY) /* && MovDir[x][y] == left_dir) */ + MovDelay[x][y] = 1; + } + else if (element == EL_FLIEGER || element == EL_FIREFLY) { - TestIfBadThingHitsOtherBadThing(x,y); + TestIfBadThingHitsOtherBadThing(x, y); + + if (IN_LEV_FIELD(left_x, left_y) && + IS_FREE_OR_PLAYER(left_x, left_y)) + MovDir[x][y] = left_dir; + else if (!IN_LEV_FIELD(move_x, move_y) || + !IS_FREE_OR_PLAYER(move_x, move_y)) + MovDir[x][y] = right_dir; + + if (element == EL_FLIEGER && MovDir[x][y] != old_move_dir) + MovDelay[x][y] = 9; + else if (element == EL_FIREFLY) /* && MovDir[x][y] == right_dir) */ + MovDelay[x][y] = 1; + } + else if (element == EL_MAMPFER) + { + boolean can_turn_left = FALSE, can_turn_right = FALSE; + + if (IN_LEV_FIELD(left_x, left_y) && + (IS_FREE_OR_PLAYER(left_x, left_y) || + Feld[left_x][left_y] == EL_DIAMANT)) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && + (IS_FREE_OR_PLAYER(right_x, right_y) || + Feld[right_x][right_y] == EL_DIAMANT)) + can_turn_right = TRUE; + + if (can_turn_left && can_turn_right) + MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); + else if (can_turn_left) + MovDir[x][y] = (RND(2) ? left_dir : back_dir); + else if (can_turn_right) + MovDir[x][y] = (RND(2) ? right_dir : back_dir); + else + MovDir[x][y] = back_dir; - if (MovDir[x][y]==MV_LEFT) - { - if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1)) - MovDir[x][y]=MV_UP; - else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y)) - MovDir[x][y]=MV_DOWN; - } - else if (MovDir[x][y]==MV_RIGHT) - { - if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1)) - MovDir[x][y]=MV_DOWN; - else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y)) - MovDir[x][y]=MV_UP; - } - else if (MovDir[x][y]==MV_UP) - { - if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y)) - MovDir[x][y]=MV_RIGHT; - else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1)) - MovDir[x][y]=MV_LEFT; - } - else if (MovDir[x][y]==MV_DOWN) - { - if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y)) - MovDir[x][y]=MV_LEFT; - else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1)) - MovDir[x][y]=MV_RIGHT; - } + MovDelay[x][y] = 16+16*RND(3); + } + else if (element == EL_MAMPFER2) + { + boolean can_turn_left = FALSE, can_turn_right = FALSE; + + if (IN_LEV_FIELD(left_x, left_y) && + (IS_FREE_OR_PLAYER(left_x, left_y) || + IS_MAMPF2(Feld[left_x][left_y]))) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && + (IS_FREE_OR_PLAYER(right_x, right_y) || + IS_MAMPF2(Feld[right_x][right_y]))) + can_turn_right = TRUE; + + if (can_turn_left && can_turn_right) + MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); + else if (can_turn_left) + MovDir[x][y] = (RND(2) ? left_dir : back_dir); + else if (can_turn_right) + MovDir[x][y] = (RND(2) ? right_dir : back_dir); + else + MovDir[x][y] = back_dir; - if (direction!=MovDir[x][y]) - MovDelay[x][y]=5; + MovDelay[x][y] = 16+16*RND(3); } - else if (element==EL_FLIEGER) + else if (element == EL_PACMAN) { - TestIfBadThingHitsOtherBadThing(x,y); + boolean can_turn_left = FALSE, can_turn_right = FALSE; + + if (IN_LEV_FIELD(left_x, left_y) && + (IS_FREE_OR_PLAYER(left_x, left_y) || + IS_AMOEBOID(Feld[left_x][left_y]))) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && + (IS_FREE_OR_PLAYER(right_x, right_y) || + IS_AMOEBOID(Feld[right_x][right_y]))) + can_turn_right = TRUE; + + if (can_turn_left && can_turn_right) + MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); + else if (can_turn_left) + MovDir[x][y] = (RND(2) ? left_dir : back_dir); + else if (can_turn_right) + MovDir[x][y] = (RND(2) ? right_dir : back_dir); + else + MovDir[x][y] = back_dir; - if (MovDir[x][y]==MV_LEFT) - { - if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1)) - MovDir[x][y]=MV_DOWN; - else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y)) - MovDir[x][y]=MV_UP; - } - else if (MovDir[x][y]==MV_RIGHT) - { - if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1)) - MovDir[x][y]=MV_UP; - else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y)) - MovDir[x][y]=MV_DOWN; - } - else if (MovDir[x][y]==MV_UP) - { - if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y)) - MovDir[x][y]=MV_LEFT; - else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1)) - MovDir[x][y]=MV_RIGHT; - } - else if (MovDir[x][y]==MV_DOWN) + MovDelay[x][y] = 6+RND(40); + } + else if (element == EL_SCHWEIN) + { + boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE; + boolean should_turn_left = FALSE, should_turn_right = FALSE; + boolean should_move_on = FALSE; + int rnd_value = 24; + int rnd = RND(rnd_value); + + if (IN_LEV_FIELD(left_x, left_y) && + (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y]))) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && + (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y]))) + can_turn_right = TRUE; + if (IN_LEV_FIELD(move_x, move_y) && + (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y]))) + can_move_on = TRUE; + + if (can_turn_left && + (!can_move_on || + (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) && + !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy)))) + should_turn_left = TRUE; + if (can_turn_right && + (!can_move_on || + (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) && + !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy)))) + should_turn_right = TRUE; + if (can_move_on && + (!can_turn_left || !can_turn_right || + (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) && + !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) || + (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) && + !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy)))) + should_move_on = TRUE; + + if (should_turn_left || should_turn_right || should_move_on) { - if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y)) - MovDir[x][y]=MV_RIGHT; - else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1)) - MovDir[x][y]=MV_LEFT; + if (should_turn_left && should_turn_right && should_move_on) + MovDir[x][y] = (rnd < rnd_value/3 ? left_dir : + rnd < 2*rnd_value/3 ? right_dir : + old_move_dir); + else if (should_turn_left && should_turn_right) + MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir); + else if (should_turn_left && should_move_on) + MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir); + else if (should_turn_right && should_move_on) + MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir); + else if (should_turn_left) + MovDir[x][y] = left_dir; + else if (should_turn_right) + MovDir[x][y] = right_dir; + else if (should_move_on) + MovDir[x][y] = old_move_dir; } + else if (can_move_on && rnd > rnd_value/8) + MovDir[x][y] = old_move_dir; + else if (can_turn_left && can_turn_right) + MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir); + else if (can_turn_left && rnd > rnd_value/8) + MovDir[x][y] = left_dir; + else if (can_turn_right && rnd > rnd_value/8) + MovDir[x][y] = right_dir; + else + MovDir[x][y] = back_dir; - if (direction!=MovDir[x][y]) - MovDelay[x][y]=5; + if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) && + !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y])) + MovDir[x][y] = old_move_dir; + + MovDelay[x][y] = 0; } - else if (element==EL_MAMPFER) + else if (element == EL_DRACHE) { - if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT) - { - MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT); - if (IN_LEV_FIELD(x,y-1) && - (IS_FREE(x,y-1) || Feld[x][y-1]==EL_DIAMANT) && - RND(2)) - MovDir[x][y]=MV_UP; - if (IN_LEV_FIELD(x,y+1) && - (IS_FREE(x,y+1) || Feld[x][y+1]==EL_DIAMANT) && - RND(2)) - MovDir[x][y]=MV_DOWN; - } - else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN) - { - MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP); - if (IN_LEV_FIELD(x-1,y) && - (IS_FREE(x-1,y) || Feld[x-1][y]==EL_DIAMANT) && - RND(2)) - MovDir[x][y]=MV_LEFT; - if (IN_LEV_FIELD(x+1,y) && - (IS_FREE(x+1,y) || Feld[x+1][y]==EL_DIAMANT) && - RND(2)) - MovDir[x][y]=MV_RIGHT; - } + boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE; + int rnd_value = 24; + int rnd = RND(rnd_value); + + if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y)) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y)) + can_turn_right = TRUE; + if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y)) + can_move_on = TRUE; + + if (can_move_on && rnd > rnd_value/8) + MovDir[x][y] = old_move_dir; + else if (can_turn_left && can_turn_right) + MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir); + else if (can_turn_left && rnd > rnd_value/8) + MovDir[x][y] = left_dir; + else if (can_turn_right && rnd > rnd_value/8) + MovDir[x][y] = right_dir; + else + MovDir[x][y] = back_dir; - MovDelay[x][y]=8+8*RND(3); + if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y)) + MovDir[x][y] = old_move_dir; + + MovDelay[x][y] = 0; } - else if (element==EL_PACMAN) + else if (element == EL_ROBOT || element == EL_SONDE || + element == EL_MAULWURF || element == EL_PINGUIN) { - if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT) + int attr_x = -1, attr_y = -1; + + if (AllPlayersGone) { - MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT); - if (IN_LEV_FIELD(x,y-1) && - (IS_FREE(x,y-1) || IS_AMOEBOID(Feld[x][y-1])) && - RND(2)) - MovDir[x][y]=MV_UP; - if (IN_LEV_FIELD(x,y+1) && - (IS_FREE(x,y+1) || IS_AMOEBOID(Feld[x][y+1])) && - RND(2)) - MovDir[x][y]=MV_DOWN; + attr_x = ExitX; + attr_y = ExitY; } - else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN) + else { - MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP); - if (IN_LEV_FIELD(x-1,y) && - (IS_FREE(x-1,y) || IS_AMOEBOID(Feld[x-1][y])) && - RND(2)) - MovDir[x][y]=MV_LEFT; - if (IN_LEV_FIELD(x+1,y) && - (IS_FREE(x+1,y) || IS_AMOEBOID(Feld[x+1][y])) && - RND(2)) - MovDir[x][y]=MV_RIGHT; - } + int i; - MovDelay[x][y]=3+RND(20); - } - else if (element==EL_ZOMBIE) - { - int attr_x = JX, attr_y = JY; + for (i=0; ijx, jy = player->jy; + + if (!player->active || player->gone) + continue; + + if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y)) + { + attr_x = jx; + attr_y = jy; + } + } + } - if (ZX>=0 && ZY>=0) + if (element == EL_ROBOT && ZX>=0 && ZY>=0) { attr_x = ZX; attr_y = ZY; } - MovDir[x][y]=MV_NO_MOVING; - if (attr_xx) - MovDir[x][y]|=MV_RIGHT; + MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT); if (attr_yy) - MovDir[x][y]|=MV_DOWN; - if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN))) - MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN)); + MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN); + + if (element == EL_ROBOT) + { + int newx, newy; + + if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN))) + MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN)); + Moving2Blocked(x, y, &newx, &newy); + + if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy)) + MovDelay[x][y] = 8+8*!RND(3); + else + MovDelay[x][y] = 16; + } + else + { + int newx, newy; + + MovDelay[x][y] = 1; + + if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN))) + { + boolean first_horiz = RND(2); + int new_move_dir = MovDir[x][y]; + + MovDir[x][y] = + new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN)); + Moving2Blocked(x, y, &newx, &newy); + + if (IN_LEV_FIELD(newx, newy) && + (IS_FREE(newx, newy) || + Feld[newx][newy] == EL_SALZSAEURE || + ((element == EL_MAULWURF || element == EL_PINGUIN) && + (Feld[newx][newy] == EL_AUSGANG_AUF || + IS_MAMPF3(Feld[newx][newy]))))) + return; + + MovDir[x][y] = + new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN)); + Moving2Blocked(x, y, &newx, &newy); + + if (IN_LEV_FIELD(newx, newy) && + (IS_FREE(newx, newy) || + Feld[newx][newy] == EL_SALZSAEURE || + ((element == EL_MAULWURF || element == EL_PINGUIN) && + (Feld[newx][newy] == EL_AUSGANG_AUF || + IS_MAMPF3(Feld[newx][newy]))))) + return; + + MovDir[x][y] = old_move_dir; + return; + } + } + } +} - MovDelay[x][y] = 8+8*RND(2); +static boolean JustBeingPushed(int x, int y) +{ + int i; + + for (i=0; iactive && !player->gone && + player->Pushing && player->MovPos) + { + int next_jx = player->jx + (player->jx - player->last_jx); + int next_jy = player->jy + (player->jy - player->last_jy); + + if (x == next_jx && y == next_jy) + return TRUE; + } } + + return FALSE; } void StartMoving(int x, int y) @@ -1000,20 +1726,22 @@ void StartMoving(int x, int y) if (CAN_FALL(element) && y0 && IS_PLAYER(x-1, y)) || (x0 && IS_FREE(x-1,y) && - (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE)); - int right = (x0 && IS_FREE(x-1, y) && + (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE)); + boolean right = (x3) phase = 7-phase; - if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y), - el2gfx(element)+phase); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase); + + if ((element == EL_MAMPFER || element == EL_MAMPFER2) + && MovDelay[x][y]%4 == 3) + PlaySoundLevel(x, y, SND_NJAM); + } + else if (element == EL_DRACHE) + { + int i; + int dir = MovDir[x][y]; + int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0); + int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); + int graphic = (dir == MV_LEFT ? GFX_FLAMMEN_LEFT : + dir == MV_RIGHT ? GFX_FLAMMEN_RIGHT : + dir == MV_UP ? GFX_FLAMMEN_UP : + dir == MV_DOWN ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM); + int phase = FrameCounter % 2; + + for (i=1; i<=3; i++) + { + int xx = x + i*dx, yy = y + i*dy; + int sx = SCREENX(xx), sy = SCREENY(yy); + + if (!IN_LEV_FIELD(xx, yy) || + IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING) + break; + + if (MovDelay[x][y]) + { + int flamed = MovingOrBlocked2Element(xx, yy); - if (element==EL_MAMPFER && MovDelay[x][y]%4==3) - PlaySoundLevel(x,y,SND_NJAM); + if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed)) + Bang(xx, yy); + else + RemoveMovingField(xx, yy); + + Feld[xx][yy] = EL_BURNING; + if (IN_SCR_FIELD(sx, sy)) + DrawGraphic(sx, sy, graphic + phase*3 + i-1); + } + else + { + if (Feld[xx][yy] == EL_BURNING) + Feld[xx][yy] = EL_LEERRAUM; + DrawLevelField(xx, yy); + } + } } if (MovDelay[x][y]) return; } - if (element==EL_KAEFER) + if (element == EL_KAEFER || element == EL_BUTTERFLY) { - PlaySoundLevel(x,y,SND_KLAPPER); + PlaySoundLevel(x, y, SND_KLAPPER); } - else if (element==EL_FLIEGER) + else if (element == EL_FLIEGER || element == EL_FIREFLY) { - PlaySoundLevel(x,y,SND_ROEHR); + PlaySoundLevel(x, y, SND_ROEHR); } - /* neuer Schritt / Wartezustand beendet */ + /* now make next step */ - Moving2Blocked(x,y,&newx,&newy); /* wohin soll's gehen? */ + Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ - if (PLAYER(newx,newy)) /* Spieler erwischt */ + if (IS_ENEMY(element) && IS_PLAYER(newx, newy)) { + /* enemy got the player */ MovDir[x][y] = 0; - KillHero(); + KillHero(PLAYERINFO(newx, newy)); return; } - else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) && - Feld[newx][newy]==EL_DIAMANT) + else if ((element == EL_MAULWURF || element == EL_PINGUIN || + element == EL_ROBOT || element == EL_SONDE) && + IN_LEV_FIELD(newx, newy) && + MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE) + { + Blurb(x, y); + Store[x][y] = EL_SALZSAEURE; + } + else if ((element == EL_MAULWURF || element == EL_PINGUIN) && + IN_LEV_FIELD(newx, newy)) + { + if (Feld[newx][newy] == EL_AUSGANG_AUF) + { + Feld[x][y] = EL_LEERRAUM; + DrawLevelField(x, y); + + PlaySoundLevel(newx, newy, SND_BUING); + if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) + DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element)); + + local_player->friends_still_needed--; + if (!local_player->friends_still_needed && + !local_player->GameOver && AllPlayersGone) + local_player->LevelSolved = local_player->GameOver = TRUE; + + return; + } + else if (IS_MAMPF3(Feld[newx][newy])) + { + if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING) + DrawLevelField(newx, newy); + else + MovDir[x][y] = MV_NO_MOVING; + } + else if (!IS_FREE(newx, newy)) + { + if (IS_PLAYER(x, y)) + DrawPlayerField(x, y); + else + DrawLevelField(x, y); + return; + } + } + else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy)) + { + if (IS_GEM(Feld[newx][newy])) + { + if (IS_MOVING(newx, newy)) + RemoveMovingField(newx, newy); + else + { + Feld[newx][newy] = EL_LEERRAUM; + DrawLevelField(newx, newy); + } + } + else if (!IS_FREE(newx, newy)) + { + if (IS_PLAYER(x, y)) + DrawPlayerField(x, y); + else + DrawLevelField(x, y); + return; + } + } + else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy)) + { + if (!IS_FREE(newx, newy)) + { + if (IS_PLAYER(x, y)) + DrawPlayerField(x, y); + else + DrawLevelField(x, y); + return; + } + else + { + boolean wanna_flame = !RND(10); + int dx = newx - x, dy = newy - y; + int newx1 = newx+1*dx, newy1 = newy+1*dy; + int newx2 = newx+2*dx, newy2 = newy+2*dy; + int element1 = (IN_LEV_FIELD(newx1, newy1) ? + MovingOrBlocked2Element(newx1, newy1) : EL_BETON); + int element2 = (IN_LEV_FIELD(newx2, newy2) ? + MovingOrBlocked2Element(newx2, newy2) : EL_BETON); + + if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) && + element1 != EL_DRACHE && element2 != EL_DRACHE && + element1 != EL_BURNING && element2 != EL_BURNING) + { + if (IS_PLAYER(x, y)) + DrawPlayerField(x, y); + else + DrawLevelField(x, y); + + MovDelay[x][y] = 50; + Feld[newx][newy] = EL_BURNING; + if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM) + Feld[newx1][newy1] = EL_BURNING; + if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM) + Feld[newx2][newy2] = EL_BURNING; + return; + } + } + } + else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) && + Feld[newx][newy] == EL_DIAMANT) + { + if (IS_MOVING(newx, newy)) + RemoveMovingField(newx, newy); + else + { + Feld[newx][newy] = EL_LEERRAUM; + DrawLevelField(newx, newy); + } + } + else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) && + IS_MAMPF2(Feld[newx][newy])) { - if (IS_MOVING(newx,newy)) - RemoveMovingField(newx,newy); + if (AmoebaNr[newx][newy]) + { + AmoebaCnt2[AmoebaNr[newx][newy]]--; + if (Feld[newx][newy] == EL_AMOEBE_VOLL || + Feld[newx][newy] == EL_AMOEBE_BD) + AmoebaCnt[AmoebaNr[newx][newy]]--; + } + + if (IS_MOVING(newx, newy)) + RemoveMovingField(newx, newy); else { Feld[newx][newy] = EL_LEERRAUM; - DrawLevelField(newx,newy); + DrawLevelField(newx, newy); } } - else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) && + else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy])) { - if (AmoebaNr[newx][newy] && Feld[newx][newy]==EL_AMOEBE_VOLL) - AmoebaCnt[AmoebaNr[newx][newy]]--; + if (AmoebaNr[newx][newy]) + { + AmoebaCnt2[AmoebaNr[newx][newy]]--; + if (Feld[newx][newy] == EL_AMOEBE_VOLL || + Feld[newx][newy] == EL_AMOEBE_BD) + AmoebaCnt[AmoebaNr[newx][newy]]--; + } Feld[newx][newy] = EL_LEERRAUM; - DrawLevelField(newx,newy); + DrawLevelField(newx, newy); } - else if (element==EL_ZOMBIE && IN_LEV_FIELD(newx,newy) && - MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE) + else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy)) { - Blurb(x,y); - Store[x][y] = EL_SALZSAEURE; - } - else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy)) - { /* gegen Wand gelaufen */ - TurnRound(x,y); - DrawLevelField(x,y); + /* object was running against a wall */ + + TurnRound(x, y); + + if (element == EL_KAEFER || element == EL_FLIEGER) + DrawLevelField(x, y); + else if (element == EL_BUTTERFLY || element == EL_FIREFLY) + DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL); + else if (element == EL_SONDE) + DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL); + return; } - InitMovingField(x,y,MovDir[x][y]); + if (element == EL_ROBOT && IN_SCR_FIELD(x, y)) + PlaySoundLevel(x, y, SND_SCHLURF); + + InitMovingField(x, y, MovDir[x][y]); } if (MovDir[x][y]) - ContinueMoving(x,y); + ContinueMoving(x, y); } void ContinueMoving(int x, int y) { int element = Feld[x][y]; int direction = MovDir[x][y]; - int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0); - int dy = (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0); + int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); + int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int horiz_move = (dx!=0); int newx = x + dx, newy = y + dy; - int step = (horiz_move ? dx : dy)*TILEX/4; + int step = (horiz_move ? dx : dy) * TILEX/8; if (CAN_FALL(element) && horiz_move) step*=2; - else if (element==EL_TROPFEN) + else if (element == EL_TROPFEN) step/=2; - else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER) + else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER) step/=4; MovPos[x][y] += step; - if (ABS(MovPos[x][y])>=TILEX) /* Zielfeld erreicht */ + if (ABS(MovPos[x][y])>=TILEX) /* object reached its destination */ { - Feld[x][y]=EL_LEERRAUM; - Feld[newx][newy]=element; + Feld[x][y] = EL_LEERRAUM; + Feld[newx][newy] = element; - if (Store[x][y]==EL_MORAST_VOLL) + if (Store[x][y] == EL_MORAST_VOLL) { Store[x][y] = 0; Feld[newx][newy] = EL_MORAST_VOLL; element = EL_MORAST_VOLL; } - else if (Store[x][y]==EL_MORAST_LEER) + else if (Store[x][y] == EL_MORAST_LEER) { Store[x][y] = 0; Feld[x][y] = EL_MORAST_LEER; } - else if (Store[x][y]==EL_SIEB_VOLL) + else if (Store[x][y] == EL_SIEB_VOLL) + { + Store[x][y] = 0; + element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT); + } + else if (Store[x][y] == EL_SIEB_LEER) + { + Store[x][y] = Store2[x][y] = 0; + Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT); + } + else if (Store[x][y] == EL_SIEB2_VOLL) { Store[x][y] = 0; - Feld[newx][newy] = EL_SIEB_VOLL; - element = EL_SIEB_VOLL; + element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT); } - else if (Store[x][y]==EL_SIEB_LEER) + else if (Store[x][y] == EL_SIEB2_LEER) { Store[x][y] = Store2[x][y] = 0; - Feld[x][y] = EL_SIEB_LEER; + Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT); } - else if (Store[x][y]==EL_SALZSAEURE) + else if (Store[x][y] == EL_SALZSAEURE) { Store[x][y] = 0; Feld[newx][newy] = EL_SALZSAEURE; element = EL_SALZSAEURE; } - else if (Store[x][y]==EL_AMOEBE_NASS) + else if (Store[x][y] == EL_AMOEBE_NASS) { Store[x][y] = 0; Feld[x][y] = EL_AMOEBE_NASS; } - MovPos[x][y] = MovDir[x][y] = 0; + MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; + MovDelay[newx][newy] = 0; if (!CAN_MOVE(element)) MovDir[newx][newy] = 0; - DrawLevelField(x,y); - DrawLevelField(newx,newy); + DrawLevelField(x, y); + DrawLevelField(newx, newy); - Stop[newx][newy]=TRUE; - CheckMoving=TRUE; + Stop[newx][newy] = TRUE; + JustHit[x][newy] = 3; - if (DONT_TOUCH(element)) /* Käfer oder Flieger */ + if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { - TestIfBadThingHitsHero(); - TestIfBadThingHitsOtherBadThing(newx,newy); + TestIfBadThingHitsHero(newx, newy); + TestIfBadThingHitsFriend(newx, newy); + TestIfBadThingHitsOtherBadThing(newx, newy); } + else if (element == EL_PINGUIN) + TestIfFriendHitsBadThing(newx, newy); - if (CAN_SMASH(element) && direction==MV_DOWN && - (newy==lev_fieldy-1 || !IS_FREE(x,newy+1))) - Impact(x,newy); - } - else /* noch in Bewegung */ - { - DrawLevelField(x,y); - CheckMoving=TRUE; + if (CAN_SMASH(element) && direction == MV_DOWN && + (newy == lev_fieldy-1 || !IS_FREE(x, newy+1))) + Impact(x, newy); } + else /* still moving on */ + DrawLevelField(x, y); } int AmoebeNachbarNr(int ax, int ay) @@ -1272,60 +2237,64 @@ int AmoebeNachbarNr(int ax, int ay) int group_nr = 0; static int xy[4][2] = { - 0,-1, - -1,0, - +1,0, - 0,+1 + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } }; - for(i=0;i<4;i++) + for (i=0; i<4; i++) { int x = ax+xy[i%4][0]; int y = ay+xy[i%4][1]; - if (!IN_LEV_FIELD(x,y)) + if (!IN_LEV_FIELD(x, y)) continue; - if (Feld[x][y]==element && AmoebaNr[x][y]>0) + if (Feld[x][y] == element && AmoebaNr[x][y]>0) group_nr = AmoebaNr[x][y]; } - return(group_nr); + return group_nr; } void AmoebenVereinigen(int ax, int ay) { - int i,x,y,xx,yy; + int i, x, y, xx, yy; int new_group_nr = AmoebaNr[ax][ay]; static int xy[4][2] = { - 0,-1, - -1,0, - +1,0, - 0,+1 + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } }; if (!new_group_nr) return; - for(i=0;i<4;i++) + for (i=0; i<4; i++) { x = ax+xy[i%4][0]; y = ay+xy[i%4][1]; - if (!IN_LEV_FIELD(x,y)) + if (!IN_LEV_FIELD(x, y)) continue; - if ((Feld[x][y]==EL_AMOEBE_VOLL || Feld[x][y]==EL_AMOEBE_TOT) && + if ((Feld[x][y] == EL_AMOEBE_VOLL || + Feld[x][y] == EL_AMOEBE_BD || + Feld[x][y] == EL_AMOEBE_TOT) && AmoebaNr[x][y] != new_group_nr) { int old_group_nr = AmoebaNr[x][y]; AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr]; AmoebaCnt[old_group_nr] = 0; + AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; + AmoebaCnt2[old_group_nr] = 0; - for(yy=0;yy= 200 && element == EL_AMOEBE_BD) + { + AmoebeUmwandeln2(newax, neway, EL_FELSBROCKEN); + return; + } } } - if (element!=EL_AMOEBE_NASS || newaylife[1]) { Feld[xx][yy] = EL_LEERRAUM; if (!Stop[xx][yy]) - DrawLevelField(xx,yy); + DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; } } - else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH) - { /* Randfeld ohne Amoebe */ + else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH) + { /* free border field */ if (nachbarn>=life[2] && nachbarn<=life[3]) { Feld[xx][yy] = element; - MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1); + MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1); if (!Stop[xx][yy]) - DrawLevelField(xx,yy); + DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; } } @@ -1591,37 +2593,34 @@ void Life(int ax, int ay) void Ablenk(int x, int y) { - CheckExploding=TRUE; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND; - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 33*(level.dauer_ablenk/10); - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (MovDelay[x][y]) { - if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4); if (!(MovDelay[x][y]%4)) - PlaySoundLevel(x,y,SND_MIEP); + PlaySoundLevel(x, y, SND_MIEP); return; } } - Feld[x][y]=EL_ABLENK_AUS; - DrawLevelField(x,y); - if (ZX==x && ZY==y) - ZX=ZY=-1; + Feld[x][y] = EL_ABLENK_AUS; + DrawLevelField(x, y); + if (ZX == x && ZY == y) + ZX = ZY = -1; } void Birne(int x, int y) { - CheckExploding=TRUE; - - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 400; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 800; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (MovDelay[x][y]) @@ -1632,7 +2631,7 @@ void Birne(int x, int y) Feld[x][y]=EL_ABLENK_EIN; else Feld[x][y]=EL_ABLENK_AUS; - DrawLevelField(x,y); + DrawLevelField(x, y); Feld[x][y]=EL_ABLENK_EIN; } return; @@ -1640,333 +2639,1132 @@ void Birne(int x, int y) } Feld[x][y]=EL_ABLENK_AUS; - DrawLevelField(x,y); - if (ZX==x && ZY==y) + DrawLevelField(x, y); + if (ZX == x && ZY == y) ZX=ZY=-1; } void Blubber(int x, int y) { - CheckExploding=TRUE; - - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 20; - - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ - { - int blubber; - - MovDelay[x][y]--; - blubber = MovDelay[x][y]/5; - if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_GEBLUBBER+3-blubber); - } + if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN) + DrawLevelField(x, y-1); + else + DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL); } void NussKnacken(int x, int y) { - CheckExploding=TRUE; - - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 4; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 7; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; - if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]); + if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2); if (!MovDelay[x][y]) { Feld[x][y] = EL_EDELSTEIN; - DrawLevelField(x,y); + DrawLevelField(x, y); } } } -void SiebAktivieren(int x, int y) +void SiebAktivieren(int x, int y, int typ) { - CheckExploding=TRUE; - - if (SiebAktiv>1) - { - if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_SIEB_VOLL+3-(SiebAktiv%8)/2); - -/* - if (!(SiebAktiv%4)) - PlaySoundLevel(x,y,SND_MIEP); -*/ - - } - else - { - Feld[x][y] = EL_SIEB_TOT; - DrawLevelField(x,y); - } + if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), + (typ == 1 ? GFX_SIEB_VOLL : + GFX_SIEB2_VOLL) + 3 - (SiebAktiv % 16) / 4); } void AusgangstuerPruefen(int x, int y) { - CheckExploding=TRUE; - - if (!Gems) + if (!local_player->gems_still_needed && + !local_player->sokobanfields_still_needed && + !local_player->lights_still_needed) + { Feld[x][y] = EL_AUSGANG_ACT; + + PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : + (x > LEVELX(BX2) ? LEVELX(BX2) : x), + y < LEVELY(BY1) ? LEVELY(BY1) : + (y > LEVELY(BY2) ? LEVELY(BY2) : y), + SND_OEFFNEN); + } } void AusgangstuerOeffnen(int x, int y) { - CheckExploding=TRUE; + int delay = 6; - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = 20; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 5*delay; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { int tuer; MovDelay[x][y]--; - tuer = MovDelay[x][y]/5; - if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_ZU+3-tuer); + tuer = MovDelay[x][y]/delay; + if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer); if (!MovDelay[x][y]) { Feld[x][y] = EL_AUSGANG_AUF; - DrawLevelField(x,y); + DrawLevelField(x, y); } } } -int GameActions(int mx, int my, int button) +void AusgangstuerBlinken(int x, int y) +{ + DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE); +} + +void EdelsteinFunkeln(int x, int y) { - static long time_delay=0, action_delay=0; - int Action; + if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y)) + return; - if (TimeLeft>0 && DelayReached(&time_delay,100) && !tape.pausing) + if (Feld[x][y] == EL_EDELSTEIN_BD) + DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE); + else { - TimeLeft--; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 11 * !SimpleRND(500); - if (tape.recording || tape.playing) - DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft); + if (MovDelay[x][y]) /* wait some time before next frame */ + { + MovDelay[x][y]--; - if (TimeLeft<=10) - PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT); + if (setup.direct_draw && MovDelay[x][y]) + SetDrawtoField(DRAW_BUFFERED); - DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW); - BackToFront(); - } + DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y])); - if (!TimeLeft) - KillHero(); + if (MovDelay[x][y]) + { + int phase = (MovDelay[x][y]-1)/2; - Action = (CheckMoving || CheckExploding || SiebAktiv); + if (phase > 2) + phase = 4-phase; -/* - if (Action && DelayReached(&action_delay,3)) -*/ + DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase); - if (DelayReached(&action_delay,3)) - { - int x,y,element; + if (setup.direct_draw) + { + int dest_x, dest_y; - if (tape.pausing || (tape.playing && !TapePlayDelay())) - return(ACT_GO_ON); - else if (tape.recording) - TapeRecordDelay(); + dest_x = FX + SCREENX(x)*TILEX; + dest_y = FY + SCREENY(y)*TILEY; - CheckMoving = CheckExploding = FALSE; - for(y=0;yjx, jy = player->jy; + int left = player_action & JOY_LEFT; + int right = player_action & JOY_RIGHT; + int up = player_action & JOY_UP; + int down = player_action & JOY_DOWN; + int button1 = player_action & JOY_BUTTON_1; + int button2 = player_action & JOY_BUTTON_2; + int dx = (left ? -1 : right ? 1 : 0); + int dy = (up ? -1 : down ? 1 : 0); + + stored_player_action[player->index_nr] = 0; + num_stored_actions++; + + if (!player->active || player->gone || tape.pausing) + return; + + if (player_action) + { + save_tape_entry = TRUE; + player->frame_reset_delay = 0; + + if (button1) + snapped = SnapField(player, dx, dy); + else + { + if (button2) + bombed = PlaceBomb(player); + moved = MoveFigure(player, dx, dy); + } + + if (tape.recording && (moved || snapped || bombed)) + { + if (bombed && !moved) + player_action &= JOY_BUTTON; + + stored_player_action[player->index_nr] = player_action; + +#if 0 + /* this allows cycled sequences of PlayerActions() */ + if (num_stored_actions >= MAX_PLAYERS) + { + TapeRecordAction(stored_player_action); + num_stored_actions = 0; + } +#endif + + } + else if (tape.playing && snapped) + SnapField(player, 0, 0); /* stop snapping */ + } + else + { + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); + SnapField(player, 0, 0); + if (++player->frame_reset_delay > MoveSpeed) + player->Frame = 0; + } + + if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry) + { + TapeRecordAction(stored_player_action); + num_stored_actions = 0; + save_tape_entry = FALSE; + } + + if (tape.playing && !tape.pausing && !player_action && + tape.counter < tape.length) + { + int next_joy = + tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT); + + if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) && + (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN)) + { + int dx = (next_joy == JOY_LEFT ? -1 : +1); + + if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy])) + { + int el = Feld[jx+dx][jy]; + int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10); + + if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay) + { + player->MovDir = next_joy; + player->Frame = FrameCounter % 4; + player->Pushing = TRUE; + } + } + } + } +} + +void GameActions() +{ + static unsigned long action_delay = 0; + unsigned long action_delay_value; + int sieb_x = 0, sieb_y = 0; + int i, x, y, element; + byte *recorded_player_action; + byte summarized_player_action = 0; + + if (game_status != PLAYING) + return; + + action_delay_value = + (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay); + + /* + if (tape.playing && tape.fast_forward) + { + char buf[100]; + + sprintf(buf, "FFWD: %ld ms", action_delay_value); + print_debug(buf); + } + */ + + + /* main game synchronization point */ + + + + +#if 1 + WaitUntilDelayReached(&action_delay, action_delay_value); +#else + + while (!DelayReached(&action_delay, action_delay_value)) + { + char buf[100]; + + sprintf(buf, "%ld %ld %ld", + Counter(), action_delay, action_delay_value); + print_debug(buf); + } + print_debug("done"); + +#endif + + + + + if (network_playing && !network_player_action_received) + { + /* +#ifdef DEBUG + printf("DEBUG: try to get network player actions in time\n"); +#endif + */ + +#ifndef MSDOS + /* last chance to get network player actions without main loop delay */ + HandleNetworking(); +#endif + + if (game_status != PLAYING) + return; + + if (!network_player_action_received) + { + /* +#ifdef DEBUG + printf("DEBUG: failed to get network player actions in time\n"); +#endif + */ + return; + } + } + + + /* + if (tape.pausing || (tape.playing && !TapePlayDelay())) + return; + else if (tape.recording) + TapeRecordDelay(); + */ + + if (tape.pausing) + return; + + if (tape.playing) + TapePlayDelay(); + else if (tape.recording) + TapeRecordDelay(); + + recorded_player_action = (tape.playing ? TapePlayAction() : NULL); + + for (i=0; ieffective_action = summarized_player_action; + + for (i=0; igone) + { + extern unsigned int last_RND(); + + printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n", + level.time - TimeLeft, + last_RND(), + getStateCheckSum(level.time - TimeLeft)); + } + */ +#endif + + + +#ifdef DEBUG + /* + if (GameFrameDelay >= 500) + printf("FrameCounter == %d\n", FrameCounter); + */ +#endif + + + + + + FrameCounter++; + TimeFrames++; + + for (y=0; y0) + JustHit[x][y]--; + +#if DEBUG + if (IS_BLOCKED(x, y)) + { + int oldx, oldy; + + Blocked2Moving(x, y, &oldx, &oldy); + if (!IS_MOVING(oldx, oldy)) + { + printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n"); + printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y); + printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy); + printf("GameActions(): This should never happen!\n"); + } + } +#endif + } + + for (y=0; yjx, jy = local_player->jy; + + if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL || + Store[x][y] == EL_SIEB_LEER) + { + SiebAktivieren(x, y, 1); + sieb = TRUE; + } + else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL || + Store[x][y] == EL_SIEB2_LEER) + { + SiebAktivieren(x, y, 2); + sieb = TRUE; + } + + /* play the element sound at the position nearest to the player */ + if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy)) + { + sieb_x = x; + sieb_y = y; + } + } + } + + if (SiebAktiv) + { + if (!(SiebAktiv%4)) + PlaySoundLevel(sieb_x, sieb_y, SND_MIEP); + SiebAktiv--; + if (!SiebAktiv) + { + for (y=0; y0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing) + { + TimeFrames = 0; + TimeLeft--; + + if (tape.recording || tape.playing) + DrawVideoDisplay(VIDEO_STATE_TIME_ON, level.time-TimeLeft); + + if (TimeLeft<=10) + PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); + + DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); + + if (!TimeLeft) + for (i=0; ijx, jy = player->jy; + int new_jx = jx+dx, new_jy = jy+dy; int element; int can_move; - if (!dx && !dy) - return(MF_NO_ACTION); - if (!IN_LEV_FIELD(newJX,newJY)) - return(MF_NO_ACTION); + if (player->gone || (!dx && !dy)) + return MF_NO_ACTION; - element = MovingOrBlocked2Element(newJX,newJY); + player->MovDir = (dx < 0 ? MV_LEFT : + dx > 0 ? MV_RIGHT : + dy < 0 ? MV_UP : + dy > 0 ? MV_DOWN : MV_NO_MOVING); + + if (!IN_LEV_FIELD(new_jx, new_jy)) + return MF_NO_ACTION; + + if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) + return MF_NO_ACTION; + + element = MovingOrBlocked2Element(new_jx, new_jy); if (DONT_GO_TO(element)) { - if (element==EL_SALZSAEURE && dx==0 && dy==1) + if (element == EL_SALZSAEURE && dx == 0 && dy == 1) + { + Blurb(jx, jy); + Feld[jx][jy] = EL_SPIELFIGUR; + InitMovingField(jx, jy, MV_DOWN); + Store[jx][jy] = EL_SALZSAEURE; + ContinueMoving(jx, jy); + BuryHero(player); + } + else + KillHero(player); + + return MF_MOVING; + } + + can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG); + if (can_move != MF_MOVING) + return can_move; + + StorePlayer[jx][jy] = 0; + player->last_jx = jx; + player->last_jy = jy; + jx = player->jx = new_jx; + jy = player->jy = new_jy; + StorePlayer[jx][jy] = player->element_nr; + + player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8; + + ScrollFigure(player, SCROLL_INIT); + + return MF_MOVING; +} + +boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) +{ + int jx = player->jx, jy = player->jy; + int old_jx = jx, old_jy = jy; + int moved = MF_NO_ACTION; + + if (player->gone || (!dx && !dy)) + return FALSE; + + if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing) + return FALSE; + + if (player->MovPos) + { + /* should only happen if pre-1.2 tape recordings are played */ + /* this is only for backward compatibility */ + +#if DEBUG + printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n"); +#endif + + while (player->MovPos) { - Blurb(JX,JY); - Feld[JX][JY] = EL_SPIELFIGUR; - InitMovingField(JX,JY,MV_DOWN); - Store[JX][JY] = EL_SALZSAEURE; - ContinueMoving(JX,JY); + ScrollFigure(player, SCROLL_GO_ON); + ScrollScreen(NULL, SCROLL_GO_ON); + FrameCounter++; + DrawAllPlayers(); + BackToFront(); + } + } - PlaySoundLevel(JX,JY,SND_AUTSCH); - PlaySoundLevel(JX,JY,SND_LACHEN); - GameOver = TRUE; - JX = JY = -1; + if (player->last_move_dir & (MV_LEFT | MV_RIGHT)) + { + if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy))) + moved |= MoveFigureOneStep(player, dx, 0, dx, dy); + } + else + { + if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy))) + moved |= MoveFigureOneStep(player, 0, dy, dx, dy); + } + + jx = player->jx; + jy = player->jy; + + if (moved & MF_MOVING && !ScreenMovPos && + (player == local_player || !options.network)) + { + int old_scroll_x = scroll_x, old_scroll_y = scroll_y; + int offset = (setup.scroll_delay ? 3 : 0); + + if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) + { + /* actual player has left the screen -- scroll in that direction */ + if (jx != old_jx) /* player has moved horizontally */ + scroll_x += (jx - old_jx); + else /* player has moved vertically */ + scroll_y += (jy - old_jy); } else - KillHero(); + { + if (jx != old_jx) /* player has moved horizontally */ + { + if ((player->MovDir == MV_LEFT && scroll_x > jx-MIDPOSX+offset) || + (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset)) + scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset); + + /* don't scroll over playfield boundaries */ + if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 1) + scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 1); + + /* don't scroll more than one field at a time */ + scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x); + + /* don't scroll against the player's moving direction */ + if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) || + (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x)) + scroll_x = old_scroll_x; + } + else /* player has moved vertically */ + { + if ((player->MovDir == MV_UP && scroll_y > jy-MIDPOSY+offset) || + (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset)) + scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset); + + /* don't scroll over playfield boundaries */ + if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 1) + scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 1); + + /* don't scroll more than one field at a time */ + scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y); + + /* don't scroll against the player's moving direction */ + if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) || + (player->MovDir == MV_DOWN && scroll_y < old_scroll_y)) + scroll_y = old_scroll_y; + } + } + + if (scroll_x != old_scroll_x || scroll_y != old_scroll_y) + { + if (!options.network && !AllPlayersInVisibleScreen()) + { + scroll_x = old_scroll_x; + scroll_y = old_scroll_y; + } + else + { + ScrollScreen(player, SCROLL_INIT); + ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y); + } + } + } + + if (!(moved & MF_MOVING) && !player->Pushing) + player->Frame = 0; + else + player->Frame = (player->Frame + 1) % 4; + + if (moved & MF_MOVING) + { + if (old_jx != jx && old_jy == jy) + player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT); + else if (old_jx == jx && old_jy != jy) + player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP); + + DrawLevelField(jx, jy); /* for "ErdreichAnbroeckeln()" */ + + player->last_move_dir = player->MovDir; + } + else + player->last_move_dir = MV_NO_MOVING; + + TestIfHeroHitsBadThing(jx, jy); + + if (player->gone) + RemoveHero(player); + + return moved; +} + +void ScrollFigure(struct PlayerInfo *player, int mode) +{ + int jx = player->jx, jy = player->jy; + int last_jx = player->last_jx, last_jy = player->last_jy; + + if (!player->active || player->gone || !player->MovPos) + return; + + if (mode == SCROLL_INIT) + { + player->actual_frame_counter = FrameCounter; + player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize); + + if (Feld[last_jx][last_jy] == EL_LEERRAUM) + Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; + + DrawPlayer(player); + return; + } + else if (!FrameReached(&player->actual_frame_counter, 1)) + return; + + player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8; + player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize); + + if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING) + Feld[last_jx][last_jy] = EL_LEERRAUM; + + DrawPlayer(player); + + if (!player->MovPos) + { + player->last_jx = jx; + player->last_jy = jy; + + if (Feld[jx][jy] == EL_AUSGANG_AUF) + { + RemoveHero(player); - return(MF_MOVING); + if (!local_player->friends_still_needed) + player->LevelSolved = player->GameOver = TRUE; + } } +} - can_move = DigField(newJX,newJY,DF_DIG); - if (can_move != MF_MOVING) - return(can_move); +void ScrollScreen(struct PlayerInfo *player, int mode) +{ + static unsigned long screen_frame_counter = 0; - oldJX = JX; - oldJY = JY; - JX = newJX; - JY = newJY; + if (mode == SCROLL_INIT) + { + screen_frame_counter = FrameCounter; + ScreenMovDir = player->MovDir; + ScreenMovPos = player->MovPos; + ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); + return; + } + else if (!FrameReached(&screen_frame_counter, 1)) + return; - if (Store[oldJX][oldJY]) + if (ScreenMovPos) { - DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY])); - DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY), - el2gfx(Feld[oldJX][oldJY])); + ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8; + ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); + redraw_mask |= REDRAW_FIELD; } - else if (Feld[oldJX][oldJY]==EL_DYNAMIT) - DrawDynamite(oldJX,oldJY); else - DrawLevelField(oldJX,oldJY); - - return(MF_MOVING); + ScreenMovDir = MV_NO_MOVING; } -BOOL MoveFigure(int dx, int dy) +void TestIfGoodThingHitsBadThing(int goodx, int goody) { - static long move_delay = 0; - int moved = MF_NO_ACTION; - - if (GameOver || (!dx && !dy)) - return(FALSE); - - if (!DelayReached(&move_delay,10) && !tape.playing) - return(FALSE); - - if (moved |= MoveFigureOneStep(dx,0)) - moved |= MoveFigureOneStep(0,dy); - else + int i, killx = goodx, killy = goody; + static int xy[4][2] = { - moved |= MoveFigureOneStep(0,dy); - moved |= MoveFigureOneStep(dx,0); - } - - if (moved & MF_MOVING) + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + static int harmless[4] = { - int old_scroll_x=scroll_x, old_scroll_y=scroll_y; - - if (scroll_x!=JX-MIDPOSX && JX>=MIDPOSX-1 && JX<=lev_fieldx-MIDPOSX) - scroll_x = JX-MIDPOSX; - if (scroll_y!=JY-MIDPOSY && JY>=MIDPOSY-1 && JY<=lev_fieldy-MIDPOSY) - scroll_y = JY-MIDPOSY; + MV_UP, + MV_LEFT, + MV_RIGHT, + MV_DOWN + }; - if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y) - ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y); + for (i=0; i<4; i++) + { + int x, y, element; - if (Feld[JX][JY]==EL_LEERRAUM) - DrawLevelElement(JX,JY,EL_SPIELFIGUR); - else - DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR); - } + x = goodx + xy[i][0]; + y = goody + xy[i][1]; + if (!IN_LEV_FIELD(x, y)) + continue; - TestIfHeroHitsBadThing(); + element = Feld[x][y]; - BackToFront(); + if (DONT_TOUCH(element)) + { + if (MovDir[x][y] == harmless[i]) + continue; - if (LevelSolved) - GameWon(); + killx = x; + killy = y; + break; + } + } - return(moved); + if (killx != goodx || killy != goody) + { + if (IS_PLAYER(goodx, goody)) + KillHero(PLAYERINFO(goodx, goody)); + else + Bang(goodx, goody); + } } -void TestIfHeroHitsBadThing() +void TestIfBadThingHitsGoodThing(int badx, int bady) { - int i, killx = JX,killy = JY; + int i, killx = badx, killy = bady; static int xy[4][2] = { - 0,-1, - -1,0, - +1,0, - 0,+1 + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } }; static int harmless[4] = { @@ -1976,20 +3774,26 @@ void TestIfHeroHitsBadThing() MV_DOWN }; - for(i=0;i<4;i++) + for (i=0; i<4; i++) { - int x,y,element; + int x, y, element; - x = JX+xy[i][0]; - y = JY+xy[i][1]; - if (!IN_LEV_FIELD(x,y)) + x = badx + xy[i][0]; + y = bady + xy[i][1]; + if (!IN_LEV_FIELD(x, y)) continue; element = Feld[x][y]; - if (DONT_TOUCH(element)) + if (IS_PLAYER(x, y)) + { + killx = x; + killy = y; + break; + } + else if (element == EL_PINGUIN) { - if (MovDir[x][y]==harmless[i]) + if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y)) continue; killx = x; @@ -1998,118 +3802,195 @@ void TestIfHeroHitsBadThing() } } - if (killx!=JX || killy!=JY) - KillHero(); + if (killx != badx || killy != bady) + { + if (IS_PLAYER(killx, killy)) + KillHero(PLAYERINFO(killx, killy)); + else + Bang(killx, killy); + } +} + +void TestIfHeroHitsBadThing(int x, int y) +{ + TestIfGoodThingHitsBadThing(x, y); +} + +void TestIfBadThingHitsHero(int x, int y) +{ + TestIfBadThingHitsGoodThing(x, y); +} + +void TestIfFriendHitsBadThing(int x, int y) +{ + TestIfGoodThingHitsBadThing(x, y); } -void TestIfBadThingHitsHero() +void TestIfBadThingHitsFriend(int x, int y) { - TestIfHeroHitsBadThing(); + TestIfBadThingHitsGoodThing(x, y); } void TestIfBadThingHitsOtherBadThing(int badx, int bady) { - int i, killx=badx, killy=bady; + int i, killx = badx, killy = bady; static int xy[4][2] = { - 0,-1, - -1,0, - +1,0, - 0,+1 + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } }; - for(i=0;i<4;i++) + for (i=0; i<4; i++) { - int x,y,element; + int x, y, element; - x=badx+xy[i][0]; - y=bady+xy[i][1]; - if (!IN_LEV_FIELD(x,y)) + x=badx + xy[i][0]; + y=bady + xy[i][1]; + if (!IN_LEV_FIELD(x, y)) continue; - element=Feld[x][y]; - if (IS_AMOEBOID(element) || element==EL_LIFE || - element==EL_AMOEBING || element==EL_TROPFEN) + element = Feld[x][y]; + if (IS_AMOEBOID(element) || element == EL_LIFE || + element == EL_AMOEBING || element == EL_TROPFEN) { - killx=x; - killy=y; + killx = x; + killy = y; break; } } - if (killx!=badx || killy!=bady) - Bang(badx,bady); + if (killx != badx || killy != bady) + Bang(badx, bady); } -void KillHero() +void KillHero(struct PlayerInfo *player) { - if (PLAYER(-1,-1)) + int jx = player->jx, jy = player->jy; + + if (player->gone) + return; + + if (IS_PFORTE(Feld[jx][jy])) + Feld[jx][jy] = EL_LEERRAUM; + + Bang(jx, jy); + BuryHero(player); +} + +void BuryHero(struct PlayerInfo *player) +{ + int jx = player->jx, jy = player->jy; + + if (player->gone) return; - if (IS_PFORTE(Feld[JX][JY])) - Feld[JX][JY] = EL_LEERRAUM; + PlaySoundLevel(jx, jy, SND_AUTSCH); + PlaySoundLevel(jx, jy, SND_LACHEN); - PlaySoundLevel(JX,JY,SND_AUTSCH); - PlaySoundLevel(JX,JY,SND_LACHEN); - Bang(JX,JY); - GameOver = TRUE; - JX = JY = -1; + player->GameOver = TRUE; + RemoveHero(player); } -int DigField(int x, int y, int mode) +void RemoveHero(struct PlayerInfo *player) { - int dx=x-JX, dy=y-JY; + int jx = player->jx, jy = player->jy; + int i, found = FALSE; + + player->gone = TRUE; + StorePlayer[jx][jy] = 0; + + for (i=0; ijx, jy = player->jy; + int dx = x - jx, dy = y - jy; int element; - static long push_delay = 0; - static int push_delay_value = 20; - if (mode==DF_NO_PUSH) + if (!player->MovPos) + player->Pushing = FALSE; + + if (mode == DF_NO_PUSH) { - push_delay = 0; - return(MF_NO_ACTION); + player->push_delay = 0; + return MF_NO_ACTION; } - if (IS_MOVING(x,y)) - return(MF_NO_ACTION); + if (IS_MOVING(x, y) || IS_PLAYER(x, y)) + return MF_NO_ACTION; element = Feld[x][y]; switch(element) { case EL_LEERRAUM: - CheckMoving=TRUE; break; + case EL_ERDREICH: - Feld[x][y]=EL_LEERRAUM; - CheckMoving=TRUE; + Feld[x][y] = EL_LEERRAUM; break; + case EL_EDELSTEIN: - Feld[x][y]=EL_LEERRAUM; - CheckMoving=TRUE; - if (Gems>0) - Gems--; - RaiseScore(level.score[SC_EDELSTEIN]); - DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW); - PlaySoundLevel(x,y,SND_PONG); - break; + case EL_EDELSTEIN_BD: + case EL_EDELSTEIN_GELB: + case EL_EDELSTEIN_ROT: + case EL_EDELSTEIN_LILA: case EL_DIAMANT: - Feld[x][y]=EL_LEERRAUM; - CheckMoving=TRUE; - Gems -= 3; - if (Gems<0) - Gems=0; - RaiseScore(level.score[SC_DIAMANT]); - DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW); - PlaySoundLevel(x,y,SND_PONG); + RemoveField(x, y); + local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1); + if (local_player->gems_still_needed < 0) + local_player->gems_still_needed = 0; + RaiseScoreElement(element); + DrawText(DX_EMERALDS, DY_EMERALDS, + int2str(local_player->gems_still_needed, 3), + FS_SMALL, FC_YELLOW); + PlaySoundLevel(x, y, SND_PONG); break; + case EL_DYNAMIT_AUS: - Feld[x][y]=EL_LEERRAUM; - CheckMoving=TRUE; - Dynamite++; - RaiseScore(level.score[SC_DYNAMIT]); - DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW); - PlaySoundLevel(x,y,SND_PONG); + RemoveField(x, y); + player->dynamite++; + RaiseScoreElement(EL_DYNAMIT); + DrawText(DX_DYNAMITE, DY_DYNAMITE, + int2str(local_player->dynamite, 3), + FS_SMALL, FC_YELLOW); + PlaySoundLevel(x, y, SND_PONG); break; + + case EL_DYNABOMB_NR: + RemoveField(x, y); + player->dynabomb_count++; + player->dynabombs_left++; + RaiseScoreElement(EL_DYNAMIT); + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_DYNABOMB_SZ: + RemoveField(x, y); + player->dynabomb_size++; + RaiseScoreElement(EL_DYNAMIT); + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_DYNABOMB_XL: + RemoveField(x, y); + player->dynabomb_xl = TRUE; + RaiseScoreElement(EL_DYNAMIT); + PlaySoundLevel(x, y, SND_PONG); + break; + case EL_SCHLUESSEL1: case EL_SCHLUESSEL2: case EL_SCHLUESSEL3: @@ -2117,363 +3998,373 @@ int DigField(int x, int y, int mode) { int key_nr = element-EL_SCHLUESSEL1; - Feld[x][y] = EL_LEERRAUM; - CheckMoving = TRUE; - Key[key_nr] = TRUE; - RaiseScore(level.score[SC_SCHLUESSEL]); - DrawMiniGraphicExtHiRes(drawto,gc, - DX_KEYS+key_nr*MINI_TILEX,DY_KEYS, - GFX_SCHLUESSEL1+key_nr); - DrawMiniGraphicExtHiRes(window,gc, - DX_KEYS+key_nr*MINI_TILEX,DY_KEYS, - GFX_SCHLUESSEL1+key_nr); - PlaySoundLevel(x,y,SND_PONG); + RemoveField(x, y); + player->key[key_nr] = TRUE; + RaiseScoreElement(EL_SCHLUESSEL); + DrawMiniGraphicExt(drawto, gc, + DX_KEYS+key_nr*MINI_TILEX, DY_KEYS, + GFX_SCHLUESSEL1+key_nr); + DrawMiniGraphicExt(window, gc, + DX_KEYS+key_nr*MINI_TILEX, DY_KEYS, + GFX_SCHLUESSEL1+key_nr); + PlaySoundLevel(x, y, SND_PONG); break; } + case EL_ABLENK_AUS: Feld[x][y] = EL_ABLENK_EIN; - CheckExploding=TRUE; - ZX=x; - ZY=y; - DrawLevelField(x,y); - return(MF_ACTION); + ZX = x; + ZY = y; + DrawLevelField(x, y); + return MF_ACTION; break; + case EL_FELSBROCKEN: case EL_BOMBE: case EL_KOKOSNUSS: case EL_ZEIT_LEER: - if (mode==DF_SNAP) - return(MF_NO_ACTION); - if (dy || !IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy]!=EL_LEERRAUM) - return(MF_NO_ACTION); + if (dy || mode == DF_SNAP) + return MF_NO_ACTION; - if (Counter() > push_delay+4*push_delay_value) - push_delay = Counter(); - if (!DelayReached(&push_delay,push_delay_value) && !tape.playing) - return(MF_NO_ACTION); + player->Pushing = TRUE; - Feld[x][y] = EL_LEERRAUM; + if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy)) + return MF_NO_ACTION; + + if (real_dy) + { + if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy])) + return MF_NO_ACTION; + } + + if (player->push_delay == 0) + player->push_delay = FrameCounter; + if (!FrameReached(&player->push_delay, player->push_delay_value) && + !tape.playing) + return MF_NO_ACTION; + + RemoveField(x, y); Feld[x+dx][y+dy] = element; - push_delay_value = 10+RND(30); - CheckMoving = TRUE; - DrawLevelField(x+dx,y+dy); - if (element==EL_FELSBROCKEN) - PlaySoundLevel(x+dx,y+dy,SND_PUSCH); - else if (element==EL_KOKOSNUSS) - PlaySoundLevel(x+dx,y+dy,SND_KNURK); + + player->push_delay_value = 2+RND(8); + + DrawLevelField(x+dx, y+dy); + if (element == EL_FELSBROCKEN) + PlaySoundLevel(x+dx, y+dy, SND_PUSCH); + else if (element == EL_KOKOSNUSS) + PlaySoundLevel(x+dx, y+dy, SND_KNURK); else - PlaySoundLevel(x+dx,y+dy,SND_KLOPF); + PlaySoundLevel(x+dx, y+dy, SND_KLOPF); break; + case EL_PFORTE1: case EL_PFORTE2: case EL_PFORTE3: case EL_PFORTE4: - if (!Key[element-EL_PFORTE1]) - return(MF_NO_ACTION); + if (!player->key[element-EL_PFORTE1]) + return MF_NO_ACTION; break; + case EL_PFORTE1X: case EL_PFORTE2X: case EL_PFORTE3X: case EL_PFORTE4X: - if (!Key[element-EL_PFORTE1X]) - return(MF_NO_ACTION); + if (!player->key[element-EL_PFORTE1X]) + return MF_NO_ACTION; break; + case EL_AUSGANG_ZU: case EL_AUSGANG_ACT: - /* Tür ist (noch) nicht offen! */ - return(MF_NO_ACTION); + /* door is not (yet) open */ + return MF_NO_ACTION; break; + case EL_AUSGANG_AUF: - if (mode==DF_SNAP || Gems>0) - return(MF_NO_ACTION); - LevelSolved = GameOver = TRUE; - PlaySoundLevel(x,y,SND_BUING); + if (mode == DF_SNAP) + return MF_NO_ACTION; + + PlaySoundLevel(x, y, SND_BUING); + + /* + player->gone = TRUE; + PlaySoundLevel(x, y, SND_BUING); + + if (!local_player->friends_still_needed) + player->LevelSolved = player->GameOver = TRUE; + */ + break; + case EL_BIRNE_AUS: Feld[x][y] = EL_BIRNE_EIN; - DrawLevelField(x,y); - PlaySoundLevel(x,y,SND_DENG); - return(MF_ACTION); + local_player->lights_still_needed--; + DrawLevelField(x, y); + PlaySoundLevel(x, y, SND_DENG); + return MF_ACTION; break; + case EL_ZEIT_VOLL: Feld[x][y] = EL_ZEIT_LEER; - DrawLevelField(x,y); - PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT); - return(MF_ACTION); + TimeLeft += 10; + DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); + DrawLevelField(x, y); + PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); + return MF_ACTION; break; - default: - return(MF_NO_ACTION); + + case EL_SOKOBAN_FELD_LEER: break; - } - push_delay=0; - return(MF_MOVING); -} -BOOL SnapField(int dx, int dy) -{ - int x = JX+dx, y = JY+dy; - static int snapped = FALSE; + case EL_SOKOBAN_FELD_VOLL: + case EL_SOKOBAN_OBJEKT: + case EL_SONDE: + if (mode == DF_SNAP) + return MF_NO_ACTION; - if (GameOver || !IN_LEV_FIELD(x,y)) - return(FALSE); - if (dx && dy) - return(FALSE); - if (!dx && !dy) - { - snapped = FALSE; - return(FALSE); - } - if (snapped) - return(FALSE); + player->Pushing = TRUE; - if (!DigField(x,y,DF_SNAP)) - return(FALSE); + if (!IN_LEV_FIELD(x+dx, y+dy) + || (!IS_FREE(x+dx, y+dy) + && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER + || !IS_SB_ELEMENT(element)))) + return MF_NO_ACTION; - snapped = TRUE; - DrawLevelField(x,y); - BackToFront(); + if (dx && real_dy) + { + if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy])) + return MF_NO_ACTION; + } + else if (dy && real_dx) + { + if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy])) + return MF_NO_ACTION; + } - return(TRUE); -} + if (player->push_delay == 0) + player->push_delay = FrameCounter; + if (!FrameReached(&player->push_delay, player->push_delay_value) && + !tape.playing) + return MF_NO_ACTION; -BOOL PlaceBomb(void) -{ - if (Dynamite==0 || Feld[JX][JY]==EL_DYNAMIT) - return(FALSE); + if (IS_SB_ELEMENT(element)) + { + if (element == EL_SOKOBAN_FELD_VOLL) + { + Feld[x][y] = EL_SOKOBAN_FELD_LEER; + local_player->sokobanfields_still_needed++; + } + else + RemoveField(x, y); - if (Feld[JX][JY]!=EL_LEERRAUM) - Store[JX][JY] = Feld[JX][JY]; - Feld[JX][JY] = EL_DYNAMIT; - MovDelay[JX][JY] = 48; - Dynamite--; - DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW); - DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT); - CheckExploding = TRUE; - return(TRUE); -} + if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER) + { + Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL; + local_player->sokobanfields_still_needed--; + if (element == EL_SOKOBAN_OBJEKT) + PlaySoundLevel(x, y, SND_DENG); + } + else + Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT; + } + else + { + RemoveField(x, y); + Feld[x+dx][y+dy] = element; + } -void PlaySoundLevel(int x, int y, int sound_nr) -{ - int sx = SCROLLX(x), sy = SCROLLY(y); - int volume, stereo; + player->push_delay_value = 2; - if (!sound_loops_on && IS_LOOP_SOUND(sound_nr)) - return; + DrawLevelField(x, y); + DrawLevelField(x+dx, y+dy); + PlaySoundLevel(x+dx, y+dy, SND_PUSCH); - if (!IN_LEV_FIELD(x,y)) - return; + if (IS_SB_ELEMENT(element) && + local_player->sokobanfields_still_needed == 0 && + game_emulation == EMU_SOKOBAN) + { + player->LevelSolved = player->GameOver = TRUE; + PlaySoundLevel(x, y, SND_BUING); + } - volume = PSND_MAX_VOLUME; - stereo = (sx-SCR_FIELDX/2)*12; + break; - if (!IN_SCR_FIELD(sx,sy)) - { - if (sx<0 || sx>=SCR_FIELDX) - volume = PSND_MAX_VOLUME - 2*ABS(sx-SCR_FIELDX/2); - else - volume = PSND_MAX_VOLUME - 2*ABS(sy-SCR_FIELDY/2); + case EL_MAULWURF: + case EL_PINGUIN: + case EL_SCHWEIN: + case EL_DRACHE: + break; + + default: + return MF_NO_ACTION; + break; } - PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP); -} + player->push_delay = 0; -void RaiseScore(int value) -{ - Score += value; - DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW); - BackToFront(); + return MF_MOVING; } -void TapeInitRecording() +boolean SnapField(struct PlayerInfo *player, int dx, int dy) { - time_t zeit1 = time(NULL); - struct tm *zeit2 = localtime(&zeit1); - - if (tape.recording || tape.playing) - return; + int jx = player->jx, jy = player->jy; + int x = jx + dx, y = jy + dy; - tape.level_nr = level_nr; - tape.recording = TRUE; - tape.pausing = TRUE; - tape.date = - 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday; + if (player->gone || !IN_LEV_FIELD(x, y)) + return FALSE; - DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_ON,0); - DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date); - DrawVideoDisplay(VIDEO_STATE_TIME_ON,0); -} - -void TapeStartRecording() -{ - tape.length = 0; - tape.counter = 0; - tape.pos[tape.counter].delay = 0; - tape.recording = TRUE; - tape.playing = FALSE; - tape.pausing = FALSE; - tape.random_seed = InitRND(NEW_RANDOMIZE); - DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_OFF,0); -} + if (dx && dy) + return FALSE; -void TapeStopRecording() -{ - if (!tape.recording) - return; + if (!dx && !dy) + { + player->snapped = FALSE; + return FALSE; + } - tape.length = tape.counter; - tape.recording = FALSE; - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_REC_OFF,0); + if (player->snapped) + return FALSE; - master_tape = tape; -} + player->MovDir = (dx < 0 ? MV_LEFT : + dx > 0 ? MV_RIGHT : + dy < 0 ? MV_UP : + dy > 0 ? MV_DOWN : MV_NO_MOVING); -void TapeRecordAction(int joy) -{ - if (!tape.recording || tape.pausing) - return; + if (!DigField(player, x, y, 0, 0, DF_SNAP)) + return FALSE; - if (tape.counter>=MAX_TAPELEN-1) - { - TapeStopRecording(); - return; - } + player->snapped = TRUE; + DrawLevelField(x, y); + BackToFront(); - if (joy) - { - tape.pos[tape.counter].joystickdata = joy; - tape.counter++; - tape.pos[tape.counter].delay = 0; - } + return TRUE; } -void TapeRecordDelay() +boolean PlaceBomb(struct PlayerInfo *player) { - if (!tape.recording || tape.pausing) - return; + int jx = player->jx, jy = player->jy; + int element; - if (tape.counter>=MAX_TAPELEN) - { - TapeStopRecording(); - return; - } + if (player->gone || player->MovPos) + return FALSE; - tape.pos[tape.counter].delay++; + element = Feld[jx][jy]; - if (tape.pos[tape.counter].delay>=255) - { - tape.pos[tape.counter].joystickdata = 0; - tape.counter++; - tape.pos[tape.counter].delay = 0; - } -} + if ((player->dynamite == 0 && player->dynabombs_left == 0) || + element == EL_DYNAMIT || element == EL_DYNABOMB || + element == EL_EXPLODING) + return FALSE; -void TapeTogglePause() -{ - if (!tape.recording && !tape.playing) - return; + if (element != EL_LEERRAUM) + Store[jx][jy] = element; - if (tape.pausing) + if (player->dynamite) { - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); - if (game_status==MAINMENU) - HandleMainMenu(SX+16,SY+7*32+16,0,0,MB_MENU_CHOICE); + Feld[jx][jy] = EL_DYNAMIT; + MovDelay[jx][jy] = 96; + player->dynamite--; + DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3), + FS_SMALL, FC_YELLOW); + if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) + DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT); } else { - tape.pausing = TRUE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0); + Feld[jx][jy] = EL_DYNABOMB; + Store2[jx][jy] = player->element_nr; /* for DynaExplode() */ + MovDelay[jx][jy] = 96; + player->dynabombs_left--; + if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) + DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB); } -} - -void TapeInitPlaying() -{ - if (tape.recording || tape.playing || TAPE_IS_EMPTY(tape)) - return; - tape.playing = TRUE; - tape.pausing = TRUE; - DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_ON,0); - DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date); - DrawVideoDisplay(VIDEO_STATE_TIME_ON,0); + return TRUE; } -void TapeStartPlaying() +void PlaySoundLevel(int x, int y, int sound_nr) { - tape = master_tape; + int sx = SCREENX(x), sy = SCREENY(y); + int volume, stereo; + int silence_distance = 8; - tape.counter = 0; - tape.recording = FALSE; - tape.playing = TRUE; - tape.pausing = FALSE; - InitRND(tape.random_seed); - DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_OFF,0); -} + if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) || + (!setup.sound_loops && IS_LOOP_SOUND(sound_nr))) + return; -void TapeStopPlaying() -{ - if (!tape.playing) + if (!IN_LEV_FIELD(x, y) || + sx < -silence_distance || sx >= SCR_FIELDX+silence_distance || + sy < -silence_distance || sy >= SCR_FIELDY+silence_distance) return; - tape.playing = FALSE; - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PLAY_OFF,0); -} + volume = PSND_MAX_VOLUME; -int TapePlayAction() -{ - if (!tape.playing || tape.pausing) - return(0); +#ifndef MSDOS + stereo = (sx-SCR_FIELDX/2)*12; +#else + stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5; + if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT; + if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT; +#endif - if (tape.counter>=tape.length) + if (!IN_SCR_FIELD(sx, sy)) { - TapeStopPlaying(); - return(0); - } + int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2; + int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2; - if (!tape.pos[tape.counter].delay) - { - tape.counter++; - return(tape.pos[tape.counter-1].joystickdata); + volume -= volume*(dx > dy ? dx : dy)/silence_distance; } - else - return(0); + + PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP); } -BOOL TapePlayDelay() +void RaiseScore(int value) { - if (!tape.playing || tape.pausing) - return(0); - - if (tape.counter>=tape.length) - { - TapeStopPlaying(); - return(TRUE); - } - - if (tape.pos[tape.counter].delay) - { - tape.pos[tape.counter].delay--; - return(TRUE); - } - else - return(FALSE); + local_player->score += value; + DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5), + FS_SMALL, FC_YELLOW); } -void TapeStop() +void RaiseScoreElement(int element) { - TapeStopRecording(); - TapeStopPlaying(); - DrawVideoDisplay(VIDEO_ALL_OFF,0); - if (tape.date && tape.length) + switch(element) { - DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date); - DrawVideoDisplay(VIDEO_STATE_TIME_ON,0); + case EL_EDELSTEIN: + case EL_EDELSTEIN_BD: + case EL_EDELSTEIN_GELB: + case EL_EDELSTEIN_ROT: + case EL_EDELSTEIN_LILA: + RaiseScore(level.score[SC_EDELSTEIN]); + break; + case EL_DIAMANT: + RaiseScore(level.score[SC_DIAMANT]); + break; + case EL_KAEFER: + case EL_BUTTERFLY: + RaiseScore(level.score[SC_KAEFER]); + break; + case EL_FLIEGER: + case EL_FIREFLY: + RaiseScore(level.score[SC_FLIEGER]); + break; + case EL_MAMPFER: + case EL_MAMPFER2: + RaiseScore(level.score[SC_MAMPFER]); + break; + case EL_ROBOT: + RaiseScore(level.score[SC_ROBOT]); + break; + case EL_PACMAN: + RaiseScore(level.score[SC_PACMAN]); + break; + case EL_KOKOSNUSS: + RaiseScore(level.score[SC_KOKOSNUSS]); + break; + case EL_DYNAMIT: + RaiseScore(level.score[SC_DYNAMIT]); + break; + case EL_SCHLUESSEL: + RaiseScore(level.score[SC_SCHLUESSEL]); + break; + default: + break; } } - -void TapeErase() -{ - tape.length = 0; -} diff --git a/src/game.h b/src/game.h index e7150b6b..4834b796 100644 --- a/src/game.h +++ b/src/game.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * game.h * ***********************************************************/ @@ -17,20 +16,12 @@ #include "main.h" -#define DF_DIG 0 -#define DF_SNAP 1 -#define DF_NO_PUSH 2 - -#define MF_NO_ACTION 0 -#define MF_MOVING 1 -#define MF_ACTION 2 - void GetPlayerConfig(void); void InitGame(void); void InitMovDir(int, int); void InitAmoebaNr(int, int); void GameWon(void); -BOOL NewHiScore(void); +boolean NewHiScore(void); void InitMovingField(int, int, int); void Moving2Blocked(int, int, int *, int *); void Blocked2Moving(int, int, int *, int *); @@ -38,7 +29,8 @@ int MovingOrBlocked2Element(int, int); void RemoveMovingField(int, int); void DrawDynamite(int, int); void CheckDynamite(int, int); -void Explode(int, int, int); +void Explode(int, int, int, int); +void DynaExplode(int, int); void Bang(int, int); void Blurb(int, int); void Impact(int, int); @@ -47,39 +39,43 @@ void StartMoving(int, int); void ContinueMoving(int, int); int AmoebeNachbarNr(int, int); void AmoebeUmwandeln(int, int); +void AmoebeUmwandeln2(int, int, int); void AmoebeWaechst(int, int); void AmoebeAbleger(int, int); void Life(int, int); void Ablenk(int, int); void Blubber(int, int); void NussKnacken(int, int); -void SiebAktivieren(int x, int y); -void AusgangstuerPruefen(int x, int y); -void AusgangstuerOeffnen(int x, int y); -int GameActions(int, int, int); +void SiebAktivieren(int, int, int); +void AusgangstuerPruefen(int, int); +void AusgangstuerOeffnen(int, int); +void AusgangstuerBlinken(int, int); +void EdelsteinFunkeln(int, int); +void MauerWaechst(int, int); +void MauerAbleger(int, int); +void GameActions(void); void ScrollLevel(int, int); -BOOL MoveFigure(int, int); -void TestIfHeroHitsBadThing(void); -void TestIfBadThingHitsHero(void); + +boolean MoveFigureOneStep(struct PlayerInfo *, int, int, int, int); +boolean MoveFigure(struct PlayerInfo *, int, int); +void ScrollFigure(struct PlayerInfo *, int); +void ScrollScreen(struct PlayerInfo *, int); + +void TestIfGoodThingHitsBadThing(int, int); +void TestIfBadThingHitsGoodThing(int, int); +void TestIfHeroHitsBadThing(int, int); +void TestIfBadThingHitsHero(int, int); +void TestIfFriendHitsBadThing(int, int); +void TestIfBadThingHitsFriend(int, int); void TestIfBadThingHitsOtherBadThing(int, int); -void KillHero(void); -int DigField(int, int, int); -BOOL SnapField(int, int); -BOOL PlaceBomb(void); +void KillHero(struct PlayerInfo *); +void BuryHero(struct PlayerInfo *); +void RemoveHero(struct PlayerInfo *); +int DigField(struct PlayerInfo *, int, int, int, int, int); +boolean SnapField(struct PlayerInfo *, int, int); +boolean PlaceBomb(struct PlayerInfo *); void PlaySoundLevel(int, int, int); void RaiseScore(int); -void TapeInitRecording(void); -void TapeStartRecording(void); -void TapeStopRecording(void); -void TapeRecordAction(int); -void TapeRecordDelay(void); -void TapeTogglePause(void); -void TapeInitPlaying(void); -void TapeStartPlaying(void); -void TapeStopPlaying(void); -int TapePlayAction(void); -BOOL TapePlayDelay(void); -void TapeStop(void); -void TapeErase(void); +void RaiseScoreElement(int); #endif diff --git a/src/image.c b/src/image.c new file mode 100644 index 00000000..09a75fce --- /dev/null +++ b/src/image.c @@ -0,0 +1,554 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* image.c * +***********************************************************/ + +#include "image.h" +#include "pcx.h" +#include "misc.h" + +/* exclude all except newImage() and freeImage() */ +#ifndef MSDOS + +/* extra colors to try allocating in private color maps to minimize flashing */ +#define NOFLASH_COLORS 256 + +/* architecture independent value-to-memory conversion + note: the internal format is big endian */ + +#define value_to_memory(value, ptr, length) ( \ +(length) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ +(length) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+1) = ( value ) ) : \ +(length) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+2) = ( value ) ) : \ + (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+3) = ( value ) )) + +static Pixmap Image_to_Mask(Image *image, Display *display, Window window) +{ + byte *src_ptr, *dst_ptr, *dst_ptr2; + unsigned int bytes_per_row; + unsigned int x, y; + byte bitmask; + byte *mask_data; + Pixmap mask_pixmap; + + bytes_per_row = (image->width + 7) / 8; + mask_data = checked_calloc(bytes_per_row * image->height); + + src_ptr = image->data; + dst_ptr = mask_data; + + /* create bitmap data which can be used by 'XCreateBitmapFromData()' + * directly to create a pixmap of depth 1 for use as a clip mask for + * the corresponding image pixmap + */ + + for (y=0; yheight; y++) + { + bitmask = 0x01; /* start with leftmost bit in the byte */ + dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ + + for (x=0; xwidth; x++) + { + if (*src_ptr++) /* source pixel solid? (pixel index != 0) */ + *dst_ptr2 |= bitmask; /* then write a bit into the image mask */ + + if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */ + { + bitmask = 0x01; /* start again with leftmost bit position */ + dst_ptr2++; /* continue with next byte in image mask */ + } + } + + dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */ + } + + mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data, + image->width, image->height); + free(mask_data); + + return mask_pixmap; +} + +static int bitsPerPixelAtDepth(Display *display, int screen, int depth) +{ + XPixmapFormatValues *pixmap_format; + int i, num_pixmap_formats, bits_per_pixel = -1; + + /* get Pixmap formats supported by the X server */ + pixmap_format = XListPixmapFormats(display, &num_pixmap_formats); + + /* find format that matches the given depth */ + for (i=0; idisplay = display; + ximageinfo->depth = depth; + + switch (visual->class) + { + case TrueColor: + case DirectColor: + { + Pixel pixval; + unsigned int redcolors, greencolors, bluecolors; + unsigned int redstep, greenstep, bluestep; + unsigned int redbottom, greenbottom, bluebottom; + unsigned int redtop, greentop, bluetop; + + redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); + greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); + bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); + + ximageinfo->cmap = global_cmap; + + retry_direct: /* tag we hit if a DirectColor allocation fails on + * default colormap */ + + /* calculate number of distinct colors in each band */ + + redcolors = greencolors = bluecolors = 1; + for (pixval=1; pixval; pixval <<= 1) + { + if (pixval & visual->red_mask) + redcolors <<= 1; + if (pixval & visual->green_mask) + greencolors <<= 1; + if (pixval & visual->blue_mask) + bluecolors <<= 1; + } + + /* consistency check */ + if (redcolors > visual->map_entries || + greencolors > visual->map_entries || + bluecolors > visual->map_entries) + Error(ERR_WARN, "inconsistency in color information"); + + redstep = 256 / redcolors; + greenstep = 256 / greencolors; + bluestep = 256 / bluecolors; + redbottom = greenbottom = bluebottom = 0; + redtop = greentop = bluetop = 0; + for (a=0; amap_entries; a++) + { + if (redbottom < 256) + redtop = redbottom + redstep; + if (greenbottom < 256) + greentop = greenbottom + greenstep; + if (bluebottom < 256) + bluetop = bluebottom + bluestep; + + xcolor.red = (redtop - 1) << 8; + xcolor.green = (greentop - 1) << 8; + xcolor.blue = (bluetop - 1) << 8; + if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) + { + /* if an allocation fails for a DirectColor default visual then + we should create a private colormap and try again. */ + + if ((visual->class == DirectColor) && + (visual == DefaultVisual(display, screen))) + { + global_cmap = XCopyColormapAndFree(display, global_cmap); + ximageinfo->cmap = global_cmap; + private_cmap = TRUE; + + goto retry_direct; + } + + /* something completely unexpected happened */ + + fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n"); + free(redvalue); + free(greenvalue); + free(bluevalue); + free(ximageinfo); + return NULL; + } + + /* fill in pixel values for each band at this intensity */ + + while ((redbottom < 256) && (redbottom < redtop)) + redvalue[redbottom++] = xcolor.pixel & visual->red_mask; + while ((greenbottom < 256) && (greenbottom < greentop)) + greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask; + while ((bluebottom < 256) && (bluebottom < bluetop)) + bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask; + } + break; + } + + case PseudoColor: + + ximageinfo->cmap = global_cmap; + + for (a=0; argb.color_used[a]) + continue; + + xcolor.red = *(image->rgb.red + a); + xcolor.green = *(image->rgb.green + a); + xcolor.blue = *(image->rgb.blue + a); + + /* look if this color already exists in our colormap */ + if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) + { + if (!private_cmap) + { + if (options.verbose) + Error(ERR_RETURN, "switching to private colormap"); + + /* we just filled up the default colormap -- get a private one + which contains all already allocated colors */ + + global_cmap = XCopyColormapAndFree(display, global_cmap); + ximageinfo->cmap = global_cmap; + private_cmap = TRUE; + + /* allocate the rest of the color cells read/write */ + global_cmap_index = + (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS); + for (i=0; i=0; i--) + { + xcolor2.pixel = *(global_cmap_index + i); + xcolor2 = xcolor_private[xcolor2.pixel]; + + if (colorcell_used[xcolor2.pixel]) + continue; + + if ((xcolor.red & mask) == (xcolor2.red & mask) && + (xcolor.green & mask) == (xcolor2.green & mask) && + (xcolor.blue & mask) == (xcolor2.blue & mask)) + { + /* + printf("replacing color cell %ld with a close color\n", + xcolor2.pixel); + */ + color_found = TRUE; + break; + } + } + + if (mask == 0x0000) + break; + + mask = (mask << 1) & 0xffff; + } + + if (!color_found) /* no more free color cells */ + Error(ERR_EXIT, "cannot allocate enough color cells"); + + xcolor.pixel = xcolor2.pixel; + xcolor_private[xcolor.pixel] = xcolor; + colorcell_used[xcolor.pixel] = TRUE; + XStoreColor(display, ximageinfo->cmap, &xcolor); + free_cmap_entries--; + } + + *(ximageinfo->index + a) = xcolor.pixel; + } + + /* + printf("still %d free colormap entries\n", free_cmap_entries); + */ + + ximageinfo->no = a; /* number of pixels allocated for this image */ + break; + + default: + Error(ERR_RETURN, "display class not supported"); + Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed"); + break; + } + +#if DEBUG_TIMING + debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: "); +#endif + + /* create XImage from internal image structure and convert it to Pixmap */ + + bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth); + bytes_per_pixel = (bits_per_pixel + 7) / 8; + + ximage = XCreateImage(display, visual, depth, ZPixmap, 0, + NULL, image->width, image->height, + 8, image->width * bytes_per_pixel); + ximage->data = + checked_malloc(image->width * image->height * bytes_per_pixel); + ximage->byte_order = MSBFirst; + + src_ptr = image->data; + dst_ptr = (byte *)ximage->data; + + switch (visual->class) + { + case DirectColor: + case TrueColor: + { + Pixel pixval; + + for (y=0; yheight; y++) /* general case */ + { + for (x=0; xwidth; x++) + { + pixval = *src_ptr++; + pixval = + redvalue[image->rgb.red[pixval] >> 8] | + greenvalue[image->rgb.green[pixval] >> 8] | + bluevalue[image->rgb.blue[pixval] >> 8]; + value_to_memory(pixval, dst_ptr, bytes_per_pixel); + dst_ptr += bytes_per_pixel; + } + } + break; + } + + case PseudoColor: + { + if (bytes_per_pixel == 1) /* (common) special case */ + { + for (y=0; yheight; y++) + for (x=0; xwidth; x++) + *dst_ptr++ = ximageinfo->index[c + *src_ptr++]; + } + else /* general case */ + { + for (y=0; yheight; y++) + { + for (x=0; xwidth; x++) + { + value_to_memory(ximageinfo->index[c + *src_ptr++], + dst_ptr, bytes_per_pixel); + dst_ptr += bytes_per_pixel; + } + } + } + break; + } + + default: + Error(ERR_RETURN, "display class not supported"); + Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed"); + break; + } + + if (redvalue) + { + free((byte *)redvalue); + free((byte *)greenvalue); + free((byte *)bluevalue); + } + +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:"); +#endif + + ximageinfo->pixmap = XCreatePixmap(display, window, + ximage->width, ximage->height, + ximageinfo->depth); + + XPutImage(ximageinfo->display, ximageinfo->pixmap, gc, + ximage, 0, 0, 0, 0, ximage->width, ximage->height); + + free(ximage->data); + ximage->data = NULL; + XDestroyImage(ximage); + + return(ximageinfo); +} + +void freeXImage(Image *image, XImageInfo *ximageinfo) +{ + if (ximageinfo->index != NULL && ximageinfo->no > 0) + XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index, + ximageinfo->no, 0); + /* this ^^^^^^^^^^^^^^ is wrong, because the used color cells + * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no' + * used color cells, but they are not at array position 0 - 'ximageinfo->no' + */ + + free(ximageinfo); +} + +#endif /* !MSDOS */ + +Image *newImage(unsigned int width, unsigned int height, unsigned int depth) +{ + Image *image; + const unsigned int bytes_per_pixel = 1; + int i; + + if (depth > 8) + Error(ERR_EXIT, "images with more than 256 colors are not supported"); + + depth = 8; + image = checked_malloc(sizeof(Image)); + image->data = checked_malloc(width * height * bytes_per_pixel); + image->width = width; + image->height = height; + image->depth = depth; + image->rgb.used = 0; + for (i=0; irgb.color_used[i] = FALSE; + + return image; +} + +void freeImage(Image *image) +{ + free(image->data); + free(image); +} + +#ifndef MSDOS + +int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, + Pixmap *pixmap, Pixmap *pixmap_mask) +{ + Image *image; + XImageInfo *ximageinfo; + int screen; + Visual *visual; + int depth; + +#if DEBUG_TIMING + debug_print_timestamp(2, NULL); /* initialize timestamp function */ +#endif + + /* read the graphic file in PCX format to image structure */ + if ((image = Read_PCX_to_Image(filename)) == NULL) + return PCX_FileInvalid; + +#if DEBUG_TIMING + printf("%s:\n", filename); + debug_print_timestamp(2, " READING PCX FILE TO IMAGE: "); +#endif + + screen = DefaultScreen(display); + visual = DefaultVisual(display, screen); + depth = DefaultDepth(display, screen); + + /* convert image structure to X11 Pixmap */ + if (!(ximageinfo = Image_to_Pixmap(display, screen, visual, + window, gc, depth, image))) + Error(ERR_EXIT, "cannot convert Image to Pixmap"); + + /* if a private colormap has been created, install it */ + if (ximageinfo->cmap != DefaultColormap(display, screen)) + XSetWindowColormap(display, window, ximageinfo->cmap); + +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:"); +#endif + + /* create clip mask for the image */ + ximageinfo->pixmap_mask = Image_to_Mask(image, display, window); + +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: "); +#endif + + *pixmap = ximageinfo->pixmap; + *pixmap_mask = ximageinfo->pixmap_mask; + + return(PCX_Success); +} + +#endif /* !MSDOS */ diff --git a/src/image.h b/src/image.h new file mode 100644 index 00000000..6315340e --- /dev/null +++ b/src/image.h @@ -0,0 +1,58 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* image.h * +***********************************************************/ + +#ifndef IMAGE_H +#define IMAGE_H + +#include "main.h" + +#define MAX_COLORS 256 /* maximal number of colors for each image */ + +typedef unsigned short Intensity; /* RGB intensity for X11 */ + +typedef struct +{ + Display *display; /* destination display */ + int depth; /* depth of destination drawable */ + Pixel index[MAX_COLORS]; /* array of pixel values */ + int no; /* number of pixels in the array */ + Colormap cmap; /* colormap used for image */ + Pixmap pixmap; /* final pixmap */ + Pixmap pixmap_mask; /* final pixmap of mask */ +} XImageInfo; + +struct RGBMap +{ + unsigned int used; /* number of colors used in RGB map */ + Intensity red[MAX_COLORS]; /* color values in X style */ + Intensity green[MAX_COLORS]; + Intensity blue[MAX_COLORS]; + boolean color_used[MAX_COLORS]; /* flag if color cell is used */ +}; + +typedef struct +{ + struct RGBMap rgb; /* RGB map of image if IRGB type */ + unsigned int width; /* width of image in pixels */ + unsigned int height; /* height of image in pixels */ + unsigned int depth; /* depth of image in bits if IRGB type */ + byte *data; /* image data */ +} Image; + +int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *); + +Image *newImage(unsigned int, unsigned int, unsigned int); +void freeImage(Image *); +void freeXImage(Image *, XImageInfo *); + +#endif /* IMAGE_H */ diff --git a/src/init.c b/src/init.c index 8032ffb3..bc72b99a 100644 --- a/src/init.c +++ b/src/init.c @@ -1,251 +1,421 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * init.c * ***********************************************************/ +#include + #include "init.h" #include "misc.h" #include "sound.h" #include "screens.h" +#include "tools.h" #include "files.h" -#include +#include "joystick.h" +#include "image.h" +#include "pcx.h" +#include "network.h" +#include "netserv.h" + +struct PictureFileInfo +{ + char *picture_filename; + boolean picture_with_mask; +}; + +struct IconFileInfo +{ + char *picture_filename; + char *picturemask_filename; +}; static int sound_process_id = 0; +static void InitLevelAndPlayerInfo(void); +static void InitNetworkServer(void); +static void InitDisplay(void); +static void InitSound(void); +static void InitSoundServer(void); +static void InitWindow(int, char **); +static void InitGfx(void); +static void LoadGfx(int, struct PictureFileInfo *); +static void InitElementProperties(void); + void OpenAll(int argc, char *argv[]) { + if (options.serveronly) + { + NetworkServer(options.server_port, options.serveronly); + + /* never reached */ + exit(0); + } + InitLevelAndPlayerInfo(); InitCounter(); InitSound(); - InitSoundProcess(); - InitJoystick(); + InitSoundServer(); + InitJoysticks(); InitRND(NEW_RANDOMIZE); - signal(SIGINT, CloseAll); - signal(SIGTERM, CloseAll); + signal(SIGINT, CloseAllAndExit); + signal(SIGTERM, CloseAllAndExit); - InitDisplay(argc, argv); + InitDisplay(); InitWindow(argc, argv); + + XMapWindow(display, window); + XFlush(display); + InitGfx(); InitElementProperties(); DrawMainMenu(); - XMapWindow(display, window); - XFlush(display); + InitNetworkServer(); } void InitLevelAndPlayerInfo() { - if (!LoadLevelInfo()) /* global level info */ - CloseAll(); + int i; - LoadPlayerInfo(PLAYER_SETUP); /* global setup info */ - LoadPlayerInfo(PLAYER_LEVEL); /* level specific info */ + /* choose default local player */ + local_player = &stored_player[0]; + + for (i=0; iconnected = TRUE; + + LoadLevelInfo(); /* global level info */ + LoadSetup(); /* global setup info */ + LoadLevelSetup(); /* info about last played level */ +} + +void InitNetworkServer() +{ +#ifndef MSDOS + int nr_wanted; +#endif + + if (!options.network) + return; + +#ifndef MSDOS + nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED); + + if (!ConnectToServer(options.server_host, options.server_port)) + Error(ERR_EXIT, "cannot connect to network game server"); + + SendToServer_PlayerName(setup.player_name); + SendToServer_ProtocolVersion(); + + if (nr_wanted) + SendToServer_NrWanted(nr_wanted); +#endif } void InitSound() { int i; - if (sound_status==SOUND_OFF) + if (sound_status == SOUND_OFF) return; - if (access(sound_device_name,W_OK)<0) +#ifndef MSDOS + if (access(sound_device_name, W_OK) != 0) { - fprintf(stderr,"%s: cannot access sound device - no sounds\n",progname); - sound_status=SOUND_OFF; + Error(ERR_WARN, "cannot access sound device - no sounds"); + sound_status = SOUND_OFF; return; } - if ((sound_device=open(sound_device_name,O_WRONLY))<0) + if ((sound_device = open(sound_device_name,O_WRONLY))<0) { - fprintf(stderr,"%s: cannot open sound device - no sounds\n",progname); - sound_status=SOUND_OFF; + Error(ERR_WARN, "cannot open sound device - no sounds"); + sound_status = SOUND_OFF; return; } close(sound_device); - sound_status=SOUND_AVAILABLE; + sound_status = SOUND_AVAILABLE; #ifdef VOXWARE sound_loops_allowed = TRUE; - sound_loops_on = TRUE; + + /* + setup.sound_loops_on = TRUE; + */ + #endif +#else /* MSDOS */ + sound_loops_allowed = TRUE; + + /* + setup.sound_loops_on = TRUE; + */ - for(i=0;i= num_joysticks) + joystick_nr = -1; + + /* misuse joystick file descriptor variable to store joystick number */ + stored_player[i].joystick_fd = joystick_nr; + } +#endif } -void InitDisplay(int argc, char *argv[]) +void InitDisplay() { - char *display_name = NULL; - int i; +#ifndef MSDOS + XVisualInfo vinfo_template, *vinfo; + int num_visuals; +#endif + unsigned int depth; - /* get X server to connect to, if given as an argument */ - for (i=1;ivisual; + XFree((void *)vinfo); } - /* connect to X server */ - if (!(display=XOpenDisplay(display_name))) + /* got appropriate visual? */ + if (depth < 8) { - fprintf(stderr,"%s: cannot connect to X server %s\n", - progname, XDisplayName(display_name)); + printf("Sorry, displays with less than 8 bits per pixel not supported.\n"); exit(-1); } - - screen = DefaultScreen(display); - cmap = DefaultColormap(display, screen); - pen_fg = WhitePixel(display,screen); - pen_bg = BlackPixel(display,screen); + else if ((depth ==8 && visual->class != PseudoColor) || + (depth > 8 && visual->class != TrueColor && + visual->class != DirectColor)) + { + printf("Sorry, cannot get appropriate visual.\n"); + exit(-1); + } +#endif } void InitWindow(int argc, char *argv[]) { unsigned int border_width = 4; + XGCValues gc_values; + unsigned long gc_valuemask; +#ifndef MSDOS + XTextProperty windowName, iconName; Pixmap icon_pixmap, iconmask_pixmap; - unsigned int icon_width,icon_height; - int icon_hot_x,icon_hot_y; + unsigned int icon_width, icon_height; + int icon_hot_x, icon_hot_y; char icon_filename[256]; XSizeHints size_hints; XWMHints wm_hints; XClassHint class_hints; - XTextProperty windowName, iconName; - XGCValues gc_values; - unsigned long gc_valuemask; - char *window_name = "Rocks'n'Diamonds"; - char *icon_name = "Rocks'n'Diamonds"; + char *window_name = WINDOWTITLE_STRING; + char *icon_name = WINDOWTITLE_STRING; long window_event_mask; - static struct PictureFile icon_pic = + Atom proto_atom = None, delete_atom = None; +#endif + int screen_width, screen_height; + int win_xpos = WIN_XPOS, win_ypos = WIN_YPOS; + unsigned long pen_fg = WhitePixel(display,screen); + unsigned long pen_bg = BlackPixel(display,screen); + const int width = WIN_XSIZE, height = WIN_YSIZE; + +#ifndef MSDOS + static struct IconFileInfo icon_pic = { "rocks_icon.xbm", "rocks_iconmask.xbm" }; +#endif - width = WIN_XSIZE; - height = WIN_YSIZE; + screen_width = XDisplayWidth(display, screen); + screen_height = XDisplayHeight(display, screen); - window = XCreateSimpleWindow(display, RootWindow(display, screen), - WIN_XPOS, WIN_YPOS, width, height, border_width, - pen_fg, pen_bg); + win_xpos = (screen_width - width) / 2; + win_ypos = (screen_height - height) / 2; - sprintf(icon_filename,"%s/%s",GFX_PATH,icon_pic.picture_filename); + window = XCreateSimpleWindow(display, RootWindow(display, screen), + win_xpos, win_ypos, width, height, border_width, + pen_fg, pen_bg); + +#ifndef MSDOS + proto_atom = XInternAtom(display, "WM_PROTOCOLS", FALSE); + delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", FALSE); + if ((proto_atom != None) && (delete_atom != None)) + XChangeProperty(display, window, proto_atom, XA_ATOM, 32, + PropModePrepend, (unsigned char *) &delete_atom, 1); + + sprintf(icon_filename, "%s/%s/%s", + options.base_directory, GRAPHICS_DIRECTORY, + icon_pic.picture_filename); XReadBitmapFile(display,window,icon_filename, &icon_width,&icon_height, &icon_pixmap,&icon_hot_x,&icon_hot_y); if (!icon_pixmap) - { - fprintf(stderr, "%s: cannot read icon bitmap file '%s'.\n", - progname,icon_filename); - exit(-1); - } + Error(ERR_EXIT, "cannot read icon bitmap file '%s'", icon_filename); - sprintf(icon_filename,"%s/%s",GFX_PATH,icon_pic.picturemask_filename); + sprintf(icon_filename, "%s/%s/%s", + options.base_directory, GRAPHICS_DIRECTORY, + icon_pic.picturemask_filename); XReadBitmapFile(display,window,icon_filename, &icon_width,&icon_height, &iconmask_pixmap,&icon_hot_x,&icon_hot_y); if (!iconmask_pixmap) - { - fprintf(stderr, "%s: cannot read icon bitmap file '%s'.\n", - progname,icon_filename); - exit(-1); - } + Error(ERR_EXIT, "cannot read icon bitmap file '%s'", icon_filename); - size_hints.flags = PSize | PMinSize | PMaxSize; size_hints.width = size_hints.min_width = size_hints.max_width = width; size_hints.height = size_hints.min_height = size_hints.max_height = height; + size_hints.flags = PSize | PMinSize | PMaxSize; - if (!XStringListToTextProperty(&window_name, 1, &windowName)) + if (win_xpos || win_ypos) { - fprintf(stderr, "%s: structure allocation for windowName failed.\n", - progname); - exit(-1); + size_hints.x = win_xpos; + size_hints.y = win_ypos; + size_hints.flags |= PPosition; } + if (!XStringListToTextProperty(&window_name, 1, &windowName)) + Error(ERR_EXIT, "structure allocation for windowName failed"); + if (!XStringListToTextProperty(&icon_name, 1, &iconName)) - { - fprintf(stderr, "%s: structure allocation for iconName failed.\n", - progname); - exit(-1); - } + Error(ERR_EXIT, "structure allocation for iconName failed"); wm_hints.initial_state = NormalState; wm_hints.input = True; @@ -253,7 +423,7 @@ void InitWindow(int argc, char *argv[]) wm_hints.icon_mask = iconmask_pixmap; wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint; - class_hints.res_name = progname; + class_hints.res_name = program_name; class_hints.res_class = "Rocks'n'Diamonds"; XSetWMProperties(display, window, &windowName, &iconName, @@ -268,6 +438,7 @@ void InitWindow(int argc, char *argv[]) ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | KeyPressMask | KeyReleaseMask; XSelectInput(display, window, window_event_mask); +#endif /* create GC for drawing with window depth */ gc_values.graphics_exposures = False; @@ -277,105 +448,107 @@ void InitWindow(int argc, char *argv[]) gc = XCreateGC(display, window, gc_valuemask, &gc_values); } +void DrawInitText(char *text, int ypos, int color) +{ + if (display && window && pix[PIX_SMALLFONT]) + { + XFillRectangle(display,window,gc,0,ypos, WIN_XSIZE,FONT2_YSIZE); + DrawTextExt(window,gc,(WIN_XSIZE-strlen(text)*FONT2_XSIZE)/2, + ypos,text,FS_SMALL,color); + XFlush(display); + } +} + void InitGfx() { - int i,j,x,y; - int xpm_err, xbm_err; - unsigned int width,height; - int hot_x,hot_y; - XGCValues gc_values; - unsigned long gc_valuemask; + int i,j; + GC copy_clipmask_gc; XGCValues clip_gc_values; unsigned long clip_gc_valuemask; - char filename[256]; - Pixmap shapemask; - static struct PictureFile pic[NUM_PICTURES] = +#ifdef MSDOS + static struct PictureFileInfo pic[NUM_PICTURES] = { - "RocksScreen.xpm", "RocksScreenMaske.xbm", - "RocksDoor.xpm", "RocksDoorMaske.xbm", - "RocksToons.xpm", "RocksToonsMaske.xbm", - "RocksFont.xpm", NULL, - "RocksFont2.xpm", NULL + { "Screen", TRUE }, + { "Door", TRUE }, + { "Heroes", TRUE }, + { "Toons", TRUE }, + { "Font", FALSE }, + { "Font2", FALSE } }; - - for(i=0;i=0; i++) + { + for(j=0; j= GFX_START_ROCKSSCREEN && + graphic <= GFX_END_ROCKSSCREEN) + { + src_pixmap = clipmask[PIX_BACK]; + graphic -= GFX_START_ROCKSSCREEN; + src_x = SX + (graphic % GFX_PER_LINE) * TILEX; + src_y = SY + (graphic / GFX_PER_LINE) * TILEY; + } + else if (graphic >= GFX_START_ROCKSHEROES && + graphic <= GFX_END_ROCKSHEROES) + { + src_pixmap = clipmask[PIX_HEROES]; + graphic -= GFX_START_ROCKSHEROES; + src_x = (graphic % HEROES_PER_LINE) * TILEX; + src_y = (graphic / HEROES_PER_LINE) * TILEY; + } + else if (graphic >= GFX_START_ROCKSFONT && + graphic <= GFX_END_ROCKSFONT) + { + src_pixmap = clipmask[PIX_BIGFONT]; + graphic -= GFX_START_ROCKSFONT; + src_x = (graphic % FONT_CHARS_PER_LINE) * TILEX; + src_y = (graphic / FONT_CHARS_PER_LINE) * TILEY + + FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY; + } + else + break; - if (!pix[PIX_DB_BACK] || !pix[PIX_DB_DOOR] || !clipmask[PIX_FADEMASK]) - { - fprintf(stderr, "%s: cannot create additional Pixmaps!\n",progname); - CloseAll(); - exit(-1); - } + tile_clipmask[tile] = XCreatePixmap(display, window, TILEX,TILEY, 1); - /* create GC for drawing with bitplane depth */ - gc_values.graphics_exposures = False; - gc_values.foreground = pen_bg; - gc_values.background = pen_bg; - gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground; - plane_gc = XCreateGC(display, clipmask[PIX_BACK], gc_valuemask, &gc_values); + XCopyArea(display,src_pixmap,tile_clipmask[tile],copy_clipmask_gc, + src_x,src_y, TILEX,TILEY, 0,0); + } + } - for(y=0;y<=SCR_FIELDY;y++) for(x=0;x<=SCR_FIELDX;x++) - XCopyArea(display,clipmask[PIX_BACK],clipmask[PIX_FADEMASK],plane_gc, - SX+2*TILEX,SY+10*TILEY,TILEX,TILEY,x*TILEX,y*TILEY); + if (!pix[PIX_DB_BACK] || !pix[PIX_DB_DOOR]) + Error(ERR_EXIT, "cannot create additional pixmaps"); - for(i=0;ipicture_filename) + { + sprintf(basefilename, "%s%s", pic->picture_filename, picture_ext); + DrawInitText(basefilename, 150, FC_YELLOW); + sprintf(filename, "%s/%s/%s", + options.base_directory, GRAPHICS_DIRECTORY, basefilename); + +#ifdef MSDOS + rest(100); +#endif /* MSDOS */ + +#if DEBUG_TIMING + debug_print_timestamp(1, NULL); /* initialize timestamp function */ +#endif + +#ifdef USE_XPM_LIBRARY + + xpm_att[pos].valuemask = XpmCloseness; + xpm_att[pos].closeness = 20000; + xpm_err = XpmReadFileToPixmap(display,window,filename, + &pix[pos],&shapemask,&xpm_att[pos]); + switch(xpm_err) + { + case XpmOpenFailed: + Error(ERR_EXIT, "cannot open XPM file '%s'", filename); + case XpmFileInvalid: + Error(ERR_EXIT, "invalid XPM file '%s'", filename); + case XpmNoMemory: + Error(ERR_EXIT, "not enough memory for XPM file '%s'", filename); + case XpmColorFailed: + Error(ERR_EXIT, "cannot get colors for XPM file '%s'", filename); + default: + break; + } + +#if DEBUG_TIMING + printf("LOADING XPM FILE %s:", filename); + debug_print_timestamp(1, ""); +#endif + +#else /* !USE_XPM_LIBRARY */ + + pcx_err = Read_PCX_to_Pixmap(display, window, gc, filename, + &pix[pos], &clipmask[pos]); + switch(pcx_err) + { + case PCX_Success: + break; + case PCX_OpenFailed: + Error(ERR_EXIT, "cannot open PCX file '%s'", filename); + case PCX_ReadFailed: + Error(ERR_EXIT, "cannot read PCX file '%s'", filename); + case PCX_FileInvalid: + Error(ERR_EXIT, "invalid PCX file '%s'", filename); + case PCX_NoMemory: + Error(ERR_EXIT, "not enough memory for PCX file '%s'", filename); + case PCX_ColorFailed: + Error(ERR_EXIT, "cannot get colors for PCX file '%s'", filename); + default: + break; + } + +#if DEBUG_TIMING + printf("SUMMARY LOADING PCX FILE %s:", filename); + debug_print_timestamp(1, ""); +#endif + +#endif /* !USE_XPM_LIBRARY */ + + if (!pix[pos]) + Error(ERR_EXIT, "cannot get graphics for '%s'", pic->picture_filename); + } + + /* zugehörige Maske laden (wenn vorhanden) */ + if (pic->picture_with_mask) + { +#ifdef USE_XPM_LIBRARY + + sprintf(basefilename, "%s%s", pic->picture_filename, picturemask_ext); + DrawInitText(basefilename, 150, FC_YELLOW); + sprintf(filename, "%s/%s/%s", + options.base_directory, GRAPHICS_DIRECTORY, basefilename); - for(i=0;ipicture_filename); + } } void InitElementProperties() @@ -441,7 +793,8 @@ void InitElementProperties() { EL_AMOEBE_NASS, EL_AMOEBE_NORM, - EL_AMOEBE_VOLL + EL_AMOEBE_VOLL, + EL_AMOEBE_BD }; static int ep_amoebalive_num = sizeof(ep_amoebalive)/sizeof(int); @@ -450,20 +803,11 @@ void InitElementProperties() EL_AMOEBE_TOT, EL_AMOEBE_NASS, EL_AMOEBE_NORM, - EL_AMOEBE_VOLL + EL_AMOEBE_VOLL, + EL_AMOEBE_BD }; static int ep_amoeboid_num = sizeof(ep_amoeboid)/sizeof(int); - static int ep_badewannoid[] = - { - EL_BADEWANNE1, - EL_BADEWANNE2, - EL_BADEWANNE3, - EL_BADEWANNE4, - EL_BADEWANNE5 - }; - static int ep_badewannoid_num = sizeof(ep_badewannoid)/sizeof(int); - static int ep_schluessel[] = { EL_SCHLUESSEL1, @@ -490,6 +834,10 @@ void InitElementProperties() { EL_BETON, EL_MAUERWERK, + EL_MAUER_LEBT, + EL_MAUER_X, + EL_MAUER_Y, + EL_MAUER_XY, EL_FELSBODEN, EL_AUSGANG_ZU, EL_AUSGANG_ACT, @@ -498,10 +846,15 @@ void InitElementProperties() EL_AMOEBE_NASS, EL_AMOEBE_NORM, EL_AMOEBE_VOLL, + EL_AMOEBE_BD, EL_MORAST_VOLL, EL_MORAST_LEER, EL_SIEB_VOLL, EL_SIEB_LEER, + EL_SIEB_TOT, + EL_SIEB2_VOLL, + EL_SIEB2_LEER, + EL_SIEB2_TOT, EL_LIFE, EL_LIFE_ASYNC, EL_BADEWANNE1, @@ -537,6 +890,10 @@ void InitElementProperties() EL_FELSBODEN, EL_FELSBROCKEN, EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, EL_DIAMANT, EL_BOMBE, EL_KOKOSNUSS, @@ -547,7 +904,8 @@ void InitElementProperties() EL_BIRNE_EIN, EL_BIRNE_AUS, EL_BADEWANNE1, - EL_BADEWANNE2 + EL_BADEWANNE2, + EL_SONDE }; static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int); @@ -555,22 +913,54 @@ void InitElementProperties() { EL_KAEFER, EL_FLIEGER, + EL_BUTTERFLY, + EL_FIREFLY, EL_MAMPFER, - EL_ZOMBIE, + EL_MAMPFER2, + EL_ROBOT, EL_PACMAN }; static int ep_enemy_num = sizeof(ep_enemy)/sizeof(int); + static int ep_mauer[] = + { + EL_BETON, + EL_PFORTE1, + EL_PFORTE2, + EL_PFORTE3, + EL_PFORTE4, + EL_PFORTE1X, + EL_PFORTE2X, + EL_PFORTE3X, + EL_PFORTE4X, + EL_AUSGANG_ZU, + EL_AUSGANG_ACT, + EL_AUSGANG_AUF, + EL_MAUERWERK, + EL_FELSBODEN, + EL_MAUER_LEBT, + EL_MAUER_X, + EL_MAUER_Y, + EL_MAUER_XY, + EL_MAUERND + }; + static int ep_mauer_num = sizeof(ep_mauer)/sizeof(int); + static int ep_can_fall[] = { EL_FELSBROCKEN, EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, EL_DIAMANT, EL_BOMBE, EL_KOKOSNUSS, EL_TROPFEN, EL_MORAST_VOLL, EL_SIEB_VOLL, + EL_SIEB2_VOLL, EL_ZEIT_VOLL, EL_ZEIT_LEER }; @@ -580,6 +970,10 @@ void InitElementProperties() { EL_FELSBROCKEN, EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, EL_DIAMANT, EL_SCHLUESSEL1, EL_SCHLUESSEL2, @@ -597,6 +991,10 @@ void InitElementProperties() { EL_FELSBROCKEN, EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, EL_DIAMANT }; static int ep_can_change_num = sizeof(ep_can_change)/sizeof(int); @@ -605,9 +1003,17 @@ void InitElementProperties() { EL_KAEFER, EL_FLIEGER, + EL_BUTTERFLY, + EL_FIREFLY, EL_MAMPFER, - EL_ZOMBIE, - EL_PACMAN + EL_MAMPFER2, + EL_ROBOT, + EL_PACMAN, + EL_MAULWURF, + EL_PINGUIN, + EL_SCHWEIN, + EL_DRACHE, + EL_SONDE }; static int ep_can_move_num = sizeof(ep_can_move)/sizeof(int); @@ -621,6 +1027,14 @@ void InitElementProperties() EL_FLIEGER_O, EL_FLIEGER_L, EL_FLIEGER_U, + EL_BUTTERFLY_R, + EL_BUTTERFLY_O, + EL_BUTTERFLY_L, + EL_BUTTERFLY_U, + EL_FIREFLY_R, + EL_FIREFLY_O, + EL_FIREFLY_L, + EL_FIREFLY_U, EL_PACMAN_R, EL_PACMAN_O, EL_PACMAN_L, @@ -631,7 +1045,9 @@ void InitElementProperties() static int ep_dont_touch[] = { EL_KAEFER, - EL_FLIEGER + EL_FLIEGER, + EL_BUTTERFLY, + EL_FIREFLY }; static int ep_dont_touch_num = sizeof(ep_dont_touch)/sizeof(int); @@ -639,84 +1055,291 @@ void InitElementProperties() { EL_KAEFER, EL_FLIEGER, + EL_BUTTERFLY, + EL_FIREFLY, EL_MAMPFER, - EL_ZOMBIE, + EL_MAMPFER2, + EL_ROBOT, EL_PACMAN, EL_TROPFEN, EL_SALZSAEURE }; static int ep_dont_go_to_num = sizeof(ep_dont_go_to)/sizeof(int); + static int ep_mampf2[] = + { + EL_ERDREICH, + EL_KAEFER, + EL_FLIEGER, + EL_BUTTERFLY, + EL_FIREFLY, + EL_MAMPFER, + EL_ROBOT, + EL_PACMAN, + EL_TROPFEN, + EL_AMOEBE_TOT, + EL_AMOEBE_NASS, + EL_AMOEBE_NORM, + EL_AMOEBE_VOLL, + EL_AMOEBE_BD, + EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, + EL_DIAMANT + }; + static int ep_mampf2_num = sizeof(ep_mampf2)/sizeof(int); + + static int ep_bd_element[] = + { + EL_LEERRAUM, + EL_ERDREICH, + EL_FELSBODEN, + EL_FELSBROCKEN, + EL_EDELSTEIN_BD, + EL_SIEB2_LEER, + EL_AUSGANG_ZU, + EL_AUSGANG_AUF, + EL_BETON, + EL_SPIELFIGUR, + EL_FIREFLY, + EL_FIREFLY_1, + EL_FIREFLY_2, + EL_FIREFLY_3, + EL_FIREFLY_4, + EL_BUTTERFLY, + EL_BUTTERFLY_1, + EL_BUTTERFLY_2, + EL_BUTTERFLY_3, + EL_BUTTERFLY_4, + EL_AMOEBE_BD, + EL_CHAR_FRAGE + }; + static int ep_bd_element_num = sizeof(ep_bd_element)/sizeof(int); + + static int ep_sb_element[] = + { + EL_LEERRAUM, + EL_BETON, + EL_SOKOBAN_OBJEKT, + EL_SOKOBAN_FELD_LEER, + EL_SOKOBAN_FELD_VOLL, + EL_SPIELFIGUR + }; + static int ep_sb_element_num = sizeof(ep_sb_element)/sizeof(int); + + static int ep_gem[] = + { + EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, + EL_DIAMANT + }; + static int ep_gem_num = sizeof(ep_gem)/sizeof(int); + + static int ep_inactive[] = + { + EL_LEERRAUM, + EL_ERDREICH, + EL_MAUERWERK, + EL_FELSBODEN, + EL_SCHLUESSEL, + EL_BETON, + EL_AMOEBE_TOT, + EL_MORAST_LEER, + EL_BADEWANNE, + EL_ABLENK_AUS, + EL_SCHLUESSEL1, + EL_SCHLUESSEL2, + EL_SCHLUESSEL3, + EL_SCHLUESSEL4, + EL_PFORTE1, + EL_PFORTE2, + EL_PFORTE3, + EL_PFORTE4, + EL_PFORTE1X, + EL_PFORTE2X, + EL_PFORTE3X, + EL_PFORTE4X, + EL_DYNAMIT_AUS, + EL_UNSICHTBAR, + EL_BIRNE_AUS, + EL_BIRNE_EIN, + EL_ERZ_EDEL, + EL_ERZ_DIAM, + EL_ERZ_EDEL_BD, + EL_ERZ_EDEL_GELB, + EL_DYNABOMB_NR, + EL_DYNABOMB_SZ, + EL_DYNABOMB_XL, + EL_SOKOBAN_OBJEKT, + EL_SOKOBAN_FELD_LEER, + EL_SOKOBAN_FELD_VOLL, + EL_ERZ_EDEL_ROT, + EL_ERZ_EDEL_LILA, + EL_BADEWANNE1, + EL_BADEWANNE2, + EL_BADEWANNE3, + EL_BADEWANNE4, + EL_BADEWANNE5, + EL_SIEB_TOT, + EL_SIEB2_TOT, + EL_AMOEBA2DIAM, + EL_BLOCKED + }; + static int ep_inactive_num = sizeof(ep_inactive)/sizeof(int); + + static int ep_explosive[] = + { + EL_BOMBE, + EL_DYNAMIT, + EL_DYNAMIT_AUS, + EL_DYNABOMB, + EL_DYNABOMB_NR, + EL_DYNABOMB_SZ, + EL_DYNABOMB_XL, + EL_KAEFER, + EL_MAULWURF, + EL_PINGUIN, + EL_SCHWEIN, + EL_DRACHE, + EL_SONDE + }; + static int ep_explosive_num = sizeof(ep_explosive)/sizeof(int); + + static int ep_mampf3[] = + { + EL_EDELSTEIN, + EL_EDELSTEIN_BD, + EL_EDELSTEIN_GELB, + EL_EDELSTEIN_ROT, + EL_EDELSTEIN_LILA, + EL_DIAMANT + }; + static int ep_mampf3_num = sizeof(ep_mampf3)/sizeof(int); + + static int ep_pushable[] = + { + EL_FELSBROCKEN, + EL_BOMBE, + EL_KOKOSNUSS, + EL_ZEIT_LEER, + EL_SOKOBAN_FELD_VOLL, + EL_SOKOBAN_OBJEKT, + EL_SONDE + }; + static int ep_pushable_num = sizeof(ep_pushable)/sizeof(int); + + static int ep_player[] = + { + EL_SPIELFIGUR, + EL_SPIELER1, + EL_SPIELER2, + EL_SPIELER3, + EL_SPIELER4 + }; + static int ep_player_num = sizeof(ep_player)/sizeof(int); + static long ep_bit[] = { EP_BIT_AMOEBALIVE, EP_BIT_AMOEBOID, - EP_BIT_BADEWANNOID, EP_BIT_SCHLUESSEL, EP_BIT_PFORTE, EP_BIT_SOLID, EP_BIT_MASSIV, EP_BIT_SLIPPERY, EP_BIT_ENEMY, + EP_BIT_MAUER, EP_BIT_CAN_FALL, EP_BIT_CAN_SMASH, EP_BIT_CAN_CHANGE, EP_BIT_CAN_MOVE, EP_BIT_COULD_MOVE, EP_BIT_DONT_TOUCH, - EP_BIT_DONT_GO_TO + EP_BIT_DONT_GO_TO, + EP_BIT_MAMPF2, + EP_BIT_BD_ELEMENT, + EP_BIT_SB_ELEMENT, + EP_BIT_GEM, + EP_BIT_INACTIVE, + EP_BIT_EXPLOSIVE, + EP_BIT_MAMPF3, + EP_BIT_PUSHABLE, + EP_BIT_PLAYER }; static int *ep_array[] = { ep_amoebalive, ep_amoeboid, - ep_badewannoid, ep_schluessel, ep_pforte, ep_solid, ep_massiv, ep_slippery, ep_enemy, + ep_mauer, ep_can_fall, ep_can_smash, ep_can_change, ep_can_move, ep_could_move, ep_dont_touch, - ep_dont_go_to + ep_dont_go_to, + ep_mampf2, + ep_bd_element, + ep_sb_element, + ep_gem, + ep_inactive, + ep_explosive, + ep_mampf3, + ep_pushable, + ep_player }; static int *ep_num[] = { &ep_amoebalive_num, &ep_amoeboid_num, - &ep_badewannoid_num, &ep_schluessel_num, &ep_pforte_num, &ep_solid_num, &ep_massiv_num, &ep_slippery_num, &ep_enemy_num, + &ep_mauer_num, &ep_can_fall_num, &ep_can_smash_num, &ep_can_change_num, &ep_can_move_num, &ep_could_move_num, &ep_dont_touch_num, - &ep_dont_go_to_num + &ep_dont_go_to_num, + &ep_mampf2_num, + &ep_bd_element_num, + &ep_sb_element_num, + &ep_gem_num, + &ep_inactive_num, + &ep_explosive_num, + &ep_mampf3_num, + &ep_pushable_num, + &ep_player_num }; static int num_properties = sizeof(ep_num)/sizeof(int *); - for(i=0;i +#endif + +#include "joystick.h" +#include "misc.h" + +void CheckJoystickData() +{ + int i; + int distance = 100; + + for(i=0; i= setup.input[i].joy.xmiddle) + setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance; + if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle) + setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance; + + if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle) + setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance; + if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle) + setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance; + } +} + +#ifndef MSDOS +static int JoystickPosition(int middle, int margin, int actual) +{ + long range, pos; + int percentage; + + if (margin < middle && actual > middle) + return 0; + if (margin > middle && actual < middle) + return 0; + + range = ABS(margin - middle); + pos = ABS(actual - middle); + percentage = (int)(pos * 100 / range); + + if (percentage > 100) + percentage = 100; + + return percentage; +} +#endif + +#ifndef MSDOS +int Joystick(int player_nr) +{ +#ifdef __FreeBSD__ + struct joystick joy_ctrl; +#else + struct joystick_control + { + int buttons; + int x; + int y; + } joy_ctrl; +#endif + + int joystick_fd = stored_player[player_nr].joystick_fd; + int js_x,js_y, js_b1,js_b2; + int left, right, up, down; + int result = 0; + + if (joystick_status == JOYSTICK_OFF) + return 0; + + if (game_status == SETUPINPUT) + return 0; + + if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) + return 0; + + if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) + { + Error(ERR_WARN, "cannot read joystick device '%s'", + setup.input[player_nr].joy.device_name); + joystick_status = JOYSTICK_OFF; + return 0; + } + + js_x = joy_ctrl.x; + js_y = joy_ctrl.y; + +#ifdef __FreeBSD__ + js_b1 = joy_ctrl.b1; + js_b2 = joy_ctrl.b2; +#else + js_b1 = joy_ctrl.buttons & 1; + js_b2 = joy_ctrl.buttons & 2; +#endif + + left = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xleft, js_x); + right = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xright, js_x); + up = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.yupper, js_y); + down = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.ylower, js_y); + + if (left > JOYSTICK_PERCENT) + result |= JOY_LEFT; + else if (right > JOYSTICK_PERCENT) + result |= JOY_RIGHT; + if (up > JOYSTICK_PERCENT) + result |= JOY_UP; + else if (down > JOYSTICK_PERCENT) + result |= JOY_DOWN; + + if (js_b1) + result |= JOY_BUTTON_1; + if (js_b2) + result |= JOY_BUTTON_2; + + return result; +} + +#else /* MSDOS */ + +/* allegro global variables for joystick control */ +extern int num_joysticks; +extern JOYSTICK_INFO joy[]; + +int Joystick(int player_nr) +{ + int joystick_nr = stored_player[player_nr].joystick_fd; + int result = 0; + + if (joystick_status == JOYSTICK_OFF) + return 0; + + if (game_status == SETUPINPUT) + return 0; + + if (joystick_nr < 0) + return 0; + + /* the allegro global variable ïnum_joysticksï contains the number + of joysticks found at initialization under MSDOS / Windows */ + +#if 0 + if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick) + return 0; +#else + +#if 1 + if (joystick_nr >= num_joysticks || + (game_status == PLAYING && !setup.input[player_nr].use_joystick)) + return 0; +#else + if (joystick_nr >= num_joysticks) + return 0; +#endif + +#endif + + poll_joystick(); + + if (joy[joystick_nr].stick[0].axis[0].d1) + result |= JOY_LEFT; + else if (joy[joystick_nr].stick[0].axis[0].d2) + result |= JOY_RIGHT; + if (joy[joystick_nr].stick[0].axis[1].d1) + result |= JOY_UP; + else if (joy[joystick_nr].stick[0].axis[1].d2) + result |= JOY_DOWN; + + if (joy[joystick_nr].button[0].b) + result |= JOY_BUTTON_1; + if (joy[joystick_nr].button[1].b) + result |= JOY_BUTTON_2; + + return result; +} +#endif /* MSDOS */ + +int JoystickButton(int player_nr) +{ + static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 }; + int joy_button = (Joystick(player_nr) & JOY_BUTTON); + int result; + + if (joy_button) + { + if (last_joy_button[player_nr]) + result = JOY_BUTTON_PRESSED; + else + result = JOY_BUTTON_NEW_PRESSED; + } + else + { + if (last_joy_button[player_nr]) + result = JOY_BUTTON_NEW_RELEASED; + else + result = JOY_BUTTON_NOT_PRESSED; + } + + last_joy_button[player_nr] = joy_button; + return result; +} + +int AnyJoystick() +{ + int i; + int result = 0; + + for (i=0; i +#define DEV_JOYSTICK_0 "/dev/joy0" +#define DEV_JOYSTICK_1 "/dev/joy1" +#define DEV_JOYSTICK_2 "/dev/joy2" +#define DEV_JOYSTICK_3 "/dev/joy3" +#else +#define DEV_JOYSTICK_0 "/dev/js0" +#define DEV_JOYSTICK_1 "/dev/js1" +#define DEV_JOYSTICK_2 "/dev/js2" +#define DEV_JOYSTICK_3 "/dev/js3" +#endif + +/* get these values from the program 'js' from the joystick package, */ +/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */ +#define JOYSTICK_XLEFT 30 +#define JOYSTICK_XMIDDLE 530 +#define JOYSTICK_XRIGHT 1250 +#define JOYSTICK_YUPPER 40 +#define JOYSTICK_YMIDDLE 680 +#define JOYSTICK_YLOWER 1440 + +#define JOYSTICK_PERCENT 25 + +#define JOY_LEFT MV_LEFT +#define JOY_RIGHT MV_RIGHT +#define JOY_UP MV_UP +#define JOY_DOWN MV_DOWN +#define JOY_BUTTON_1 (1<<4) +#define JOY_BUTTON_2 (1<<5) +#define JOY_BUTTON (JOY_BUTTON_1 | JOY_BUTTON_2) + +#define JOY_BUTTON_NOT_PRESSED 0 +#define JOY_BUTTON_PRESSED 1 +#define JOY_BUTTON_NEW_PRESSED 2 +#define JOY_BUTTON_NEW_RELEASED 3 + +#ifdef NO_JOYSTICK +#define JOYSTICK_STATUS JOYSTICK_OFF +#else +#define JOYSTICK_STATUS JOYSTICK_AVAILABLE +#endif + + +void CheckJoystickData(void); +int Joystick(int); +int JoystickButton(int); +int AnyJoystick(void); +int AnyJoystickButton(void); + +#endif diff --git a/src/main.c b/src/main.c index 0e3f612b..a0483461 100644 --- a/src/main.c +++ b/src/main.c @@ -1,95 +1,114 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * main.c * ***********************************************************/ #include "main.h" #include "init.h" +#include "game.h" #include "events.h" #include "sound.h" +#include "joystick.h" +#include "misc.h" + +#ifdef MSDOS +#include +#endif Display *display; +Visual *visual; int screen; Window window; -GC gc, plane_gc; -GC clip_gc[NUM_PIXMAPS]; +GC gc, clip_gc[NUM_PIXMAPS], tile_clip_gc; Pixmap pix[NUM_PIXMAPS]; -Pixmap clipmask[NUM_PIXMAPS]; +Pixmap clipmask[NUM_PIXMAPS], tile_clipmask[NUM_TILES]; + +#ifdef USE_XPM_LIBRARY XpmAttributes xpm_att[NUM_PICTURES]; -Drawable drawto, drawto_field, backbuffer; +#endif + +Drawable drawto, drawto_field, backbuffer, fieldbuffer; Colormap cmap; int sound_pipe[2]; int sound_device; char *sound_device_name = SOUND_DEVICE; int joystick_device = 0; -char *joystick_device_name[2] = { DEV_JOYSTICK_0, DEV_JOYSTICK_1 }; -int width, height; -unsigned long pen_fg, pen_bg; +char *joystick_device_name[MAX_PLAYERS] = +{ + DEV_JOYSTICK_0, + DEV_JOYSTICK_1, + DEV_JOYSTICK_2, + DEV_JOYSTICK_3 +}; + +char *program_name = NULL; int game_status = MAINMENU; -int button_status = MB_NOT_PRESSED, motion_status = FALSE; -int key_status = KEY_NOT_PRESSED; +boolean network_playing = FALSE; +int button_status = MB_NOT_PRESSED; +boolean motion_status = FALSE; +int key_joystick_mapping = 0; int global_joystick_status = JOYSTICK_STATUS; int joystick_status = JOYSTICK_STATUS; -int sound_status = SOUND_STATUS, sound_on=TRUE; -int sound_loops_allowed = FALSE, sound_loops_on = FALSE; -int sound_music_on = FALSE; -int toons_on = TRUE; -int direct_draw_on = FALSE; -int fading_on = FALSE; -int autorecord_on = FALSE; -int joystick_nr = 0; -int quick_doors = FALSE; - -BOOL redraw[SCR_FIELDX][SCR_FIELDY]; +int sound_status = SOUND_STATUS; +boolean sound_loops_allowed = FALSE; + +boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; +int redraw_x1 = 0, redraw_y1 = 0; int redraw_mask; int redraw_tiles; -int Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -int AmoebaCnt[MAX_NUM_AMOEBA]; -long Elementeigenschaften[MAX_ELEMENTS]; +short Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short JustHit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +short AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA]; +unsigned long Elementeigenschaften[MAX_ELEMENTS]; int level_nr, leveldir_nr, num_leveldirs; int lev_fieldx,lev_fieldy, scroll_x,scroll_y; -int LevelSolved,GameOver, JX,JY, ZX,ZY; -int Gems,Dynamite,Key[4],TimeLeft,Score,MampferNr; -int CheckMoving,CheckExploding, SiebAktiv; +int FX = SX, FY = SY, ScrollStepSize = TILEX/8; +int ScreenMovDir = MV_NO_MOVING, ScreenMovPos = 0; +int ScreenGfxPos = 0; +int GameFrameDelay = GAME_FRAME_DELAY; +int FfwdFrameDelay = FFWD_FRAME_DELAY; +int MoveSpeed = 8; +int BX1 = 0, BY1 = 0, BX2 = SCR_FIELDX-1, BY2 = SCR_FIELDY-1; +int ZX,ZY, ExitX,ExitY; +int AllPlayersGone; +int FrameCounter, TimeFrames, TimeLeft; +int MampferNr, SiebAktiv; + +boolean network_player_action_received = FALSE; struct LevelDirInfo leveldir[MAX_LEVDIR_ENTRIES]; struct LevelInfo level; -struct PlayerInfo player; +struct PlayerInfo stored_player[MAX_PLAYERS], *local_player = NULL; struct HiScore highscore[MAX_SCORE_ENTRIES]; struct SoundInfo Sound[NUM_SOUNDS]; -struct RecordingInfo tape,master_tape; - -struct JoystickInfo joystick[2] = -{ - JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE, - JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE, - - JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE, - JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE -}; +struct TapeInfo tape; +struct OptionInfo options; +struct SetupInfo setup; +struct SetupFileList *setup_list = NULL; +struct SetupFileList *level_setup_list = NULL; /* data needed for playing sounds */ char *sound_name[NUM_SOUNDS] = @@ -161,15 +180,17 @@ int background_loop[] = }; int num_bg_loops = sizeof(background_loop)/sizeof(int); -char *progname; - int main(int argc, char *argv[]) { - progname = argv[0]; + program_name = (strrchr(argv[0],'/') ? strrchr(argv[0],'/') + 1 : argv[0]); + +#ifdef MSDOS + _fmode = O_BINARY; +#endif + GetOptions(argv); OpenAll(argc,argv); EventLoop(); - CloseAll(); - - exit(0); + CloseAllAndExit(0); + exit(0); /* to keep compilers happy */ } diff --git a/src/main.h b/src/main.h index 905688b3..fed17ca6 100644 --- a/src/main.h +++ b/src/main.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * main.h * ***********************************************************/ @@ -15,101 +14,97 @@ #ifndef MAIN_H #define MAIN_H +#include +#include +#include +#include +#include +#include + +#ifndef MSDOS #define XK_MISCELLANY #define XK_LATIN1 #include #include +#include #include #include #include +#ifdef XPM_INCLUDE_FILE +#define USE_XPM_LIBRARY #include XPM_INCLUDE_FILE +#endif +#else /* MSDOS */ +#include "msdos.h" +#endif /* MSDOS */ -#include -#include -#include -#include -#include -#include +#ifdef DEBUG +#define DEBUG_TIMING 0 +#endif -typedef int BOOL; +typedef unsigned char boolean; +typedef unsigned char byte; -#define TRUE 1 +#ifndef FALSE #define FALSE 0 +#define TRUE (!FALSE) +#endif -#define WIN_XPOS 0 -#define WIN_YPOS 0 #define WIN_XSIZE 672 #define WIN_YSIZE 560 +#ifndef MSDOS +#define WIN_XPOS 0 +#define WIN_YPOS 0 +#else /* MSDOS */ +#define WIN_XPOS ((XRES - WIN_XSIZE) / 2) +#define WIN_YPOS ((YRES - WIN_YSIZE) / 2) +#endif /* MSDOS */ #define SCR_FIELDX 17 #define SCR_FIELDY 17 +#define MAX_BUF_XSIZE (SCR_FIELDX + 2) +#define MAX_BUF_YSIZE (SCR_FIELDY + 2) -#define MIN_LEV_FIELDX (SCR_FIELDX-2) -#define MIN_LEV_FIELDY (SCR_FIELDY-2) +#define MIN_LEV_FIELDX (SCR_FIELDX - 2) +#define MIN_LEV_FIELDY (SCR_FIELDY - 2) #define STD_LEV_FIELDX 64 #define STD_LEV_FIELDY 32 #define MAX_LEV_FIELDX 128 #define MAX_LEV_FIELDY 128 -#define MIN(a,b) ((a)<(b) ? (a) : (b)) -#define MAX(a,b) ((a)>(b) ? (a) : (b)) -#define ABS(a) ((a)<0 ? -(a) : (a)) -#define SIGN(a) ((a)<0 ? -1 : ((a)>0 ? 1 : 0)) -#define SCROLLX(a) ((a)-scroll_x) -#define SCROLLY(a) ((a)-scroll_y) -#define UNSCROLLX(a) ((a)+scroll_x) -#define UNSCROLLY(a) ((a)+scroll_y) -#define IN_SCR_FIELD(x,y) ((x)>=0 && (x)=0 &&(y)=0 && (x)=0 &&(y)=EL_BADEWANNE1 && (e)<=EL_BADEWANNE5) -#define IS_SCHLUESSEL(e) ((e)>=EL_SCHLUESSEL1 && (e)<=EL_SCHLUESSEL4) -#define IS_PFORTE(e) ((e)>=EL_PFORTE1 && (e)<=EL_PFORTE4X) - -#define IS_SOLID(e) ((e)==EL_BETON || (e)==EL_MAUERWERK || (e)==EL_FELSBODEN || (e)==EL_AUSGANG_ZU || (e)==EL_AUSGANG_ACT || (e)==EL_AUSGANG_AUF || IS_AMOEBOID(e) || (e)==EL_MORAST_VOLL || (e)==EL_MORAST_LEER || (e)==EL_SIEB_VOLL || (e)==EL_SIEB_LEER || (e)==EL_LIFE || (e)==EL_LIFE_ASYNC || IS_BADEWANNOID(e)) - -#define IS_MASSIV(e) ((e)==EL_BETON || (e)==EL_SALZSAEURE || IS_BADEWANNOID(e) || IS_PFORTE(e)) - -#define IS_SLIPPERY(e) ((e)==EL_FELSBODEN || (e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_ABLENK_EIN || (e)==EL_ABLENK_AUS || (e)==EL_ZEIT_VOLL || (e)==EL_ZEIT_LEER || (e)==EL_BIRNE_EIN || (e)==EL_BIRNE_AUS || (e)==EL_BADEWANNE1 || (e)==EL_BADEWANNE2) - -#define IS_ENEMY(e) ((e)==EL_KAEFER || (e)==EL_FLIEGER || (e)==EL_MAMPFER || (e)==EL_ZOMBIE || (e)==EL_PACMAN) - -#define CAN_FALL(e) ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_TROPFEN || (e)==EL_MORAST_VOLL || (e)==EL_SIEB_VOLL || (e)==EL_ZEIT_VOLL || (e)==EL_ZEIT_LEER) - -#define CAN_SMASH(e) ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || IS_SCHLUESSEL(e) || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_TROPFEN || (e)==EL_ZEIT_VOLL || (e)==EL_ZEIT_LEER) +#define MAX_PLAYERS 4 -#define CAN_CHANGE(e) ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT) - -#define CAN_MOVE(e) ((e)==EL_KAEFER || (e)==EL_FLIEGER || (e)==EL_MAMPFER || (e)==EL_ZOMBIE || (e)==EL_PACMAN) - -#define COULD_MOVE(e) (((e)>=EL_KAEFER_R && (e)<=EL_KAEFER_U) || ((e)>=EL_FLIEGER_R && (e)<=EL_FLIEGER_U) || ((e)>=EL_PACMAN_R && (e)==EL_PACMAN_U)) - -#define DONT_TOUCH(e) ((e)==EL_KAEFER || (e)==EL_FLIEGER) -#define DONT_GO_TO(e) (IS_ENEMY(e) || (e)==EL_TROPFEN || (e)==EL_SALZSAEURE) - -#define IS_CHAR(e) ((e)>=EL_CHAR_START && (e)<=EL_CHAR_END) - -*/ +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif +#ifndef SIGN +#define SIGN(a) ((a) < 0 ? -1 : ((a)>0 ? 1 : 0)) +#endif +#define SCREENX(a) ((a) - scroll_x) +#define SCREENY(a) ((a) - scroll_y) +#define LEVELX(a) ((a) + scroll_x) +#define LEVELY(a) ((a) + scroll_y) +#define IN_VIS_FIELD(x,y) ((x)>=0 && (x)=0 &&(y)=BX1 && (x)<=BX2 && (y)>=BY1 &&(y)<=BY2) +#define IN_LEV_FIELD(x,y) ((x)>=0 && (x)=0 &&(y)=EL_BLOCKED) -#define TIMESIZE (TimeLeft*100/level.time) -#define LEVELDIR_SIZE(x) ((x).num_ready + (x).num_free) +#define IS_DRAWABLE(e) ((e) < EL_BLOCKED) +#define IS_NOT_DRAWABLE(e) ((e) >= EL_BLOCKED) +#define TIMESIZE (TimeLeft * 100 / level.time) #define TAPE_IS_EMPTY(x) ((x).length == 0) +#define TAPE_IS_STOPPED(x) (!(x).recording && !(x).playing &&!(x).pausing) + +#define PLAYERINFO(x,y) (&stored_player[StorePlayer[x][y]-EL_SPIELER1]) /* Pixmaps with Xpm or X11 Bitmap files */ #define PIX_BACK 0 #define PIX_DOOR 1 -#define PIX_TOONS 2 -#define PIX_BIGFONT 3 -#define PIX_SMALLFONT 4 +#define PIX_HEROES 2 +#define PIX_TOONS 3 +#define PIX_BIGFONT 4 +#define PIX_SMALLFONT 5 /* Pixmaps without them */ -#define PIX_DB_BACK 5 -#define PIX_DB_DOOR 6 -#define PIX_FADEMASK 7 +#define PIX_DB_BACK 6 +#define PIX_DB_DOOR 7 +#define PIX_DB_FIELD 8 -#define NUM_PICTURES 5 -#define NUM_PIXMAPS 8 +#define NUM_PICTURES 6 +#define NUM_PIXMAPS 9 /* boundaries of arrays etc. */ #define MAX_NAMELEN (10+1) - #define MAX_LEVNAMLEN 32 -#define MAX_SC_ENTRIES 15 -#define MAX_TAPELEN 10000 - -#define MAX_LEVDIR_FILENAME (64+1) -#define MAX_LEVDIR_NAME (16+1) -#define MAX_LEVDIR_ENTRIES 15 -#define MAX_SCORE_ENTRIES 15 - -#define MAX_FILENAME 256 -#define MAX_NUM_AMOEBA 100 +#define MAX_TAPELEN (1000 * 50) /* max. time * framerate */ +#define MAX_LEVDIR_ENTRIES 100 +#define MAX_SCORE_ENTRIES 100 #define MAX_ELEMENTS 512 +#define MAX_NUM_AMOEBA 100 -struct PictureFile -{ - char *picture_filename; - char *picturemask_filename; -}; +#define LEVEL_SCORE_ELEMENTS 16 /* level elements with score */ + +/* fundamental game speed values */ +#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */ +#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */ +#define FRAMES_PER_SECOND (1000 / GAME_FRAME_DELAY) struct HiScore { @@ -188,13 +211,113 @@ struct HiScore int Score; }; +struct OptionInfo +{ + char *display_name; + char *server_host; + int server_port; + char *base_directory; + char *level_directory; + boolean serveronly; + boolean network; + boolean verbose; +}; + +struct SetupJoystickInfo +{ + char *device_name; + int xleft, xmiddle, xright; + int yupper, ymiddle, ylower; + int snap; + int bomb; +}; + +struct SetupKeyboardInfo +{ + KeySym left; + KeySym right; + KeySym up; + KeySym down; + KeySym snap; + KeySym bomb; +}; + +struct SetupInputInfo +{ + boolean use_joystick; + struct SetupJoystickInfo joy; + struct SetupKeyboardInfo key; +}; + +struct SetupInfo +{ + char *player_name; + + boolean sound; + boolean sound_loops; + boolean sound_music; + boolean sound_simple; + boolean toons; + boolean double_buffering; + boolean direct_draw; /* !double_buffering (redundant!) */ + boolean scroll_delay; + boolean soft_scrolling; + boolean fading; + boolean autorecord; + boolean quick_doors; + boolean team_mode; + + struct SetupInputInfo input[MAX_PLAYERS]; +}; + +struct SetupFileList +{ + char *token; + char *value; + struct SetupFileList *next; +}; + struct PlayerInfo { - char login_name[MAX_NAMELEN]; - char alias_name[MAX_NAMELEN]; - int handicap; - unsigned int setup; - int leveldir_nr; + boolean present; /* player present in level playfield */ + boolean connected; /* player connected (locally or via network) */ + boolean active; /* player (present && connected) */ + + int index_nr, client_nr, element_nr; + + byte action; /* action from local input device */ + byte effective_action; /* action aknowledged from network server + or summarized over all configured input + devices when in single player mode */ + + int joystick_fd; /* file descriptor of player's joystick */ + + int jx,jy, last_jx,last_jy; + int MovDir, MovPos, GfxPos; + int Frame; + + boolean Pushing; + boolean gone, LevelSolved, GameOver; + boolean snapped; + + unsigned long move_delay; + int last_move_dir; + + unsigned long push_delay; + unsigned long push_delay_value; + + int frame_reset_delay; + + unsigned long actual_frame_counter; + + int score; + int gems_still_needed; + int sokobanfields_still_needed; + int lights_still_needed; + int friends_still_needed; + int key[4]; + int dynamite; + int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl; }; struct LevelInfo @@ -204,162 +327,181 @@ struct LevelInfo int time; int edelsteine; char name[MAX_LEVNAMLEN]; - int score[MAX_SC_ENTRIES]; - int amoebe_inhalt; + int score[LEVEL_SCORE_ELEMENTS]; int mampfer_inhalt[4][3][3]; int tempo_amoebe; int dauer_sieb; int dauer_ablenk; + int amoebe_inhalt; }; struct LevelDirInfo { - char filename[MAX_LEVDIR_FILENAME]; - char name[MAX_LEVDIR_NAME]; - int num_ready; - int num_free; + char *filename; + char *name; + int levels; + int sort_priority; + boolean user_defined; + boolean readonly; }; -struct RecordingInfo +struct TapeInfo { int level_nr; - unsigned int random_seed; + unsigned long random_seed; unsigned long date; unsigned long counter; unsigned long length; - BOOL recording, playing, pausing; + unsigned long length_seconds; + unsigned int delay_played; + boolean pause_before_death; + boolean recording, playing, pausing; + boolean fast_forward; + boolean changed; + boolean player_participates[MAX_PLAYERS]; struct { - unsigned char joystickdata; - unsigned char delay; + byte action[MAX_PLAYERS]; + byte delay; } pos[MAX_TAPELEN]; }; -struct JoystickInfo -{ - int xleft, xright, xmiddle; - int yupper, ylower, ymiddle; -}; - extern Display *display; +extern Visual *visual; extern int screen; extern Window window; -extern GC gc, plane_gc; -extern GC clip_gc[]; -extern XImage *image[]; -extern Pixmap clipmask[]; +extern GC gc, clip_gc[], tile_clip_gc; extern Pixmap pix[]; +extern Pixmap clipmask[], tile_clipmask[]; + +#ifdef USE_XPM_LIBRARY extern XpmAttributes xpm_att[]; -extern Drawable drawto, drawto_field, backbuffer; +#endif + +extern Drawable drawto, drawto_field, backbuffer, fieldbuffer; extern Colormap cmap; extern int sound_pipe[2]; extern int sound_device; extern char *sound_device_name; extern int joystick_device; -extern char *joystick_device_name[2]; -extern int width, height; -extern unsigned long pen_fg, pen_bg; +extern char *joystick_device_name[]; + +extern char *program_name; extern int game_status; -extern int button_status, motion_status; -extern int key_status; +extern boolean network_playing; +extern int button_status; +extern boolean motion_status; +extern int key_joystick_mapping; extern int global_joystick_status, joystick_status; -extern int sound_status, sound_on; -extern int sound_loops_allowed, sound_loops_on; -extern int sound_music_on; -extern int toons_on; -extern int direct_draw_on; -extern int fading_on; -extern int autorecord_on; -extern int joystick_nr; -extern int quick_doors; - -extern BOOL redraw[SCR_FIELDX][SCR_FIELDY]; +extern int sound_status; +extern boolean sound_loops_allowed; + +extern boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; +extern int redraw_x1, redraw_y1; extern int redraw_mask; extern int redraw_tiles; -extern int Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; -extern int AmoebaCnt[MAX_NUM_AMOEBA]; -extern long Elementeigenschaften[MAX_ELEMENTS]; +extern short Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short JustHit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern short AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA]; +extern unsigned long Elementeigenschaften[MAX_ELEMENTS]; extern int level_nr, leveldir_nr, num_leveldirs; extern int lev_fieldx,lev_fieldy, scroll_x,scroll_y; -extern int LevelSolved,GameOver, JX,JY, ZX,ZY; -extern int Gems,Dynamite,Key[4],TimeLeft,Score,MampferNr; -extern int CheckMoving,CheckExploding, SiebAktiv; +extern int FX,FY, ScrollStepSize; +extern int ScreenMovDir, ScreenMovPos, ScreenGfxPos; +extern int GameFrameDelay; +extern int FfwdFrameDelay; +extern int MoveSpeed; +extern int BX1,BY1, BX2,BY2; +extern int ZX,ZY, ExitX,ExitY; +extern int AllPlayersGone; +extern int FrameCounter, TimeFrames, TimeLeft; +extern int MampferNr, SiebAktiv; + +extern boolean network_player_action_received; extern struct LevelDirInfo leveldir[]; extern struct LevelInfo level; -extern struct PlayerInfo player; +extern struct PlayerInfo stored_player[], *local_player; extern struct HiScore highscore[]; -extern struct RecordingInfo tape, master_tape; +extern struct TapeInfo tape; +extern struct SoundInfo Sound[]; extern struct JoystickInfo joystick[]; +extern struct OptionInfo options; +extern struct SetupInfo setup; +extern struct SetupFileList *setup_list; +extern struct SetupFileList *level_setup_list; +extern char *sound_name[]; extern int background_loop[]; extern int num_bg_loops; -extern char *progname; - /* often used screen positions */ -#define SX 8 -#define SY 8 -#define REAL_SX (SX-2) -#define REAL_SY (SY-2) -#define DX 566 -#define DY 60 -#define VX DX -#define VY 400 -#define TILEX 32 -#define TILEY 32 -#define MINI_TILEX (TILEX/2) -#define MINI_TILEY (TILEY/2) -#define MICRO_TILEX (TILEX/8) -#define MICRO_TILEY (TILEY/8) -#define MIDPOSX (SCR_FIELDX/2) -#define MIDPOSY (SCR_FIELDY/2) -#define SXSIZE (SCR_FIELDX*TILEX) -#define SYSIZE (SCR_FIELDY*TILEY) -#define DXSIZE 100 -#define DYSIZE 280 -#define VXSIZE DXSIZE -#define VYSIZE 100 -#define FULL_SXSIZE (2+SXSIZE+2) -#define FULL_SYSIZE (2+SYSIZE+2) -#define MICROLEV_XPOS (SX+4*32+16) -#define MICROLEV_YPOS (SX+12*32) -#define MICROLEV_XSIZE (STD_LEV_FIELDX*MICRO_TILEX) -#define MICROLEV_YSIZE (STD_LEV_FIELDY*MICRO_TILEY) -#define MICROLABEL_YPOS (MICROLEV_YPOS+MICROLEV_YSIZE+12) -#define FONT1_XSIZE 32 -#define FONT1_YSIZE 32 -#define FONT2_XSIZE 14 -#define FONT2_YSIZE 14 -#define FONT3_XSIZE 11 -#define FONT3_YSIZE 14 -#define FONT4_XSIZE 16 -#define FONT4_YSIZE 16 +#define SX 8 +#define SY 8 +#define REAL_SX (SX-2) +#define REAL_SY (SY-2) +#define DX 566 +#define DY 60 +#define VX DX +#define VY 400 +#define TILEX 32 +#define TILEY 32 +#define MINI_TILEX (TILEX/2) +#define MINI_TILEY (TILEY/2) +#define MICRO_TILEX (TILEX/8) +#define MICRO_TILEY (TILEY/8) +#define MIDPOSX (SCR_FIELDX/2) +#define MIDPOSY (SCR_FIELDY/2) +#define SXSIZE (SCR_FIELDX*TILEX) +#define SYSIZE (SCR_FIELDY*TILEY) +#define FXSIZE ((SCR_FIELDX+2)*TILEX) +#define FYSIZE ((SCR_FIELDY+2)*TILEY) +#define DXSIZE 100 +#define DYSIZE 280 +#define VXSIZE DXSIZE +#define VYSIZE 100 +#define FULL_SXSIZE (2+SXSIZE+2) +#define FULL_SYSIZE (2+SYSIZE+2) +#define MICROLEV_XPOS (SX+4*32+16) +#define MICROLEV_YPOS (SX+12*32) +#define MICROLEV_XSIZE (STD_LEV_FIELDX*MICRO_TILEX) +#define MICROLEV_YSIZE (STD_LEV_FIELDY*MICRO_TILEY) +#define MICROLABEL_YPOS (MICROLEV_YPOS+MICROLEV_YSIZE+12) +#define FONT1_XSIZE 32 +#define FONT1_YSIZE 32 +#define FONT2_XSIZE 14 +#define FONT2_YSIZE 14 +#define FONT3_XSIZE 11 +#define FONT3_YSIZE 14 +#define FONT4_XSIZE 16 +#define FONT4_YSIZE 16 #define GFX_STARTX SX #define GFX_STARTY SY #define MINI_GFX_STARTX SX -#define MINI_GFX_STARTY 432 +#define MINI_GFX_STARTY 424 #define MICRO_GFX_STARTX SX -#define MICRO_GFX_STARTY 528 +#define MICRO_GFX_STARTY 536 #define GFX_PER_LINE 16 #define MINI_GFX_PER_LINE 32 #define MICRO_GFX_PER_LINE 128 +#define HEROES_PER_LINE 16 #define FONT_CHARS_PER_LINE 16 #define FONT_LINES_PER_FONT 4 @@ -368,549 +510,614 @@ extern char *progname; ** 256 - 511: flag elements, only used at runtime */ /* "real" level elements */ -#define EL_LEERRAUM 0 -#define EL_ERDREICH 1 -#define EL_MAUERWERK 2 -#define EL_FELSBODEN 3 -#define EL_FELSBROCKEN 4 -#define EL_SCHLUESSEL 5 -#define EL_EDELSTEIN 6 -#define EL_AUSGANG_ZU 7 -#define EL_SPIELFIGUR 8 -#define EL_KAEFER 9 -#define EL_FLIEGER 10 -#define EL_MAMPFER 11 -#define EL_ZOMBIE 12 -#define EL_BETON 13 -#define EL_DIAMANT 14 -#define EL_AMOEBE_TOT 15 -#define EL_MORAST_LEER 16 -#define EL_MORAST_VOLL 17 -#define EL_TROPFEN 18 -#define EL_BOMBE 19 -#define EL_SIEB_LEER 20 -#define EL_SIEB_VOLL 21 -#define EL_SALZSAEURE 22 -#define EL_AMOEBE_NASS 23 -#define EL_AMOEBE_NORM 24 -#define EL_KOKOSNUSS 25 -#define EL_LIFE 26 -#define EL_LIFE_ASYNC 27 -#define EL_DYNAMIT 28 -#define EL_BADEWANNE 29 -#define EL_ABLENK_AUS 30 -#define EL_ABLENK_EIN 31 -#define EL_SCHLUESSEL1 32 -#define EL_SCHLUESSEL2 33 -#define EL_SCHLUESSEL3 34 -#define EL_SCHLUESSEL4 35 -#define EL_PFORTE1 36 -#define EL_PFORTE2 37 -#define EL_PFORTE3 38 -#define EL_PFORTE4 39 -#define EL_PFORTE1X 40 -#define EL_PFORTE2X 41 -#define EL_PFORTE3X 42 -#define EL_PFORTE4X 43 -#define EL_DYNAMIT_AUS 44 -#define EL_PACMAN 45 -#define EL_UNSICHTBAR 46 -#define EL_BIRNE_AUS 47 -#define EL_BIRNE_EIN 48 -#define EL_ERZ_EDEL 49 -#define EL_ERZ_DIAM 50 -#define EL_AMOEBE_VOLL 51 -#define EL_AMOEBA2DIAM 52 -#define EL_ZEIT_VOLL 53 -#define EL_ZEIT_LEER 54 - -#define EL_SPIELER1 80 -#define EL_SPIELER2 81 -#define EL_SPIELER3 82 -#define EL_SPIELER4 83 -#define EL_KAEFER_R 84 -#define EL_KAEFER_O 85 -#define EL_KAEFER_L 86 -#define EL_KAEFER_U 87 -#define EL_FLIEGER_R 88 -#define EL_FLIEGER_O 89 -#define EL_FLIEGER_L 90 -#define EL_FLIEGER_U 91 -#define EL_PACMAN_R 92 -#define EL_PACMAN_O 93 -#define EL_PACMAN_L 94 -#define EL_PACMAN_U 95 - -#define EL_BADEWANNE1 100 -#define EL_BADEWANNE2 101 -#define EL_BADEWANNE3 102 -#define EL_BADEWANNE4 103 -#define EL_BADEWANNE5 104 -#define EL_SIEB_TOT 105 -#define EL_AUSGANG_ACT 106 -#define EL_AUSGANG_AUF 107 - -#define EL_CHAR_START 120 -#define EL_CHAR_ASCII0 (EL_CHAR_START-32) -#define EL_CHAR_AUSRUF (EL_CHAR_ASCII0+33) -#define EL_CHAR_ZOLL (EL_CHAR_ASCII0+34) -#define EL_CHAR_DOLLAR (EL_CHAR_ASCII0+36) -#define EL_CHAR_PROZ (EL_CHAR_ASCII0+37) -#define EL_CHAR_APOSTR (EL_CHAR_ASCII0+39) -#define EL_CHAR_KLAMM1 (EL_CHAR_ASCII0+40) -#define EL_CHAR_KLAMM2 (EL_CHAR_ASCII0+41) -#define EL_CHAR_PLUS (EL_CHAR_ASCII0+43) -#define EL_CHAR_KOMMA (EL_CHAR_ASCII0+44) -#define EL_CHAR_MINUS (EL_CHAR_ASCII0+45) -#define EL_CHAR_PUNKT (EL_CHAR_ASCII0+46) -#define EL_CHAR_SLASH (EL_CHAR_ASCII0+47) -#define EL_CHAR_0 (EL_CHAR_ASCII0+48) -#define EL_CHAR_9 (EL_CHAR_ASCII0+57) -#define EL_CHAR_DOPPEL (EL_CHAR_ASCII0+58) -#define EL_CHAR_SEMIKL (EL_CHAR_ASCII0+59) -#define EL_CHAR_LT (EL_CHAR_ASCII0+60) -#define EL_CHAR_GLEICH (EL_CHAR_ASCII0+61) -#define EL_CHAR_GT (EL_CHAR_ASCII0+62) -#define EL_CHAR_FRAGE (EL_CHAR_ASCII0+63) -#define EL_CHAR_AT (EL_CHAR_ASCII0+64) -#define EL_CHAR_A (EL_CHAR_ASCII0+65) -#define EL_CHAR_Z (EL_CHAR_ASCII0+90) -#define EL_CHAR_AE (EL_CHAR_ASCII0+91) -#define EL_CHAR_OE (EL_CHAR_ASCII0+92) -#define EL_CHAR_UE (EL_CHAR_ASCII0+93) -#define EL_CHAR_COPY (EL_CHAR_ASCII0+94) -#define EL_CHAR_END (EL_CHAR_START+79) +#define EL_LEERRAUM 0 +#define EL_ERDREICH 1 +#define EL_MAUERWERK 2 +#define EL_FELSBODEN 3 +#define EL_FELSBROCKEN 4 +#define EL_SCHLUESSEL 5 +#define EL_EDELSTEIN 6 +#define EL_AUSGANG_ZU 7 +#define EL_SPIELFIGUR 8 +#define EL_KAEFER 9 +#define EL_FLIEGER 10 +#define EL_MAMPFER 11 +#define EL_ROBOT 12 +#define EL_BETON 13 +#define EL_DIAMANT 14 +#define EL_AMOEBE_TOT 15 +#define EL_MORAST_LEER 16 +#define EL_MORAST_VOLL 17 +#define EL_TROPFEN 18 +#define EL_BOMBE 19 +#define EL_SIEB_LEER 20 +#define EL_SIEB_VOLL 21 +#define EL_SALZSAEURE 22 +#define EL_AMOEBE_NASS 23 +#define EL_AMOEBE_NORM 24 +#define EL_KOKOSNUSS 25 +#define EL_LIFE 26 +#define EL_LIFE_ASYNC 27 +#define EL_DYNAMIT 28 +#define EL_BADEWANNE 29 +#define EL_ABLENK_AUS 30 +#define EL_ABLENK_EIN 31 +#define EL_SCHLUESSEL1 32 +#define EL_SCHLUESSEL2 33 +#define EL_SCHLUESSEL3 34 +#define EL_SCHLUESSEL4 35 +#define EL_PFORTE1 36 +#define EL_PFORTE2 37 +#define EL_PFORTE3 38 +#define EL_PFORTE4 39 +#define EL_PFORTE1X 40 +#define EL_PFORTE2X 41 +#define EL_PFORTE3X 42 +#define EL_PFORTE4X 43 +#define EL_DYNAMIT_AUS 44 +#define EL_PACMAN 45 +#define EL_UNSICHTBAR 46 +#define EL_BIRNE_AUS 47 +#define EL_BIRNE_EIN 48 +#define EL_ERZ_EDEL 49 +#define EL_ERZ_DIAM 50 +#define EL_AMOEBE_VOLL 51 +#define EL_AMOEBE_BD 52 +#define EL_ZEIT_VOLL 53 +#define EL_ZEIT_LEER 54 +#define EL_MAUER_LEBT 55 +#define EL_EDELSTEIN_BD 56 +#define EL_EDELSTEIN_GELB 57 +#define EL_ERZ_EDEL_BD 58 +#define EL_ERZ_EDEL_GELB 59 +#define EL_MAMPFER2 60 +#define EL_SIEB2_LEER 61 +#define EL_SIEB2_VOLL 62 +#define EL_DYNABOMB 63 +#define EL_DYNABOMB_NR 64 +#define EL_DYNABOMB_SZ 65 +#define EL_DYNABOMB_XL 66 +#define EL_SOKOBAN_OBJEKT 67 +#define EL_SOKOBAN_FELD_LEER 68 +#define EL_SOKOBAN_FELD_VOLL 69 +#define EL_BUTTERFLY_R 70 +#define EL_BUTTERFLY_O 71 +#define EL_BUTTERFLY_L 72 +#define EL_BUTTERFLY_U 73 +#define EL_FIREFLY_R 74 +#define EL_FIREFLY_O 75 +#define EL_FIREFLY_L 76 +#define EL_FIREFLY_U 77 +#define EL_BUTTERFLY_1 EL_BUTTERFLY_U +#define EL_BUTTERFLY_2 EL_BUTTERFLY_L +#define EL_BUTTERFLY_3 EL_BUTTERFLY_O +#define EL_BUTTERFLY_4 EL_BUTTERFLY_R +#define EL_FIREFLY_1 EL_FIREFLY_L +#define EL_FIREFLY_2 EL_FIREFLY_U +#define EL_FIREFLY_3 EL_FIREFLY_R +#define EL_FIREFLY_4 EL_FIREFLY_O +#define EL_BUTTERFLY 78 +#define EL_FIREFLY 79 +#define EL_SPIELER1 80 +#define EL_SPIELER2 81 +#define EL_SPIELER3 82 +#define EL_SPIELER4 83 +#define EL_KAEFER_R 84 +#define EL_KAEFER_O 85 +#define EL_KAEFER_L 86 +#define EL_KAEFER_U 87 +#define EL_FLIEGER_R 88 +#define EL_FLIEGER_O 89 +#define EL_FLIEGER_L 90 +#define EL_FLIEGER_U 91 +#define EL_PACMAN_R 92 +#define EL_PACMAN_O 93 +#define EL_PACMAN_L 94 +#define EL_PACMAN_U 95 +#define EL_EDELSTEIN_ROT 96 +#define EL_EDELSTEIN_LILA 97 +#define EL_ERZ_EDEL_ROT 98 +#define EL_ERZ_EDEL_LILA 99 +#define EL_BADEWANNE1 100 +#define EL_BADEWANNE2 101 +#define EL_BADEWANNE3 102 +#define EL_BADEWANNE4 103 +#define EL_BADEWANNE5 104 +#define EL_SIEB_TOT 105 +#define EL_AUSGANG_ACT 106 +#define EL_AUSGANG_AUF 107 +#define EL_SIEB2_TOT 108 +#define EL_AMOEBA2DIAM 109 +#define EL_MAULWURF 110 +#define EL_PINGUIN 111 +#define EL_SONDE 112 +#define EL_PFEIL_L 113 +#define EL_PFEIL_R 114 +#define EL_PFEIL_O 115 +#define EL_PFEIL_U 116 +#define EL_SCHWEIN 117 +#define EL_DRACHE 118 + +#define EL_UNUSED_119 119 + +#define EL_CHAR_START 120 +#define EL_CHAR_ASCII0 (EL_CHAR_START-32) +#define EL_CHAR_AUSRUF (EL_CHAR_ASCII0+33) +#define EL_CHAR_ZOLL (EL_CHAR_ASCII0+34) +#define EL_CHAR_DOLLAR (EL_CHAR_ASCII0+36) +#define EL_CHAR_PROZ (EL_CHAR_ASCII0+37) +#define EL_CHAR_APOSTR (EL_CHAR_ASCII0+39) +#define EL_CHAR_KLAMM1 (EL_CHAR_ASCII0+40) +#define EL_CHAR_KLAMM2 (EL_CHAR_ASCII0+41) +#define EL_CHAR_PLUS (EL_CHAR_ASCII0+43) +#define EL_CHAR_KOMMA (EL_CHAR_ASCII0+44) +#define EL_CHAR_MINUS (EL_CHAR_ASCII0+45) +#define EL_CHAR_PUNKT (EL_CHAR_ASCII0+46) +#define EL_CHAR_SLASH (EL_CHAR_ASCII0+47) +#define EL_CHAR_0 (EL_CHAR_ASCII0+48) +#define EL_CHAR_9 (EL_CHAR_ASCII0+57) +#define EL_CHAR_DOPPEL (EL_CHAR_ASCII0+58) +#define EL_CHAR_SEMIKL (EL_CHAR_ASCII0+59) +#define EL_CHAR_LT (EL_CHAR_ASCII0+60) +#define EL_CHAR_GLEICH (EL_CHAR_ASCII0+61) +#define EL_CHAR_GT (EL_CHAR_ASCII0+62) +#define EL_CHAR_FRAGE (EL_CHAR_ASCII0+63) +#define EL_CHAR_AT (EL_CHAR_ASCII0+64) +#define EL_CHAR_A (EL_CHAR_ASCII0+65) +#define EL_CHAR_Z (EL_CHAR_ASCII0+90) +#define EL_CHAR_AE (EL_CHAR_ASCII0+91) +#define EL_CHAR_OE (EL_CHAR_ASCII0+92) +#define EL_CHAR_UE (EL_CHAR_ASCII0+93) +#define EL_CHAR_COPY (EL_CHAR_ASCII0+94) +#define EL_CHAR_END (EL_CHAR_START+79) + +#define EL_MAUER_X 200 +#define EL_MAUER_Y 201 +#define EL_MAUER_XY 202 + +#define EL_UNUSED_200 203 +/* ... */ +#define EL_UNUSED_255 255 /* "unreal" runtime elements */ -#define EL_BLOCKED 300 -#define EL_EXPLODING 301 -#define EL_CRACKINGNUT 302 -#define EL_BLURB_LEFT 303 -#define EL_BLURB_RIGHT 304 -#define EL_AMOEBING 305 - -/* names for the graphic objects */ +#define EL_BLOCKED 300 +#define EL_EXPLODING 301 +#define EL_CRACKINGNUT 302 +#define EL_BLURB_LEFT 303 +#define EL_BLURB_RIGHT 304 +#define EL_AMOEBING 305 +#define EL_MAUERND 306 +#define EL_BURNING 307 +#define EL_PLAYER_IS_LEAVING 308 + +/* game graphics: +** 0 - 255: graphics from "RocksScreen" +** 256 - 511: graphics from "RocksFont" +** 512 - 767: graphics from "RocksHeroes" +*/ + +#define GFX_START_ROCKSSCREEN 0 +#define GFX_END_ROCKSSCREEN 255 +#define GFX_START_ROCKSFONT 256 +#define GFX_END_ROCKSFONT 511 +#define GFX_START_ROCKSHEROES 512 +#define GFX_END_ROCKSHEROES 767 + +#define NUM_TILES 768 + +/* graphics from "RocksScreen" */ /* Zeile 0 (0) */ -#define GFX_LEERRAUM (-1) -#define GFX_ERDREICH 0 -#define GFX_ERDENRAND 1 -#define GFX_MORAST_LEER 2 -#define GFX_MORAST_VOLL 3 -#define GFX_BETON 4 -#define GFX_MAUERWERK 5 -#define GFX_FELSBODEN 6 -#define GFX_BOMBE_MM 7 -#define GFX_EDELSTEIN 8 -#define GFX_DIAMANT 10 -#define GFX_FELSBROCKEN 12 +#define GFX_LEERRAUM (-1) +#define GFX_ERDREICH 0 +#define GFX_ERDENRAND 1 +#define GFX_MORAST_LEER 2 +#define GFX_MORAST_VOLL 3 +#define GFX_BETON 4 +#define GFX_MAUERWERK 5 +#define GFX_FELSBODEN 6 +#define GFX_EDELSTEIN 8 +#define GFX_DIAMANT 10 +#define GFX_FELSBROCKEN 12 /* Zeile 1 (16) */ -#define GFX_BADEWANNE1 16 -#define GFX_SALZSAEURE 17 -#define GFX_BADEWANNE2 18 -#define GFX_UNSICHTBAR 19 -#define GFX_SCHLUESSEL1 20 -#define GFX_SCHLUESSEL2 21 -#define GFX_SCHLUESSEL3 22 -#define GFX_SCHLUESSEL4 23 -#define GFX_LIFE 24 -#define GFX_LIFE_ASYNC 25 -#define GFX_BADEWANNE 26 -#define GFX_BOMBE 27 -#define GFX_KOKOSNUSS 28 -#define GFX_CRACKINGNUT 29 +#define GFX_BADEWANNE1 16 +#define GFX_SALZSAEURE 17 +#define GFX_BADEWANNE2 18 +#define GFX_UNSICHTBAR 19 +#define GFX_SCHLUESSEL1 20 +#define GFX_SCHLUESSEL2 21 +#define GFX_SCHLUESSEL3 22 +#define GFX_SCHLUESSEL4 23 +#define GFX_LIFE 24 +#define GFX_LIFE_ASYNC 25 +#define GFX_BADEWANNE 26 +#define GFX_BOMBE 27 +#define GFX_KOKOSNUSS 28 +#define GFX_CRACKINGNUT 29 /* Zeile 2 (32) */ -#define GFX_BADEWANNE3 32 -#define GFX_BADEWANNE4 33 -#define GFX_BADEWANNE5 34 -#define GFX_SPIELFIGUR 35 -#define GFX_PFORTE1 36 -#define GFX_PFORTE2 37 -#define GFX_PFORTE3 38 -#define GFX_PFORTE4 39 -#define GFX_PFORTE1X 40 -#define GFX_PFORTE2X 41 -#define GFX_PFORTE3X 42 -#define GFX_PFORTE4X 43 -#define GFX_AUSGANG_ZU 44 -#define GFX_AUSGANG_ACT 44 -#define GFX_AUSGANG_AUF 47 +#define GFX_BADEWANNE3 32 +#define GFX_BADEWANNE4 33 +#define GFX_BADEWANNE5 34 +#define GFX_SMILEY 35 +#define GFX_PFORTE1 36 +#define GFX_PFORTE2 37 +#define GFX_PFORTE3 38 +#define GFX_PFORTE4 39 +#define GFX_PFORTE1X 40 +#define GFX_PFORTE2X 41 +#define GFX_PFORTE3X 42 +#define GFX_PFORTE4X 43 /* Zeile 3 (48) */ -#define GFX_DYNAMIT_AUS 48 -#define GFX_DYNAMIT 49 -#define GFX_FLIEGER 56 -#define GFX_FLIEGER_R 56 -#define GFX_FLIEGER_O 57 -#define GFX_FLIEGER_L 58 -#define GFX_FLIEGER_U 59 +#define GFX_DYNAMIT_AUS 48 +#define GFX_DYNAMIT 49 +#define GFX_FLIEGER 56 +#define GFX_FLIEGER_R 56 +#define GFX_FLIEGER_O 57 +#define GFX_FLIEGER_L 58 +#define GFX_FLIEGER_U 59 /* Zeile 4 (64) */ -#define GFX_EXPLOSION 64 -#define GFX_KAEFER 72 -#define GFX_KAEFER_R 72 -#define GFX_KAEFER_O 73 -#define GFX_KAEFER_L 74 -#define GFX_KAEFER_U 75 +#define GFX_EXPLOSION 64 +#define GFX_KAEFER 72 +#define GFX_KAEFER_R 72 +#define GFX_KAEFER_O 73 +#define GFX_KAEFER_L 74 +#define GFX_KAEFER_U 75 /* Zeile 5 (80) */ -#define GFX_MAMPFER 80 -#define GFX_ZOMBIE 84 -#define GFX_PACMAN 88 -#define GFX_PACMAN_R 88 -#define GFX_PACMAN_O 89 -#define GFX_PACMAN_L 90 -#define GFX_PACMAN_U 91 +#define GFX_MAMPFER 80 +#define GFX_ROBOT 84 +#define GFX_PACMAN 88 +#define GFX_PACMAN_R 88 +#define GFX_PACMAN_O 89 +#define GFX_PACMAN_L 90 +#define GFX_PACMAN_U 91 /* Zeile 6 (96) */ -#define GFX_ABLENK 96 -#define GFX_ABLENK_EIN GFX_ABLENK -#define GFX_ABLENK_AUS GFX_ABLENK -#define GFX_AMOEBE_NASS 100 -#define GFX_TROPFEN 101 -#define GFX_AMOEBING GFX_TROPFEN -#define GFX_AMOEBE_LEBT 104 -#define GFX_AMOEBE_NORM GFX_AMOEBE_LEBT -#define GFX_AMOEBE_TOT 108 -#define GFX_AMOEBA2DIAM GFX_AMOEBE_TOT -#define GFX_ZEIT_VOLL 114 -#define GFX_ZEIT_LEER 115 +#define GFX_ABLENK 96 +#define GFX_ABLENK_EIN GFX_ABLENK +#define GFX_ABLENK_AUS GFX_ABLENK +#define GFX_AMOEBE_NASS 100 +#define GFX_TROPFEN 101 +#define GFX_AMOEBING GFX_TROPFEN +#define GFX_AMOEBE_LEBT 104 +#define GFX_AMOEBE_NORM GFX_AMOEBE_LEBT +#define GFX_AMOEBE_TOT 108 +#define GFX_AMOEBA2DIAM GFX_AMOEBE_TOT /* Zeile 7 (112) */ -#define GFX_GEBLUBBER 124 +#define GFX_BIRNE_AUS 112 +#define GFX_BIRNE_EIN 113 +#define GFX_ZEIT_VOLL 114 +#define GFX_ZEIT_LEER 115 +#define GFX_SPIELER1 116 +#define GFX_SPIELER2 117 +#define GFX_SPIELER3 118 +#define GFX_SPIELER4 119 +#define GFX_AMOEBE_VOLL 120 +#define GFX_AMOEBE_BD GFX_AMOEBE_VOLL +#define GFX_SOKOBAN_OBJEKT 121 +#define GFX_SOKOBAN_FELD_LEER 122 +#define GFX_SOKOBAN_FELD_VOLL 123 +#define GFX_GEBLUBBER 124 /* Zeile 8 (128) */ -#define GFX_SIEB_LEER 128 -#define GFX_SIEB_VOLL GFX_SIEB_LEER -#define GFX_SIEB_TOT GFX_SIEB_LEER -#define GFX_ERZ_EDEL 132 -#define GFX_ERZ_DIAM 133 -#define GFX_BIRNE_AUS 134 -#define GFX_BIRNE_EIN 135 -#define GFX_AMOEBE_VOLL 136 -#define GFX_KUGEL_ROT 140 -#define GFX_KUGEL_BLAU 141 -#define GFX_KUGEL_GELB 142 +#define GFX_SIEB_LEER 128 +#define GFX_SIEB_VOLL GFX_SIEB_LEER +#define GFX_SIEB_TOT GFX_SIEB_LEER +#define GFX_ERZ_EDEL 132 +#define GFX_ERZ_DIAM 133 +#define GFX_ERZ_EDEL_ROT 134 +#define GFX_ERZ_EDEL_LILA 135 +#define GFX_ERZ_EDEL_GELB 136 +#define GFX_ERZ_EDEL_BD 137 +#define GFX_EDELSTEIN_GELB 138 +#define GFX_KUGEL_ROT 140 +#define GFX_KUGEL_BLAU 141 +#define GFX_KUGEL_GELB 142 +#define GFX_KUGEL_GRAU 143 /* Zeile 9 (144) */ -#define GFX_BLURB_LEFT 144 -#define GFX_BLURB_RIGHT 148 - -#define GFX_SCHLUESSEL GFX_SCHLUESSEL1 - -#define GFX_SPIELER1 116 -#define GFX_SPIELER2 117 -#define GFX_SPIELER3 118 -#define GFX_SPIELER4 119 - -/* nicht in "RocksScreen" sondern woanders :) */ -#define GFX_CHAR_START 256 -#define GFX_CHAR_ASCII0 (GFX_CHAR_START-32) -#define GFX_CHAR_AUSRUF (GFX_CHAR_ASCII0+33) -#define GFX_CHAR_ZOLL (GFX_CHAR_ASCII0+34) -#define GFX_CHAR_DOLLAR (GFX_CHAR_ASCII0+36) -#define GFX_CHAR_PROZ (GFX_CHAR_ASCII0+37) -#define GFX_CHAR_APOSTR (GFX_CHAR_ASCII0+39) -#define GFX_CHAR_KLAMM1 (GFX_CHAR_ASCII0+40) -#define GFX_CHAR_KLAMM2 (GFX_CHAR_ASCII0+41) -#define GFX_CHAR_PLUS (GFX_CHAR_ASCII0+43) -#define GFX_CHAR_KOMMA (GFX_CHAR_ASCII0+44) -#define GFX_CHAR_MINUS (GFX_CHAR_ASCII0+45) -#define GFX_CHAR_PUNKT (GFX_CHAR_ASCII0+46) -#define GFX_CHAR_SLASH (GFX_CHAR_ASCII0+47) -#define GFX_CHAR_0 (GFX_CHAR_ASCII0+48) -#define GFX_CHAR_9 (GFX_CHAR_ASCII0+57) -#define GFX_CHAR_DOPPEL (GFX_CHAR_ASCII0+58) -#define GFX_CHAR_SEMIKL (GFX_CHAR_ASCII0+59) -#define GFX_CHAR_LT (GFX_CHAR_ASCII0+60) -#define GFX_CHAR_GLEICH (GFX_CHAR_ASCII0+61) -#define GFX_CHAR_GT (GFX_CHAR_ASCII0+62) -#define GFX_CHAR_FRAGE (GFX_CHAR_ASCII0+63) -#define GFX_CHAR_AT (GFX_CHAR_ASCII0+64) -#define GFX_CHAR_A (GFX_CHAR_ASCII0+65) -#define GFX_CHAR_Z (GFX_CHAR_ASCII0+90) -#define GFX_CHAR_AE (GFX_CHAR_ASCII0+91) -#define GFX_CHAR_OE (GFX_CHAR_ASCII0+92) -#define GFX_CHAR_UE (GFX_CHAR_ASCII0+93) -#define GFX_CHAR_COPY (GFX_CHAR_ASCII0+94) -#define GFX_CHAR_END (GFX_CHAR_START+79) - -/* score for elements */ -#define SC_EDELSTEIN 0 -#define SC_DIAMANT 1 -#define SC_KAEFER 2 -#define SC_FLIEGER 3 -#define SC_MAMPFER 4 -#define SC_ZOMBIE 5 -#define SC_PACMAN 6 -#define SC_KOKOSNUSS 7 -#define SC_DYNAMIT 8 -#define SC_SCHLUESSEL 9 -#define SC_ZEITBONUS 10 +#define GFX_PINGUIN 144 +#define GFX_MAULWURF 145 +#define GFX_SCHWEIN 146 +#define GFX_DRACHE 147 +#define GFX_MAUER_XY 148 +#define GFX_MAUER_X 149 +#define GFX_MAUER_Y 150 +#define GFX_EDELSTEIN_ROT 152 +#define GFX_EDELSTEIN_LILA 154 +#define GFX_DYNABOMB_XL 156 +#define GFX_SONDE 159 +/* Zeile 10 (160) */ +#define GFX_EDELSTEIN_BD 163 +#define GFX_MAUER_RIGHT 165 +#define GFX_MAUER_R1 GFX_MAUER_RIGHT +#define GFX_MAUER_R 167 +#define GFX_MAUER_LEFT 168 +#define GFX_MAUER_L1 GFX_MAUER_LEFT +#define GFX_MAUER_L 170 +#define GFX_MAUER_LEBT 171 +#define GFX_SIEB2_LEER 172 +#define GFX_SIEB2_VOLL GFX_SIEB2_LEER +#define GFX_SIEB2_TOT GFX_SIEB2_LEER +/* Zeile 11 (176) */ +#define GFX_AUSGANG_ZU 176 +#define GFX_AUSGANG_ACT 177 +#define GFX_AUSGANG_AUF 180 +#define GFX_MAMPFER2 184 +#define GFX_DYNABOMB 188 +#define GFX_DYNABOMB_NR 188 +#define GFX_DYNABOMB_SZ 191 +/* Zeile 12 (192) */ +#define GFX_PFEIL_L 192 +#define GFX_PFEIL_R 193 +#define GFX_PFEIL_O 194 +#define GFX_PFEIL_U 195 +#define GFX_BUTTERFLY 196 +#define GFX_FIREFLY 198 +#define GFX_BUTTERFLY_R 200 +#define GFX_BUTTERFLY_O 201 +#define GFX_BUTTERFLY_L 202 +#define GFX_BUTTERFLY_U 203 +#define GFX_FIREFLY_R 204 +#define GFX_FIREFLY_O 205 +#define GFX_FIREFLY_L 206 +#define GFX_FIREFLY_U 207 + +#define GFX_SCHLUESSEL GFX_SCHLUESSEL1 +#define GFX_SPIELFIGUR GFX_SPIELER1 + + +/* graphics from "RocksHeroes" */ + +#define GFX_SPIELER1_DOWN (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 0) +#define GFX_SPIELER1_UP (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 4) +#define GFX_SPIELER1_LEFT (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 0) +#define GFX_SPIELER1_RIGHT (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 4) +#define GFX_SPIELER1_PUSH_RIGHT (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 0) +#define GFX_SPIELER1_PUSH_LEFT (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 4) +#define GFX_SPIELER2_DOWN (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 0) +#define GFX_SPIELER2_UP (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 4) +#define GFX_SPIELER2_LEFT (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 0) +#define GFX_SPIELER2_RIGHT (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 4) +#define GFX_SPIELER2_PUSH_RIGHT (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 0) +#define GFX_SPIELER2_PUSH_LEFT (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 4) +#define GFX_SPIELER3_DOWN (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 0) +#define GFX_SPIELER3_UP (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 4) +#define GFX_SPIELER3_LEFT (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 0) +#define GFX_SPIELER3_RIGHT (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 4) +#define GFX_SPIELER3_PUSH_RIGHT (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 0) +#define GFX_SPIELER3_PUSH_LEFT (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 4) +#define GFX_SPIELER4_DOWN (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 0) +#define GFX_SPIELER4_UP (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 4) +#define GFX_SPIELER4_LEFT (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 0) +#define GFX_SPIELER4_RIGHT (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 4) +#define GFX_SPIELER4_PUSH_RIGHT (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 0) +#define GFX_SPIELER4_PUSH_LEFT (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 4) +#define GFX_MAUER_DOWN (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 0) +#define GFX_MAUER_UP (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 3) + +#define GFX_SONDE_START (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 8) +#define GFX_SCHWEIN_DOWN (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 8) +#define GFX_SCHWEIN_UP (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE +12) +#define GFX_SCHWEIN_LEFT (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 8) +#define GFX_SCHWEIN_RIGHT (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE +12) +#define GFX_DRACHE_DOWN (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 8) +#define GFX_DRACHE_UP (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE +12) +#define GFX_DRACHE_LEFT (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 8) +#define GFX_DRACHE_RIGHT (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE +12) +#define GFX_MAULWURF_DOWN (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 8) +#define GFX_MAULWURF_UP (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE +12) +#define GFX_MAULWURF_LEFT (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 8) +#define GFX_MAULWURF_RIGHT (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE +12) +#define GFX_PINGUIN_DOWN (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 8) +#define GFX_PINGUIN_UP (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE +12) +#define GFX_PINGUIN_LEFT (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 8) +#define GFX_PINGUIN_RIGHT (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE +12) +#define GFX_BLURB_LEFT (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 8) +#define GFX_BLURB_RIGHT (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE +12) +#define GFX_FUNKELN_BLAU (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 8) +#define GFX_FUNKELN_WEISS (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE +12) +#define GFX_FLAMMEN_LEFT (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 8) +#define GFX_FLAMMEN_RIGHT (GFX_START_ROCKSHEROES +13*HEROES_PER_LINE + 8) +#define GFX_FLAMMEN_UP (GFX_START_ROCKSHEROES +14*HEROES_PER_LINE + 8) +#define GFX_FLAMMEN_DOWN (GFX_START_ROCKSHEROES +15*HEROES_PER_LINE + 8) + +/* graphics from "RocksFont" */ +#define GFX_CHAR_START (GFX_START_ROCKSFONT) +#define GFX_CHAR_ASCII0 (GFX_CHAR_START-32) +#define GFX_CHAR_AUSRUF (GFX_CHAR_ASCII0+33) +#define GFX_CHAR_ZOLL (GFX_CHAR_ASCII0+34) +#define GFX_CHAR_DOLLAR (GFX_CHAR_ASCII0+36) +#define GFX_CHAR_PROZ (GFX_CHAR_ASCII0+37) +#define GFX_CHAR_APOSTR (GFX_CHAR_ASCII0+39) +#define GFX_CHAR_KLAMM1 (GFX_CHAR_ASCII0+40) +#define GFX_CHAR_KLAMM2 (GFX_CHAR_ASCII0+41) +#define GFX_CHAR_PLUS (GFX_CHAR_ASCII0+43) +#define GFX_CHAR_KOMMA (GFX_CHAR_ASCII0+44) +#define GFX_CHAR_MINUS (GFX_CHAR_ASCII0+45) +#define GFX_CHAR_PUNKT (GFX_CHAR_ASCII0+46) +#define GFX_CHAR_SLASH (GFX_CHAR_ASCII0+47) +#define GFX_CHAR_0 (GFX_CHAR_ASCII0+48) +#define GFX_CHAR_9 (GFX_CHAR_ASCII0+57) +#define GFX_CHAR_DOPPEL (GFX_CHAR_ASCII0+58) +#define GFX_CHAR_SEMIKL (GFX_CHAR_ASCII0+59) +#define GFX_CHAR_LT (GFX_CHAR_ASCII0+60) +#define GFX_CHAR_GLEICH (GFX_CHAR_ASCII0+61) +#define GFX_CHAR_GT (GFX_CHAR_ASCII0+62) +#define GFX_CHAR_FRAGE (GFX_CHAR_ASCII0+63) +#define GFX_CHAR_AT (GFX_CHAR_ASCII0+64) +#define GFX_CHAR_A (GFX_CHAR_ASCII0+65) +#define GFX_CHAR_Z (GFX_CHAR_ASCII0+90) +#define GFX_CHAR_AE (GFX_CHAR_ASCII0+91) +#define GFX_CHAR_OE (GFX_CHAR_ASCII0+92) +#define GFX_CHAR_UE (GFX_CHAR_ASCII0+93) +#define GFX_CHAR_COPY (GFX_CHAR_ASCII0+94) +#define GFX_CHAR_END (GFX_CHAR_START+79) /* the names of the sounds */ -#define SND_ALCHEMY 0 -#define SND_AMOEBE 1 -#define SND_ANTIGRAV 2 -#define SND_AUTSCH 3 -#define SND_BLURB 4 -#define SND_BONG 5 -#define SND_BUING 6 -#define SND_CHASE 7 -#define SND_CZARDASZ 8 -#define SND_DENG 9 -#define SND_FUEL 10 -#define SND_GONG 11 -#define SND_HALLOFFAME 12 -#define SND_HOLZ 13 -#define SND_HUI 14 -#define SND_KABUMM 15 -#define SND_KINK 16 -#define SND_KLAPPER 17 -#define SND_KLING 18 -#define SND_KLOPF 19 -#define SND_KLUMPF 20 -#define SND_KNACK 21 -#define SND_KNURK 22 -#define SND_KRACH 23 -#define SND_LACHEN 24 -#define SND_LASER 25 -#define SND_MIEP 26 -#define SND_NETWORK 27 -#define SND_NJAM 28 -#define SND_OEFFNEN 29 -#define SND_PLING 30 -#define SND_PONG 31 -#define SND_PUSCH 32 -#define SND_QUIEK 33 -#define SND_QUIRK 34 -#define SND_RHYTHMLOOP 35 -#define SND_ROAAAR 36 -#define SND_ROEHR 37 -#define SND_RUMMS 38 -#define SND_SCHLOPP 39 -#define SND_SCHLURF 40 -#define SND_SCHRFF 41 -#define SND_SCHWIRR 42 -#define SND_SIRR 43 -#define SND_SLURP 44 -#define SND_SPROING 45 -#define SND_TWILIGHT 46 -#define SND_TYGER 47 -#define SND_VOYAGER 48 -#define SND_WARNTON 49 -#define SND_WHOOSH 50 -#define SND_ZISCH 51 - -#define NUM_SOUNDS 52 - -#define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \ - (s)==SND_NJAM || (s)==SND_MIEP) -#define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \ - (s)==SND_NETWORK || (s)==SND_CZARDASZ || \ - (s)==SND_TYGER || (s)==SND_VOYAGER || \ - (s)==SND_TWILIGHT) -extern char *sound_name[NUM_SOUNDS]; - -/* this structure contains the sound data for the sound server */ -extern struct SoundInfo Sound[NUM_SOUNDS]; +#define SND_ALCHEMY 0 +#define SND_AMOEBE 1 +#define SND_ANTIGRAV 2 +#define SND_AUTSCH 3 +#define SND_BLURB 4 +#define SND_BONG 5 +#define SND_BUING 6 +#define SND_CHASE 7 +#define SND_CZARDASZ 8 +#define SND_DENG 9 +#define SND_FUEL 10 +#define SND_GONG 11 +#define SND_HALLOFFAME 12 +#define SND_HOLZ 13 +#define SND_HUI 14 +#define SND_KABUMM 15 +#define SND_KINK 16 +#define SND_KLAPPER 17 +#define SND_KLING 18 +#define SND_KLOPF 19 +#define SND_KLUMPF 20 +#define SND_KNACK 21 +#define SND_KNURK 22 +#define SND_KRACH 23 +#define SND_LACHEN 24 +#define SND_LASER 25 +#define SND_MIEP 26 +#define SND_NETWORK 27 +#define SND_NJAM 28 +#define SND_OEFFNEN 29 +#define SND_PLING 30 +#define SND_PONG 31 +#define SND_PUSCH 32 +#define SND_QUIEK 33 +#define SND_QUIRK 34 +#define SND_RHYTHMLOOP 35 +#define SND_ROAAAR 36 +#define SND_ROEHR 37 +#define SND_RUMMS 38 +#define SND_SCHLOPP 39 +#define SND_SCHLURF 40 +#define SND_SCHRFF 41 +#define SND_SCHWIRR 42 +#define SND_SIRR 43 +#define SND_SLURP 44 +#define SND_SPROING 45 +#define SND_TWILIGHT 46 +#define SND_TYGER 47 +#define SND_VOYAGER 48 +#define SND_WARNTON 49 +#define SND_WHOOSH 50 +#define SND_ZISCH 51 + +#define NUM_SOUNDS 52 + +/* default input keys */ +#define KEY_UNDEFINDED XK_VoidSymbol +#define DEFAULT_KEY_LEFT XK_Left +#define DEFAULT_KEY_RIGHT XK_Right +#define DEFAULT_KEY_UP XK_Up +#define DEFAULT_KEY_DOWN XK_Down +#define DEFAULT_KEY_SNAP XK_Shift_L +#define DEFAULT_KEY_BOMB XK_Shift_R +#define DEFAULT_KEY_OKAY XK_Return +#define DEFAULT_KEY_CANCEL XK_Escape /* directions for moving */ -#define MV_NO_MOVING 0 -#define MV_LEFT 1 -#define MV_RIGHT 2 -#define MV_UP 4 -#define MV_DOWN 8 +#define MV_NO_MOVING 0 +#define MV_LEFT (1<<0) +#define MV_RIGHT (1<<1) +#define MV_UP (1<<2) +#define MV_DOWN (1<<3) /* font types */ -#define FS_SMALL 0 -#define FS_BIG 1 +#define FS_SMALL 0 +#define FS_BIG 1 /* font colors */ -#define FC_RED 0 -#define FC_BLUE 1 -#define FC_GREEN 2 -#define FC_YELLOW 3 -#define FC_SPECIAL1 4 -#define FC_SPECIAL2 5 +#define FC_RED 0 +#define FC_BLUE 1 +#define FC_GREEN 2 +#define FC_YELLOW 3 +#define FC_SPECIAL1 4 +#define FC_SPECIAL2 5 /* values for game_status */ -#define MAINMENU 0 -#define PLAYING 1 -#define LEVELED 2 -#define HELPSCREEN 3 -#define CHOOSELEVEL 4 -#define TYPENAME 5 -#define HALLOFFAME 6 -#define SETUP 7 -#define EXITGAME 8 - -/* return values for GameActions */ -#define ACT_GO_ON 0 -#define ACT_GAME_OVER 1 -#define ACT_NEW_GAME 2 - -/* values for the joystick */ -#define JOYSTICK_OFF 0 -#define JOYSTICK_AVAILABLE 1 -#ifdef __FreeBSD__ -#define DEV_JOYSTICK_0 "/dev/joy0" -#define DEV_JOYSTICK_1 "/dev/joy1" -#else -#define DEV_JOYSTICK_0 "/dev/js0" -#define DEV_JOYSTICK_1 "/dev/js1" -#endif - -/* get these values from the program 'js' from the joystick package, */ -/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */ -#define JOYSTICK_XLEFT 30 -#define JOYSTICK_XRIGHT 1250 -#define JOYSTICK_XMIDDLE 530 -#define JOYSTICK_YUPPER 40 -#define JOYSTICK_YLOWER 1440 -#define JOYSTICK_YMIDDLE 680 -#define JOYSTICK_PERCENT 25 -#define JOY_LEFT MV_LEFT -#define JOY_RIGHT MV_RIGHT -#define JOY_UP MV_UP -#define JOY_DOWN MV_DOWN -#define JOY_BUTTON_1 16 -#define JOY_BUTTON_2 32 -#define JOY_BUTTON (JOY_BUTTON_1 | JOY_BUTTON_2) -#define JOY_BUTTON_NOT_PRESSED 0 -#define JOY_BUTTON_PRESSED 1 -#define JOY_BUTTON_NEW_PRESSED 2 -#define JOY_BUTTON_NEW_RELEASED 3 - -#ifdef NO_JOYSTICK -#define JOYSTICK_STATUS JOYSTICK_OFF -#else -#define JOYSTICK_STATUS JOYSTICK_AVAILABLE -#endif +#define EXITGAME 0 +#define MAINMENU 1 +#define PLAYING 2 +#define LEVELED 3 +#define HELPSCREEN 4 +#define CHOOSELEVEL 5 +#define TYPENAME 6 +#define HALLOFFAME 7 +#define SETUP 8 +#define SETUPINPUT 9 +#define CALIBRATION 10 #ifndef GAME_DIR -#define GAME_DIR "." +#define GAME_DIR "." #endif -#ifndef GFX_PATH -#define GFX_PATH GAME_DIR "/graphics" -#endif -#ifndef SND_PATH -#define SND_PATH GAME_DIR "/sounds" -#endif -#ifndef LEVEL_PATH -#define LEVEL_PATH GAME_DIR "/levels" -#endif -#ifndef SCORE_PATH -#define SCORE_PATH LEVEL_PATH -#endif -#ifndef NAMES_PATH -#define NAMES_PATH LEVEL_PATH -#endif -#ifndef CONFIG_PATH -#define CONFIG_PATH GAME_DIR -#endif -#ifndef JOYDAT_PATH -#define JOYDAT_PATH GAME_DIR -#endif +#define BASE_PATH GAME_DIR -#define SCORE_FILENAME "ROCKS.score" -#define NAMES_FILENAME "ROCKS.names" -#define LEVDIR_FILENAME "ROCKS.levelinfo" -#define JOYDAT_FILENAME "ROCKS.joystick" - -#define JOYDAT_FILE JOYDAT_PATH "/" JOYDAT_FILENAME - -#define LEVEL_PERMS (S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH) -#define SCORE_PERMS LEVEL_PERMS -#define NAMES_PERMS LEVEL_PERMS -#define LEVDIR_PERMS LEVEL_PERMS -#define LEVREC_PERMS LEVEL_PERMS -#define JOYDAT_PERMS LEVEL_PERMS - -#define LEVEL_COOKIE "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.0" -#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.0" -#define NAMES_COOKIE "ROCKSNDIAMONDS_NAMES_FILE_VERSION_1.0" -#define LEVELDIR_COOKIE "ROCKSNDIAMONDS_LEVELDIR_FILE_VERSION_1.0" -#define LEVELREC_COOKIE "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0" -#define JOYSTICK_COOKIE "ROCKSNDIAMONDS_JOYSTICK_FILE_VERSION_1.0" -#define LEVEL_COOKIE_LEN (strlen(LEVEL_COOKIE)+1) -#define SCORE_COOKIE_LEN (strlen(SCORE_COOKIE)+1) -#define NAMES_COOKIE_LEN (strlen(NAMES_COOKIE)+1) -#define LEVELDIR_COOKIE_LEN (strlen(LEVELDIR_COOKIE)+1) -#define LEVELREC_COOKIE_LEN (strlen(LEVELREC_COOKIE)+1) -#define JOYSTICK_COOKIE_LEN (strlen(JOYSTICK_COOKIE)+1) - -/* Leerer Login- und Alias-Name */ -#define EMPTY_LOGIN "NO_LOGIN" -#define EMPTY_ALIAS "NO_NAME" +#define GRAPHICS_DIRECTORY "graphics" +#define SOUNDS_DIRECTORY "sounds" +#define LEVELS_DIRECTORY "levels" +#define TAPES_DIRECTORY "tapes" +#define SCORES_DIRECTORY "scores" + +#define VERSION_STRING "1.2.0" +#define GAMETITLE_STRING "Rocks'n'Diamonds" +#define WINDOWTITLE_STRING GAMETITLE_STRING " " VERSION_STRING +#define COPYRIGHT_STRING "Copyright ^1995-98 by Holger Schemel" + +/* default name for empty highscore entry */ +#define EMPTY_PLAYER_NAME "no name" /* values for button_status */ -#define MB_NOT_PRESSED FALSE -#define MB_RELEASED FALSE -#define MB_PRESSED TRUE -#define MB_MENU_CHOICE FALSE -#define MB_MENU_MARK TRUE -#define MB_LEFT 1 -#define MB_MIDDLE 2 -#define MB_RIGHT 3 - -/* values for key_status */ -#define KEY_NOT_PRESSED FALSE -#define KEY_RELEASED FALSE -#define KEY_PRESSED TRUE - -/* values for focus_status */ -#define FOCUS_OUT FALSE -#define FOCUS_IN TRUE +#define MB_NOT_PRESSED FALSE +#define MB_RELEASED FALSE +#define MB_PRESSED TRUE +#define MB_MENU_CHOICE FALSE +#define MB_MENU_MARK TRUE +#define MB_MENU_INITIALIZE (-1) +#define MB_LEFT 1 +#ifdef MSDOS +#define MB_MIDDLE 4 +#define MB_RIGHT 2 +#else +#define MB_MIDDLE 2 +#define MB_RIGHT 3 +#endif /* values for redraw_mask */ -#define REDRAW_ALL (1L<<0) -#define REDRAW_FIELD (1L<<1) -#define REDRAW_TILES (1L<<2) -#define REDRAW_DOOR_1 (1L<<3) -#define REDRAW_VIDEO_1 (1L<<4) -#define REDRAW_VIDEO_2 (1L<<5) -#define REDRAW_VIDEO_3 (1L<<6) -#define REDRAW_MICROLEV (1L<<7) +#define REDRAW_ALL (1L<<0) +#define REDRAW_FIELD (1L<<1) +#define REDRAW_TILES (1L<<2) +#define REDRAW_DOOR_1 (1L<<3) +#define REDRAW_VIDEO_1 (1L<<4) +#define REDRAW_VIDEO_2 (1L<<5) +#define REDRAW_VIDEO_3 (1L<<6) +#define REDRAW_MICROLEV (1L<<7) +#define REDRAW_FROM_BACKBUFFER (1L<<8) #define REDRAW_DOOR_2 (REDRAW_VIDEO_1 | REDRAW_VIDEO_2 | REDRAW_VIDEO_3) #define REDRAW_DOORS (REDRAW_DOOR_1 | REDRAW_DOOR_2) #define REDRAW_MAIN (REDRAW_FIELD | REDRAW_TILES | REDRAW_MICROLEV) -#define REDRAWTILES_TH SCR_FIELDX*SCR_FIELDY/2 - -/* positions in the game control window */ -#define XX_LEVEL 37 -#define YY_LEVEL 20 -#define XX_EMERALDS 29 -#define YY_EMERALDS 54 -#define XX_DYNAMITE 29 -#define YY_DYNAMITE 89 -#define XX_KEYS 18 -#define YY_KEYS 123 -#define XX_SCORE 15 -#define YY_SCORE 159 -#define XX_TIME 29 -#define YY_TIME 194 - -#define DX_LEVEL (DX+XX_LEVEL) -#define DY_LEVEL (DY+YY_LEVEL) -#define DX_EMERALDS (DX+XX_EMERALDS) -#define DY_EMERALDS (DY+YY_EMERALDS) -#define DX_DYNAMITE (DX+XX_DYNAMITE) -#define DY_DYNAMITE (DY+YY_DYNAMITE) -#define DX_KEYS (DX+XX_KEYS) -#define DY_KEYS (DY+YY_KEYS) -#define DX_SCORE (DX+XX_SCORE) -#define DY_SCORE (DY+YY_SCORE) -#define DX_TIME (DX+XX_TIME) -#define DY_TIME (DY+YY_TIME) - -/* Felder in PIX_DOOR */ -/* Bedeutung in PIX_DB_DOOR: (3 PAGEs) - PAGEX1: 1. Zwischenspeicher für DOOR_1 - PAGEX2: 2. Zwischenspeicher für DOOR_1 - PAGEX3: Pufferspeicher für Animationen +#define REDRAWTILES_THRESHOLD SCR_FIELDX*SCR_FIELDY/2 + +/* areas in pixmap PIX_DOOR */ +/* meaning in PIX_DB_DOOR: (3 PAGEs) + PAGEX1: 1. buffer for DOOR_1 + PAGEX2: 2. buffer for DOOR_1 + PAGEX3: buffer for animations */ #define DOOR_GFX_PAGESIZE DXSIZE -#define DOOR_GFX_PAGEX1 (0*DOOR_GFX_PAGESIZE) -#define DOOR_GFX_PAGEX2 (1*DOOR_GFX_PAGESIZE) -#define DOOR_GFX_PAGEX3 (2*DOOR_GFX_PAGESIZE) -#define DOOR_GFX_PAGEX4 (3*DOOR_GFX_PAGESIZE) -#define DOOR_GFX_PAGEX5 (4*DOOR_GFX_PAGESIZE) -#define DOOR_GFX_PAGEX6 (5*DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX1 (0 * DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX2 (1 * DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX3 (2 * DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX4 (3 * DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX5 (4 * DOOR_GFX_PAGESIZE) +#define DOOR_GFX_PAGEX6 (5 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEY1 0 #define DOOR_GFX_PAGEY2 DYSIZE -#endif +/* for DrawGraphicAnimation() [tools.c] and AnimateToon() [cartoons.c] */ +#define ANIM_NORMAL 0 +#define ANIM_OSCILLATE 1 +#define ANIM_REVERSE 2 + +#endif /* MAIN_H */ diff --git a/src/misc.c b/src/misc.c index a17b1da5..39d1fdc4 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,441 +1,900 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * misc.c * ***********************************************************/ -#include "misc.h" -#include "tools.h" -#include "sound.h" #include #include #include #include #include #include +#include +#include -void microsleep(unsigned long usec) -{ - struct timeval delay; +#include "misc.h" +#include "init.h" +#include "tools.h" +#include "sound.h" +#include "random.h" +#include "joystick.h" +#include "files.h" - delay.tv_sec = usec / 1000000; - delay.tv_usec = usec % 1000000; +#ifdef MSDOS +volatile unsigned long counter = 0; - if (select(0,NULL,NULL,NULL,&delay)!=0) - fprintf(stderr,"%s: in function microsleep: select failed!\n", - progname); +void increment_counter() +{ + counter++; } -long mainCounter(int mode) +END_OF_FUNCTION(increment_counter); +#endif + + + +/* maximal allowed length of a command line option */ +#define MAX_OPTION_LEN 256 + +#ifndef MSDOS +static unsigned long mainCounter(int mode) { static struct timeval base_time = { 0, 0 }; struct timeval current_time; - long counter_ms; + unsigned long counter_ms; - gettimeofday(¤t_time,NULL); - if (mode==0 || current_time.tv_sec= base_counter) + actual_counter = Counter(); + } + else + { + struct timeval delay; + + delay.tv_sec = milliseconds_delay / 1000; + delay.tv_usec = 1000 * (milliseconds_delay % 1000); + + if (select(0, NULL, NULL, NULL, &delay) != 0) + Error(ERR_WARN, "sleep_milliseconds(): select() failed"); + } } -long Counter2() /* returns 1/1000 secs since last call of InitCounter() */ +void Delay(unsigned long delay) /* Sleep specified number of milliseconds */ { - return(mainCounter(2)); + sleep_milliseconds(delay); } -void WaitCounter(long value) /* wait for counter to reach value */ +boolean FrameReached(unsigned long *frame_counter_var, + unsigned long frame_delay) { - long wait; + unsigned long actual_frame_counter = FrameCounter; + + if (actual_frame_counter < *frame_counter_var+frame_delay && + actual_frame_counter >= *frame_counter_var) + return(FALSE); - while((wait=value-Counter())>0) - microsleep(wait*10000); + *frame_counter_var = actual_frame_counter; + return(TRUE); } -void WaitCounter2(long value) /* wait for counter to reach value */ +boolean DelayReached(unsigned long *counter_var, + unsigned long delay) { - long wait; + unsigned long actual_counter = Counter(); - while((wait=value-Counter2())>0) - microsleep(wait*1000); + if (actual_counter < *counter_var + delay && + actual_counter >= *counter_var) + return(FALSE); + + *counter_var = actual_counter; + return(TRUE); } -void Delay(long value) +void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) { - microsleep(value); + unsigned long actual_counter; + + while(1) + { + actual_counter = Counter(); + + if (actual_counter < *counter_var + delay && + actual_counter >= *counter_var) + sleep_milliseconds((*counter_var + delay - actual_counter) / 2); + else + break; + } + + *counter_var = actual_counter; } -BOOL DelayReached(long *counter_var, int delay) +char *int2str(int number, int size) { - long actual_counter = Counter(); + static char s[40]; - if (actual_counter>*counter_var+delay || actual_counter<*counter_var) + if (size > 20) + size = 20; + + if (size) { - *counter_var = actual_counter; - return(TRUE); + sprintf(s, " %09d", number); + return &s[strlen(s) - size]; } else - return(FALSE); + { + sprintf(s, "%d", number); + return s; + } } -unsigned long be2long(unsigned long *be) /* big-endian -> longword */ +unsigned int SimpleRND(unsigned int max) { - unsigned char *ptr = (unsigned char *)be; + static unsigned long root = 654321; + struct timeval current_time; - return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]); + gettimeofday(¤t_time,NULL); + root = root * 4253261 + current_time.tv_sec + current_time.tv_usec; + return (root % max); } -char *int2str(int ct, int nr) -{ - static char str[20]; +#ifdef DEBUG +static unsigned int last_RND_value = 0; - sprintf(str,"%09d",ct); - return(&str[strlen(str)-nr]); +unsigned int last_RND() +{ + return last_RND_value; } +#endif unsigned int RND(unsigned int max) { - return(rand() % max); +#ifdef DEBUG + return (last_RND_value = random_linux_libc() % max); +#else + return (random_linux_libc() % max); +#endif } unsigned int InitRND(long seed) { struct timeval current_time; - if (seed==NEW_RANDOMIZE) + if (seed == NEW_RANDOMIZE) { gettimeofday(¤t_time,NULL); - srand((unsigned int) current_time.tv_usec); - return((unsigned int) current_time.tv_usec); + srandom_linux_libc((unsigned int) current_time.tv_usec); + return (unsigned int)current_time.tv_usec; } else { - srand((unsigned int) seed); - return((unsigned int) seed); + srandom_linux_libc((unsigned int) seed); + return (unsigned int)seed; } } -char *GetLoginName() +char *getLoginName() { struct passwd *pwd; - if (!(pwd=getpwuid(getuid()))) - return("ANONYMOUS"); + if (!(pwd = getpwuid(getuid()))) + return "ANONYMOUS"; else - return(pwd->pw_name); + return pwd->pw_name; +} + +char *getHomeDir() +{ +#ifndef MSDOS + static char *home_dir = NULL; + + if (!home_dir) + { + if (!(home_dir = getenv("HOME"))) + { + struct passwd *pwd; + + if ((pwd = getpwuid(getuid()))) + home_dir = pwd->pw_dir; + else + home_dir = "."; + } + } + + return home_dir; +#else + return "."; +#endif } -void InitAnimation() +char *getPath2(char *path1, char *path2) { - HandleAnimation(ANIM_START); + char *complete_path = checked_malloc(strlen(path1) + 1 + + strlen(path2) + 1); + + sprintf(complete_path, "%s/%s", path1, path2); + return complete_path; } -void StopAnimation() +char *getPath3(char *path1, char *path2, char *path3) { - HandleAnimation(ANIM_STOP); + char *complete_path = checked_malloc(strlen(path1) + 1 + + strlen(path2) + 1 + + strlen(path3) + 1); + + sprintf(complete_path, "%s/%s/%s", path1, path2, path3); + return complete_path; } -void DoAnimation() +char *getStringCopy(char *s) { - HandleAnimation(ANIM_CONTINUE); + char *s_copy = checked_malloc(strlen(s) + 1); + + strcpy(s_copy, s); + return s_copy; } -void HandleAnimation(int mode) +char *getStringToLower(char *s) { - static long animstart_delay = -1; - static long animstart_delay_value = 0; - static BOOL anim_restart = TRUE; - static BOOL reset_delay = TRUE; - static int toon_nr = 0; + char *s_copy = checked_malloc(strlen(s) + 1); + char *s_ptr = s_copy; - if (!toons_on || game_status==PLAYING) - return; + while (*s) + *s_ptr++ = tolower(*s++); - switch(mode) + return s_copy; +} + +void MarkTileDirty(int x, int y) +{ + int xx = redraw_x1 + x; + int yy = redraw_y1 + y; + + if (!redraw[xx][yy]) + redraw_tiles++; + + redraw[xx][yy] = TRUE; + redraw_mask |= REDRAW_TILES; +} + +void GetOptions(char *argv[]) +{ + char **options_left = &argv[1]; + + /* initialize global program options */ + options.display_name = NULL; + options.server_host = NULL; + options.server_port = 0; + options.base_directory = BASE_PATH; + options.level_directory = BASE_PATH "/" LEVELS_DIRECTORY; + options.serveronly = FALSE; + options.network = FALSE; + options.verbose = FALSE; + + while (*options_left) { - case ANIM_START: - anim_restart = TRUE; - reset_delay = TRUE; - return; - break; - case ANIM_CONTINUE: - break; - case ANIM_STOP: - redraw_mask |= REDRAW_FIELD; - BackToFront(); - return; - break; - default: + char option_str[MAX_OPTION_LEN]; + char *option = options_left[0]; + char *next_option = options_left[1]; + char *option_arg = NULL; + int option_len = strlen(option); + + if (option_len >= MAX_OPTION_LEN) + Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); + + strcpy(option_str, option); /* copy argument into buffer */ + option = option_str; + + if (strcmp(option, "--") == 0) /* stop scanning arguments */ break; + + if (strncmp(option, "--", 2) == 0) /* treat '--' like '-' */ + option++; + + option_arg = strchr(option, '='); + if (option_arg == NULL) /* no '=' in option */ + option_arg = next_option; + else + { + *option_arg++ = '\0'; /* cut argument from option */ + if (*option_arg == '\0') /* no argument after '=' */ + Error(ERR_EXIT_HELP, "option '%s' has invalid argument", option_str); + } + + option_len = strlen(option); + + if (strcmp(option, "-") == 0) + Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); + else if (strncmp(option, "-help", option_len) == 0) + { + printf("Usage: %s [options] [server.name [port]]\n" + "Options:\n" + " -d, --display machine:0 X server display\n" + " -b, --basepath directory alternative base directory\n" + " -l, --levels directory alternative level directory\n" + " -s, --serveronly only start network server\n" + " -n, --network network multiplayer game\n" + " -v, --verbose verbose mode\n", + program_name); + exit(0); + } + else if (strncmp(option, "-display", option_len) == 0) + { + if (option_arg == NULL) + Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); + + options.display_name = option_arg; + if (option_arg == next_option) + options_left++; + } + else if (strncmp(option, "-basepath", option_len) == 0) + { + if (option_arg == NULL) + Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); + + options.base_directory = option_arg; + if (option_arg == next_option) + options_left++; + + /* adjust path for level directory accordingly */ + options.level_directory = + getPath2(options.base_directory, LEVELS_DIRECTORY); + } + else if (strncmp(option, "-levels", option_len) == 0) + { + if (option_arg == NULL) + Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); + + options.level_directory = option_arg; + if (option_arg == next_option) + options_left++; + } + else if (strncmp(option, "-network", option_len) == 0) + { + options.network = TRUE; + } + else if (strncmp(option, "-serveronly", option_len) == 0) + { + options.serveronly = TRUE; + } + else if (strncmp(option, "-verbose", option_len) == 0) + { + options.verbose = TRUE; + } + else if (*option == '-') + { + Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str); + } + else if (options.server_host == NULL) + { + options.server_host = *options_left; + } + else if (options.server_port == 0) + { + options.server_port = atoi(*options_left); + if (options.server_port < 1024) + Error(ERR_EXIT_HELP, "bad port number '%d'", options.server_port); + } + else + Error(ERR_EXIT_HELP, "too many arguments"); + + options_left++; } +} + +void Error(int mode, char *format, ...) +{ + char *process_name = ""; + FILE *error = stderr; + + /* display warnings only when running in verbose mode */ + if (mode & ERR_WARN && !options.verbose) + return; - if (reset_delay) +#ifdef MSDOS + if ((error = openErrorFile()) == NULL) { - animstart_delay = Counter(); - animstart_delay_value = RND(500); - reset_delay = FALSE; + printf("Cannot write to error output file!\n"); + CloseAllAndExit(1); } +#endif - if (anim_restart) + if (mode & ERR_SOUND_SERVER) + process_name = " sound server"; + else if (mode & ERR_NETWORK_SERVER) + process_name = " network server"; + else if (mode & ERR_NETWORK_CLIENT) + process_name = " network client **"; + + if (format) { - if (!DelayReached(&animstart_delay,animstart_delay_value)) - return; + va_list ap; + + fprintf(error, "%s%s: ", program_name, process_name); + + if (mode & ERR_WARN) + fprintf(error, "warning: "); + + va_start(ap, format); + vfprintf(error, format, ap); + va_end(ap); + + fprintf(error, "\n"); + } + + if (mode & ERR_HELP) + fprintf(error, "%s: Try option '--help' for more information.\n", + program_name); + + if (mode & ERR_EXIT) + fprintf(error, "%s%s: aborting\n", program_name, process_name); + + if (error != stderr) + fclose(error); - toon_nr = RND(NUM_TOONS); + if (mode & ERR_EXIT) + { + if (mode & ERR_FROM_SERVER) + exit(1); /* child process: normal exit */ + else + CloseAllAndExit(1); /* main process: clean up stuff */ } +} + +void *checked_malloc(unsigned long size) +{ + void *ptr; + + ptr = malloc(size); - anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart); + if (ptr == NULL) + Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); + + return ptr; } -BOOL AnimateToon(int toon_nr, BOOL restart) +void *checked_calloc(unsigned long size) { - static pos_x = 0, pos_y = 0; - static delta_x = 0, delta_y = 0; - static int frame = 0, frame_step = 1; - static BOOL horiz_move, vert_move; - static long anim_delay = 0; - static int anim_delay_value = 0; - static int width,height; - static int pad_x,pad_y; - static int cut_x,cut_y; - static int src_x, src_y; - static int dest_x, dest_y; - static struct AnimInfo toon[NUM_TOONS] = + void *ptr; + + ptr = calloc(1, size); + + if (ptr == NULL) + Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); + + return ptr; +} + +#define TRANSLATE_KEYSYM_TO_KEYNAME 0 +#define TRANSLATE_KEYSYM_TO_X11KEYNAME 1 +#define TRANSLATE_X11KEYNAME_TO_KEYSYM 2 + +void translate_keyname(KeySym *keysym, char **x11name, char **name, int mode) +{ + static struct + { + KeySym keysym; + char *x11name; + char *name; + } translate_key[] = { - DWARF_XSIZE, DWARF_YSIZE, - DWARF_X, DWARF_Y, - DWARF_FRAMES, - DWARF_FPS, - DWARF_STEPSIZE, - FALSE, - ANIMDIR_RIGHT, - ANIMPOS_DOWN, - - DWARF_XSIZE, DWARF_YSIZE, - DWARF_X, DWARF2_Y, - DWARF_FRAMES, - DWARF_FPS, - DWARF_STEPSIZE, - FALSE, - ANIMDIR_LEFT, - ANIMPOS_DOWN, - - JUMPER_XSIZE, JUMPER_YSIZE, - JUMPER_X, JUMPER_Y, - JUMPER_FRAMES, - JUMPER_FPS, - JUMPER_STEPSIZE, - FALSE, - ANIMDIR_LEFT, - ANIMPOS_DOWN, - - CLOWN_XSIZE, CLOWN_YSIZE, - CLOWN_X, CLOWN_Y, - CLOWN_FRAMES, - CLOWN_FPS, - CLOWN_STEPSIZE, - FALSE, - ANIMDIR_UP, - ANIMPOS_ANY, - - BIRD_XSIZE, BIRD_YSIZE, - BIRD1_X, BIRD1_Y, - BIRD_FRAMES, - BIRD_FPS, - BIRD_STEPSIZE, - TRUE, - ANIMDIR_RIGHT, - ANIMPOS_UPPER, - - BIRD_XSIZE, BIRD_YSIZE, - BIRD2_X, BIRD2_Y, - BIRD_FRAMES, - BIRD_FPS, - BIRD_STEPSIZE, - TRUE, - ANIMDIR_LEFT, - ANIMPOS_UPPER + /* normal cursor keys */ + { XK_Left, "XK_Left", "cursor left" }, + { XK_Right, "XK_Right", "cursor right" }, + { XK_Up, "XK_Up", "cursor up" }, + { XK_Down, "XK_Down", "cursor down" }, + + /* keypad cursor keys */ +#ifdef XK_KP_Left + { XK_KP_Left, "XK_KP_Left", "keypad left" }, + { XK_KP_Right, "XK_KP_Right", "keypad right" }, + { XK_KP_Up, "XK_KP_Up", "keypad up" }, + { XK_KP_Down, "XK_KP_Down", "keypad down" }, +#endif + + /* other keypad keys */ +#ifdef XK_KP_Enter + { XK_KP_Enter, "XK_KP_Enter", "keypad enter" }, + { XK_KP_Add, "XK_KP_Add", "keypad +" }, + { XK_KP_Subtract, "XK_KP_Subtract", "keypad -" }, + { XK_KP_Multiply, "XK_KP_Multiply", "keypad mltply" }, + { XK_KP_Divide, "XK_KP_Divide", "keypad /" }, + { XK_KP_Separator, "XK_KP_Separator", "keypad ," }, +#endif + + /* modifier keys */ + { XK_Shift_L, "XK_Shift_L", "left shift" }, + { XK_Shift_R, "XK_Shift_R", "right shift" }, + { XK_Control_L, "XK_Control_L", "left control" }, + { XK_Control_R, "XK_Control_R", "right control" }, + { XK_Meta_L, "XK_Meta_L", "left meta" }, + { XK_Meta_R, "XK_Meta_R", "right meta" }, + { XK_Alt_L, "XK_Alt_L", "left alt" }, + { XK_Alt_R, "XK_Alt_R", "right alt" }, + { XK_Mode_switch, "XK_Mode_switch", "mode switch" }, + { XK_Multi_key, "XK_Multi_key", "multi key" }, + + /* some special keys */ + { XK_BackSpace, "XK_BackSpace", "backspace" }, + { XK_Delete, "XK_Delete", "delete" }, + { XK_Insert, "XK_Insert", "insert" }, + { XK_Tab, "XK_Tab", "tab" }, + { XK_Home, "XK_Home", "home" }, + { XK_End, "XK_End", "end" }, + { XK_Page_Up, "XK_Page_Up", "page up" }, + { XK_Page_Down, "XK_Page_Down", "page down" }, + { XK_space, "XK_space", "space" }, + + /* even more special keys */ + { XK_adiaeresis, "XK_adiaeresis", "ä" }, + { XK_odiaeresis, "XK_odiaeresis", "ö" }, + { XK_udiaeresis, "XK_udiaeresis", "ü" }, + { XK_apostrophe, "XK_apostrophe", "'" }, + { XK_plus, "XK_plus", "+" }, + { XK_minus, "XK_minus", "-" }, + { XK_equal, "XK_equal", "equal" }, + { XK_comma, "XK_comma", "," }, + { XK_period, "XK_period", "." }, + { XK_colon, "XK_colon", ";" }, + { XK_slash, "XK_slash", "/" }, + { XK_numbersign, "XK_numbersign", "#" }, + { XK_backslash, "XK_backslash", "backslash" }, + { XK_braceleft, "XK_braceleft", "brace left" }, + { XK_braceright, "XK_braceright", "brace right" }, + { XK_less, "XK_less", "less" }, + { XK_greater, "XK_greater", "greater" }, + { XK_asciicircum, "XK_asciicircum", "circumflex" }, + { XK_ssharp, "XK_ssharp", "sharp s" }, + + /* end-of-array identifier */ + { 0, NULL, NULL } }; - struct AnimInfo *anim = &toon[toon_nr]; - if (restart) - { - horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT)); - vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN)); - anim_delay_value = 100/anim->frames_per_second; - frame = 0; + int i; - if (horiz_move) + if (mode == TRANSLATE_KEYSYM_TO_KEYNAME) + { + static char name_buffer[30]; + KeySym key = *keysym; + + if (key >= XK_A && key <= XK_Z) + sprintf(name_buffer, "%c", 'A' + (char)(key - XK_A)); + else if (key >= XK_a && key <= XK_z) + sprintf(name_buffer, "%c", 'a' + (char)(key - XK_a)); + else if (key >= XK_0 && key <= XK_9) + sprintf(name_buffer, "%c", '0' + (char)(key - XK_0)); + else if (key >= XK_KP_0 && key <= XK_KP_9) + sprintf(name_buffer, "keypad %c", '0' + (char)(key - XK_KP_0)); + else if (key >= XK_F1 && key <= XK_F24) + sprintf(name_buffer, "function F%d", (int)(key - XK_F1 + 1)); + else if (key == KEY_UNDEFINDED) + strcpy(name_buffer, "(undefined)"); + else { - if (anim->position==ANIMPOS_UP) - pos_y = 0; - else if (anim->position==ANIMPOS_DOWN) - pos_y = FULL_SYSIZE-anim->height; - else if (anim->position==ANIMPOS_UPPER) - pos_y = RND((FULL_SYSIZE-anim->height)/2); - else - pos_y = RND(FULL_SYSIZE-anim->height); + i = 0; - if (anim->direction==ANIMDIR_RIGHT) + do { - delta_x = anim->stepsize; - pos_x = -anim->width+delta_x; + if (key == translate_key[i].keysym) + { + strcpy(name_buffer, translate_key[i].name); + break; + } } - else + while (translate_key[++i].name); + + if (!translate_key[i].name) + strcpy(name_buffer, "(unknown)"); + } + + *name = name_buffer; + } + else if (mode == TRANSLATE_KEYSYM_TO_X11KEYNAME) + { + static char name_buffer[30]; + KeySym key = *keysym; + + if (key >= XK_A && key <= XK_Z) + sprintf(name_buffer, "XK_%c", 'A' + (char)(key - XK_A)); + else if (key >= XK_a && key <= XK_z) + sprintf(name_buffer, "XK_%c", 'a' + (char)(key - XK_a)); + else if (key >= XK_0 && key <= XK_9) + sprintf(name_buffer, "XK_%c", '0' + (char)(key - XK_0)); + else if (key >= XK_KP_0 && key <= XK_KP_9) + sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - XK_KP_0)); + else if (key >= XK_F1 && key <= XK_F24) + sprintf(name_buffer, "XK_F%d", (int)(key - XK_F1 + 1)); + else if (key == KEY_UNDEFINDED) + strcpy(name_buffer, "[undefined]"); + else + { + i = 0; + + do { - delta_x = -anim->stepsize; - pos_x = FULL_SXSIZE+delta_x; + if (key == translate_key[i].keysym) + { + strcpy(name_buffer, translate_key[i].x11name); + break; + } } - delta_y = 0; + while (translate_key[++i].x11name); + + if (!translate_key[i].x11name) + sprintf(name_buffer, "0x%04lx", (unsigned long)key); } - else + + *x11name = name_buffer; + } + else if (mode == TRANSLATE_X11KEYNAME_TO_KEYSYM) + { + KeySym key = XK_VoidSymbol; + char *name_ptr = *x11name; + + if (strncmp(name_ptr, "XK_", 3) == 0 && strlen(name_ptr) == 4) { - if (anim->position==ANIMPOS_LEFT) - pos_x = 0; - else if (anim->position==ANIMPOS_RIGHT) - pos_x = FULL_SXSIZE-anim->width; - else - pos_x = RND(FULL_SXSIZE-anim->width); + char c = name_ptr[3]; + + if (c >= 'A' && c <= 'Z') + key = XK_A + (KeySym)(c - 'A'); + else if (c >= 'a' && c <= 'z') + key = XK_a + (KeySym)(c - 'a'); + else if (c >= '0' && c <= '9') + key = XK_0 + (KeySym)(c - '0'); + } + else if (strncmp(name_ptr, "XK_KP_", 6) == 0 && strlen(name_ptr) == 7) + { + char c = name_ptr[6]; + + if (c >= '0' && c <= '9') + key = XK_0 + (KeySym)(c - '0'); + } + else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6) + { + char c1 = name_ptr[4]; + char c2 = name_ptr[5]; + int d = 0; + + if ((c1 >= '0' && c1 <= '9') && + ((c2 >= '0' && c1 <= '9') || c2 == '\0')) + d = atoi(&name_ptr[4]); - if (anim->direction==ANIMDIR_DOWN) + if (d >=1 && d <= 24) + key = XK_F1 + (KeySym)(d - 1); + } + else if (strncmp(name_ptr, "XK_", 3) == 0) + { + i = 0; + + do { - delta_y = anim->stepsize; - pos_y = -anim->height+delta_y; + if (strcmp(name_ptr, translate_key[i].x11name) == 0) + { + key = translate_key[i].keysym; + break; + } } - else + while (translate_key[++i].x11name); + } + else if (strncmp(name_ptr, "0x", 2) == 0) + { + unsigned long value = 0; + + name_ptr += 2; + + while (name_ptr) { - delta_y = -anim->stepsize; - pos_y = FULL_SYSIZE+delta_y; + char c = *name_ptr++; + int d = -1; + + if (c >= '0' && c <= '9') + d = (int)(c - '0'); + else if (c >= 'a' && c <= 'f') + d = (int)(c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + d = (int)(c - 'A' + 10); + + if (d == -1) + { + value = -1; + break; + } + + value = value * 16 + d; } - delta_x = 0; + + if (value != -1) + key = (KeySym)value; } + + *keysym = key; } +} - if (pos_x <= -anim->width - anim->stepsize || - pos_x >= FULL_SXSIZE + anim->stepsize || - pos_y <= -anim->height - anim->stepsize || - pos_y >= FULL_SYSIZE + anim->stepsize) - return(TRUE); +char *getKeyNameFromKeySym(KeySym keysym) +{ + char *name; - if (!DelayReached(&anim_delay,anim_delay_value)) - { - if (game_status==HELPSCREEN && !restart) - DrawAnim(src_x+cut_x,src_y+cut_y, width,height, - REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y); + translate_keyname(&keysym, NULL, &name, TRANSLATE_KEYSYM_TO_KEYNAME); + return name; +} - return(FALSE); - } +char *getX11KeyNameFromKeySym(KeySym keysym) +{ + char *x11name; - if (pos_x<-anim->width) - pos_x = -anim->width; - else if (pos_x>FULL_SXSIZE) - pos_x = FULL_SXSIZE; - if (pos_y<-anim->height) - pos_y = -anim->height; - else if (pos_y>FULL_SYSIZE) - pos_y = FULL_SYSIZE; - - pad_x = (horiz_move ? anim->stepsize : 0); - pad_y = (vert_move ? anim->stepsize : 0); - src_x = anim->src_x + frame * anim->width; - src_y = anim->src_y; - dest_x = pos_x; - dest_y = pos_y; - cut_x = cut_y = 0; - width = anim->width; - height = anim->height; - - if (pos_x<0) - { - dest_x = 0; - width += pos_x; - cut_x = -pos_x; - } - else if (pos_x>FULL_SXSIZE-anim->width) - width -= (pos_x - (FULL_SXSIZE-anim->width)); + translate_keyname(&keysym, &x11name, NULL, TRANSLATE_KEYSYM_TO_X11KEYNAME); + return x11name; +} + +KeySym getKeySymFromX11KeyName(char *x11name) +{ + KeySym keysym; - if (pos_y<0) + translate_keyname(&keysym, &x11name, NULL, TRANSLATE_X11KEYNAME_TO_KEYSYM); + return keysym; +} + +#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0 +#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1 + +void translate_joyname(int *joysymbol, char **name, int mode) +{ + static struct { - dest_y = 0; - height += pos_y; - cut_y = -pos_y; - } - else if (pos_y>FULL_SYSIZE-anim->height) - height -= (pos_y - (FULL_SYSIZE-anim->height)); + int joysymbol; + char *name; + } translate_joy[] = + { + { JOY_LEFT, "joystick_left" }, + { JOY_RIGHT, "joystick_right" }, + { JOY_UP, "joystick_up" }, + { JOY_DOWN, "joystick_down" }, + { JOY_BUTTON_1, "joystick_button_1" }, + { JOY_BUTTON_2, "joystick_button_2" }, + }; - DrawAnim(src_x+cut_x,src_y+cut_y, width,height, - REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y); + int i; - pos_x += delta_x; - pos_y += delta_y; - frame += frame_step; + if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME) + { + *name = "[undefined]"; - if (frame<0 || frame>=anim->frames) + for (i=0; i<6; i++) + { + if (*joysymbol == translate_joy[i].joysymbol) + { + *name = translate_joy[i].name; + break; + } + } + } + else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL) { - if (anim->pingpong) + *joysymbol = 0; + + for (i=0; i<6; i++) { - frame_step *= -1; - frame = (frame<0 ? 1 : anim->frames-2); + if (strcmp(*name, translate_joy[i].name) == 0) + { + *joysymbol = translate_joy[i].joysymbol; + break; + } } - else - frame = (frame<0 ? anim->frames-1 : 0); } +} + +char *getJoyNameFromJoySymbol(int joysymbol) +{ + char *name; - return(FALSE); + translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME); + return name; } -void DrawAnim(int src_x, int src_y, int width, int height, - int dest_x, int dest_y, int pad_x, int pad_y) +int getJoySymbolFromJoyName(char *name) { - int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1; + int joysymbol; -#if 1 - /* special method to avoid flickering interference with BackToFront() */ - XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y, - width+2*pad_x,height+2*pad_y, buf_x,buf_y); - XSetClipOrigin(display,clip_gc[PIX_TOONS],dest_x-src_x,dest_y-src_y); - XCopyArea(display,pix[PIX_TOONS],backbuffer,clip_gc[PIX_TOONS], - src_x,src_y, width,height, dest_x,dest_y); - XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y, - width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); - BackToFront(); - XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y, - width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); -#else - /* normal method, causing flickering interference with BackToFront() */ - XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y, - width+2*pad_x,height+2*pad_y, buf_x,buf_y); - XSetClipOrigin(display,clip_gc[PIX_TOONS], - buf_x-src_x+pad_x,buf_y-src_y+pad_y); - XCopyArea(display,pix[PIX_TOONS],pix[PIX_DB_DOOR],clip_gc[PIX_TOONS], - src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y); - XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y, - width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y); -#endif + translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL); + return joysymbol; +} + +int getJoystickNrFromDeviceName(char *device_name) +{ + char c; + int joystick_nr = 0; + + if (device_name == NULL || device_name[0] == '\0') + return 0; + + c = device_name[strlen(device_name) - 1]; + + if (c >= '0' && c <= '9') + joystick_nr = (int)(c - '0'); + + if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS) + joystick_nr = 0; + + return joystick_nr; +} + +/* ----------------------------------------------------------------- */ +/* the following is only for debugging purpose and normally not used */ +/* ----------------------------------------------------------------- */ + +#define DEBUG_NUM_TIMESTAMPS 3 + +void debug_print_timestamp(int counter_nr, char *message) +{ + static long counter[DEBUG_NUM_TIMESTAMPS][2]; + + if (counter_nr >= DEBUG_NUM_TIMESTAMPS) + Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c"); + + counter[counter_nr][0] = Counter(); + + if (message) + printf("%s %.2f seconds\n", message, + (float)(counter[counter_nr][0] - counter[counter_nr][1]) / 1000); - XFlush(display); + counter[counter_nr][1] = Counter(); } diff --git a/src/misc.h b/src/misc.h index dba38015..ae8ae79e 100644 --- a/src/misc.h +++ b/src/misc.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * misc.h * ***********************************************************/ @@ -17,91 +16,53 @@ #include "main.h" -/* values for cartoon figures */ -#define NUM_TOONS 6 +#define INIT_COUNTER 0 +#define READ_COUNTER 1 -#define DWARF_XSIZE 40 -#define DWARF_YSIZE 48 -#define DWARF_X 2 -#define DWARF_Y 72 -#define DWARF2_Y 186 -#define DWARF_FRAMES 8 -#define DWARF_FPS 10 -#define DWARF_STEPSIZE 4 -#define JUMPER_XSIZE 48 -#define JUMPER_YSIZE 56 -#define JUMPER_X 2 -#define JUMPER_Y 125 -#define JUMPER_FRAMES 8 -#define JUMPER_FPS 10 -#define JUMPER_STEPSIZE 4 -#define CLOWN_XSIZE 80 -#define CLOWN_YSIZE 110 -#define CLOWN_X 327 -#define CLOWN_Y 10 -#define CLOWN_FRAMES 1 -#define CLOWN_FPS 10 -#define CLOWN_STEPSIZE 4 -#define BIRD_XSIZE 32 -#define BIRD_YSIZE 30 -#define BIRD1_X 2 -#define BIRD1_Y 2 -#define BIRD2_X 2 -#define BIRD2_Y 37 -#define BIRD_FRAMES 8 -#define BIRD_FPS 20 -#define BIRD_STEPSIZE 4 +#define NEW_RANDOMIZE -1 -#define ANIMDIR_LEFT 1 -#define ANIMDIR_RIGHT 2 -#define ANIMDIR_UP 4 -#define ANIMDIR_DOWN 8 +#define ERR_RETURN 0 +#define ERR_WARN (1 << 0) +#define ERR_EXIT (1 << 1) +#define ERR_HELP (1 << 2) +#define ERR_SOUND_SERVER (1 << 3) +#define ERR_NETWORK_SERVER (1 << 4) +#define ERR_NETWORK_CLIENT (1 << 5) +#define ERR_FROM_SERVER (ERR_SOUND_SERVER | ERR_NETWORK_SERVER) +#define ERR_EXIT_HELP (ERR_EXIT | ERR_HELP) +#define ERR_EXIT_SOUND_SERVER (ERR_EXIT | ERR_SOUND_SERVER) +#define ERR_EXIT_NETWORK_SERVER (ERR_EXIT | ERR_NETWORK_SERVER) +#define ERR_EXIT_NETWORK_CLIENT (ERR_EXIT | ERR_NETWORK_CLIENT) -#define ANIMPOS_ANY 0 -#define ANIMPOS_LEFT 1 -#define ANIMPOS_RIGHT 2 -#define ANIMPOS_UP 4 -#define ANIMPOS_DOWN 8 -#define ANIMPOS_UPPER 16 - -#define ANIM_START 0 -#define ANIM_CONTINUE 1 -#define ANIM_STOP 2 - -struct AnimInfo -{ - int width, height; - int src_x, src_y; - int frames; - int frames_per_second; - int stepsize; - BOOL pingpong; - int direction; - int position; -}; - -#define NEW_RANDOMIZE -1 - -void microsleep(unsigned long); -long mainCounter(int); void InitCounter(void); -long Counter(void); -long Counter2(void); -void WaitCounter(long); -void WaitCounter2(long); -void Delay(long); -BOOL DelayReached(long *, int); -unsigned long be2long(unsigned long *); +unsigned long Counter(void); +void Delay(unsigned long); +boolean FrameReached(unsigned long *, unsigned long); +boolean DelayReached(unsigned long *, unsigned long); +void WaitUntilDelayReached(unsigned long *, unsigned long); char *int2str(int, int); +unsigned int SimpleRND(unsigned int); unsigned int RND(unsigned int); unsigned int InitRND(long); -char *GetLoginName(void); +char *getLoginName(void); +char *getHomeDir(void); +char *getPath2(char *, char *); +char *getPath3(char *, char *, char*); +char *getStringCopy(char *); +char *getStringToLower(char *); +void MarkTileDirty(int, int); +void GetOptions(char **); +void Error(int, char *, ...); +void *checked_malloc(unsigned long); +void *checked_calloc(unsigned long); +char *getKeyNameFromKeySym(KeySym); +char *getX11KeyNameFromKeySym(KeySym); +KeySym getKeySymFromX11KeyName(char *); +char *getJoyNameFromJoySymbol(int); +int getJoySymbolFromJoyName(char *); +int getJoystickNrFromDeviceName(char *); -void InitAnimation(void); -void StopAnimation(void); -void DoAnimation(void); -void HandleAnimation(int); -BOOL AnimateToon(int, BOOL); -void DrawAnim(int, int, int, int, int, int, int, int); +void debug_print_timestamp(int, char *); +void print_debug(char *); -#endif +#endif /* MISC_H */ diff --git a/src/msdos.c b/src/msdos.c new file mode 100644 index 00000000..efcd8020 --- /dev/null +++ b/src/msdos.c @@ -0,0 +1,776 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* ©1995 Artsoft Development * +* Holger Schemel * +* 33659 Bielefeld-Senne * +* Telefon: (0521) 493245 * +* eMail: aeglos@valinor.owl.de * +* aeglos@uni-paderborn.de * +* q99492@pbhrzx.uni-paderborn.de * +*----------------------------------------------------------* +* msdos.c * +***********************************************************/ + +#ifdef MSDOS + +#include "main.h" +#include "misc.h" +#include "tools.h" +#include "sound.h" +#include "files.h" +#include "joystick.h" +#include "image.h" +#include "pcx.h" + +/* allegro driver declarations */ +DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1) +DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8) +DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB) +DECLARE_MIDI_DRIVER_LIST() +DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD) + +/* allegro global variables */ +extern volatile int key_shifts; +extern int num_joysticks; +extern JOYSTICK_INFO joy[]; +extern int i_love_bill; + +/* internal variables of msdos.c */ +static int key_press_state[MAX_SCANCODES]; +static XEvent event_buffer[MAX_EVENT_BUFFER]; +static int pending_events; +static boolean joystick_event; +static boolean mouse_installed = FALSE; +static int last_mouse_pos; +static int last_mouse_b; +static int last_joystick_state; +static BITMAP* video_bitmap; + +static RGB global_colormap[MAX_COLORS]; +static int global_colormap_entries_used = 0; + +boolean wait_for_vsync; + +/* +extern int playing_sounds; +extern struct SoundControl playlist[MAX_SOUNDS_PLAYING]; +extern struct SoundControl emptySoundControl; +*/ + +static BITMAP *Read_PCX_to_AllegroBitmap(char *); + +static void allegro_drivers() +{ + int i; + + for (i=0; i 0) + mouse_installed = TRUE; + + last_joystick_state = 0; + joystick_event = FALSE; + + reserve_voices(MAX_SOUNDS_PLAYING, 0); + if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) == -1) + if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1) + sound_status = SOUND_OFF; +} + +static boolean hide_mouse(Display *display, int x, int y, + unsigned int width, unsigned int height) +{ + if (mouse_x + display->mouse_ptr->w < x || mouse_x > x + width) + return FALSE; + if (mouse_y + display->mouse_ptr->h < y || mouse_y > y + height) + return FALSE; + + show_mouse(NULL); + + return TRUE; +} + +static void unhide_mouse(Display *display) +{ + if (mouse_installed) + show_mouse(video_bitmap); +} + +static KeySym ScancodeToKeySym(byte scancode) +{ + switch(scancode) + { + case KEY_ESC: return XK_Escape; + case KEY_1: return XK_1; + case KEY_2: return XK_2; + case KEY_3: return XK_3; + case KEY_4: return XK_4; + case KEY_5: return XK_5; + case KEY_6: return XK_6; + case KEY_7: return XK_7; + case KEY_8: return XK_8; + case KEY_9: return XK_9; + case KEY_0: return XK_0; + case KEY_MINUS: return XK_minus; + case KEY_EQUALS: return XK_equal; + case KEY_BACKSPACE: return XK_BackSpace; + case KEY_TAB: return XK_Tab; + case KEY_Q: return XK_q; + case KEY_W: return XK_w; + case KEY_E: return XK_e; + case KEY_R: return XK_r; + case KEY_T: return XK_t; + case KEY_Y: return XK_y; + case KEY_U: return XK_u; + case KEY_I: return XK_i; + case KEY_O: return XK_o; + case KEY_P: return XK_p; + case KEY_OPENBRACE: return XK_braceleft; + case KEY_CLOSEBRACE: return XK_braceright; + case KEY_ENTER: return XK_Return; + case KEY_LCONTROL: return XK_Control_L; + case KEY_A: return XK_a; + case KEY_S: return XK_s; + case KEY_D: return XK_d; + case KEY_F: return XK_f; + case KEY_G: return XK_g; + case KEY_H: return XK_h; + case KEY_J: return XK_j; + case KEY_K: return XK_k; + case KEY_L: return XK_l; + case KEY_COLON: return XK_colon; + case KEY_QUOTE: return XK_apostrophe; + case KEY_TILDE: return XK_asciitilde; + case KEY_LSHIFT: return XK_Shift_L; + case KEY_BACKSLASH: return XK_backslash; + case KEY_Z: return XK_z; + case KEY_X: return XK_x; + case KEY_C: return XK_c; + case KEY_V: return XK_v; + case KEY_B: return XK_b; + case KEY_N: return XK_n; + case KEY_M: return XK_m; + case KEY_COMMA: return XK_comma; + case KEY_STOP: return XK_period; + case KEY_SLASH: return XK_slash; + case KEY_RSHIFT: return XK_Shift_R; + case KEY_ASTERISK: return XK_KP_Multiply; + case KEY_ALT: return XK_Alt_L; + case KEY_SPACE: return XK_space; + case KEY_CAPSLOCK: return XK_Caps_Lock; + case KEY_F1: return XK_F1; + case KEY_F2: return XK_F2; + case KEY_F3: return XK_F3; + case KEY_F4: return XK_F4; + case KEY_F5: return XK_F5; + case KEY_F6: return XK_F6; + case KEY_F7: return XK_F7; + case KEY_F8: return XK_F8; + case KEY_F9: return XK_F9; + case KEY_F10: return XK_F10; + case KEY_NUMLOCK: return XK_Num_Lock; + case KEY_SCRLOCK: return XK_Scroll_Lock; + case KEY_HOME: return XK_Home; + case KEY_UP: return XK_Up; + case KEY_PGUP: return XK_Page_Up; + case KEY_MINUS_PAD: return XK_KP_Subtract; + case KEY_LEFT: return XK_Left; + case KEY_5_PAD: return XK_KP_5; + case KEY_RIGHT: return XK_Right; + case KEY_PLUS_PAD: return XK_KP_Add; + case KEY_END: return XK_End; + case KEY_DOWN: return XK_Down; + case KEY_PGDN: return XK_Page_Down; + case KEY_INSERT: return XK_Insert; + case KEY_DEL: return XK_Delete; + case KEY_PRTSCR: return XK_Print; + case KEY_F11: return XK_F11; + case KEY_F12: return XK_F12; + case KEY_LWIN: return XK_Meta_L; + case KEY_RWIN: return XK_Meta_R; + case KEY_MENU: return XK_Menu; + case KEY_PAD: return XK_VoidSymbol; + case KEY_RCONTROL: return XK_Control_R; + case KEY_ALTGR: return XK_Alt_R; + case KEY_SLASH2: return XK_KP_Divide; + case KEY_PAUSE: return XK_Pause; + + case NEW_KEY_BACKSLASH: return XK_backslash; + case NEW_KEY_1_PAD: return XK_KP_1; + case NEW_KEY_2_PAD: return XK_KP_2; + case NEW_KEY_3_PAD: return XK_KP_3; + case NEW_KEY_4_PAD: return XK_KP_4; + case NEW_KEY_5_PAD: return XK_KP_5; + case NEW_KEY_6_PAD: return XK_KP_6; + case NEW_KEY_7_PAD: return XK_KP_7; + case NEW_KEY_8_PAD: return XK_KP_8; + case NEW_KEY_9_PAD: return XK_KP_9; + case NEW_KEY_0_PAD: return XK_KP_0; + case NEW_KEY_STOP_PAD: return XK_KP_Separator; + case NEW_KEY_EQUALS_PAD: return XK_KP_Equal; + case NEW_KEY_SLASH_PAD: return XK_KP_Divide; + case NEW_KEY_ASTERISK_PAD: return XK_KP_Multiply; + case NEW_KEY_ENTER_PAD: return XK_KP_Enter; + + default: return XK_VoidSymbol; + } +} + +void XMapWindow(Display *display, Window window) +{ + int x, y; + unsigned int width, height; + boolean mouse_off; + + x = display->screens[display->default_screen].x; + y = display->screens[display->default_screen].y; + width = display->screens[display->default_screen].width; + height = display->screens[display->default_screen].height; + + mouse_off = hide_mouse(display, x, y, width, height); + blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height); + + if (mouse_off) + unhide_mouse(display); +} + +Display *XOpenDisplay(char *display_name) +{ + Screen *screen; + Display *display; + BITMAP *mouse_bitmap = NULL; + char *filename; + + filename = getPath3(options.base_directory, GRAPHICS_DIRECTORY, + MOUSE_FILENAME); + + mouse_bitmap = Read_PCX_to_AllegroBitmap(filename); + free(filename); + + if (mouse_bitmap == NULL) + return NULL; + + screen = malloc(sizeof(Screen)); + display = malloc(sizeof(Display)); + + screen[0].cmap = 0; + screen[0].root = 0; + screen[0].white_pixel = 0xFF; + screen[0].black_pixel = 0x00; + screen[0].video_bitmap = NULL; + + display->default_screen = 0; + display->screens = screen; + display->mouse_ptr = mouse_bitmap; + + allegro_init(); + allegro_drivers(); + set_color_depth(8); + + /* force Windows 95 to switch to fullscreen mode */ + set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0); + rest(200); + set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0); + + return display; +} + +Window XCreateSimpleWindow(Display *display, Window parent, int x, int y, + unsigned int width, unsigned int height, + unsigned int border_width, unsigned long border, + unsigned long background) +{ + video_bitmap = create_video_bitmap(XRES, YRES); + clear_to_color(video_bitmap, background); + + display->screens[display->default_screen].video_bitmap = video_bitmap; + display->screens[display->default_screen].x = x; + display->screens[display->default_screen].y = y; + display->screens[display->default_screen].width = XRES; + display->screens[display->default_screen].height = YRES; + + set_mouse_sprite(display->mouse_ptr); + set_mouse_speed(1, 1); + set_mouse_range(display->screens[display->default_screen].x + 1, + display->screens[display->default_screen].y + 1, + display->screens[display->default_screen].x + WIN_XSIZE + 1, + display->screens[display->default_screen].y + WIN_YSIZE + 1); + + show_video_bitmap(video_bitmap); + + return (Window)video_bitmap; +} + +Status XStringListToTextProperty(char **list, int count, + XTextProperty *text_prop_return) +{ + char *string; + + if (count >= 1) + { + string = malloc(strlen(list[0] + 1)); + strcpy(string, list[0]); + text_prop_return->value = (unsigned char *)string; + return 1; + } + else + text_prop_return = NULL; + + return 0; +} + +void XFree(void *data) +{ + if (data) + free(data); +} + +GC XCreateGC(Display *display, Drawable d, unsigned long value_mask, + XGCValues *values) +{ + XGCValues *gcv; + gcv = malloc(sizeof(XGCValues)); + gcv->foreground = values->foreground; + gcv->background = values->background; + gcv->graphics_exposures = values->graphics_exposures; + gcv->clip_mask = values->clip_mask; + gcv->clip_x_origin = values->clip_x_origin; + gcv->clip_y_origin = values->clip_y_origin; + gcv->value_mask = value_mask; + return (GC)gcv; +} + +void XSetClipMask(Display *display, GC gc, Pixmap pixmap) +{ + XGCValues *gcv = (XGCValues *)gc; + + gcv->clip_mask = pixmap; + gcv->value_mask |= GCClipMask; +} + +void XSetClipOrigin(Display *display, GC gc, int x, int y) +{ + XGCValues *gcv = (XGCValues *)gc; + + gcv->clip_x_origin = x; + gcv->clip_x_origin = y; +} + +void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y, + unsigned int width, unsigned int height) +{ + boolean mouse_off = FALSE; + + if ((BITMAP *)d == video_bitmap) + { + x += display->screens[display->default_screen].x; + y += display->screens[display->default_screen].y; + freeze_mouse_flag = TRUE; + mouse_off = hide_mouse(display, x, y, width, height); + } + + rectfill((BITMAP *)d, x, y, x + width, y + height, + ((XGCValues *)gc)->foreground); + + if (mouse_off) + unhide_mouse(display); + + freeze_mouse_flag = FALSE; +} + +Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width, + unsigned int height, unsigned int depth) +{ + BITMAP *bitmap = NULL; + + if (gfx_capabilities & GFX_HW_VRAM_BLIT && + width == FXSIZE && height == FYSIZE) + bitmap = create_video_bitmap(width, height); + + if (bitmap == NULL) + bitmap = create_bitmap(width, height); + + return (Pixmap)bitmap; +} + +void XSync(Display *display, Bool discard_events) +{ + wait_for_vsync = TRUE; +} + +inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc, + int src_x, int src_y, + unsigned int width, unsigned int height, + int dest_x, int dest_y) +{ + boolean mouse_off = FALSE; + + if ((BITMAP *)src == video_bitmap) + { + src_x += display->screens[display->default_screen].x; + src_y += display->screens[display->default_screen].y; + } + + if ((BITMAP *)dest == video_bitmap) + { + dest_x += display->screens[display->default_screen].x; + dest_y += display->screens[display->default_screen].y; + freeze_mouse_flag = TRUE; + mouse_off = hide_mouse(display, dest_x, dest_y, width, height); + } + + if (wait_for_vsync) + { + wait_for_vsync = FALSE; + vsync(); + } + + if (((XGCValues *)gc)->value_mask & GCClipMask) + masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y, + width, height); + else + blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y, + width, height); + + if (mouse_off) + unhide_mouse(display); + + freeze_mouse_flag = FALSE; +} + +static BITMAP *Image_to_AllegroBitmap(Image *image) +{ + BITMAP *bitmap; + byte *src_ptr = image->data; + byte pixel_mapping[MAX_COLORS]; + unsigned int depth = 8; + int i, j, x, y; + + /* allocate new allegro bitmap structure */ + if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL) + return NULL; + + clear(bitmap); + + /* try to use existing colors from the global colormap */ + for (i=0; irgb.color_used[i]) + continue; + + r = image->rgb.red[i] >> 10; + g = image->rgb.green[i] >> 10; + b = image->rgb.blue[i] >> 10; + + for (j=0; jheight; y++) + for (x=0; xwidth; x++) + putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]); + + return bitmap; +} + +static BITMAP *Read_PCX_to_AllegroBitmap(char *filename) +{ + BITMAP *bitmap; + Image *image; + + /* read the graphic file in PCX format to internal image structure */ + if ((image = Read_PCX_to_Image(filename)) == NULL) + return NULL; + + /* convert internal image structure to allegro bitmap structure */ + if ((bitmap = Image_to_AllegroBitmap(image)) == NULL) + return NULL; + + set_pallete(global_colormap); + + return bitmap; +} + +int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, + Pixmap *pixmap, Pixmap *pixmap_mask) +{ + BITMAP *bitmap; + + if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL) + return PCX_FileInvalid; + + *pixmap = (Pixmap)bitmap; + *pixmap_mask = (Pixmap)bitmap; + + return PCX_Success; +} + +int XpmReadFileToPixmap(Display *display, Drawable d, char *filename, + Pixmap *pixmap_return, Pixmap *shapemask_return, + XpmAttributes *attributes) +{ + BITMAP *bitmap; + + if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL) + return XpmOpenFailed; + + *pixmap_return = (Pixmap)bitmap; + + return XpmSuccess; +} + +int XReadBitmapFile(Display *display, Drawable d, char *filename, + unsigned int *width_return, unsigned int *height_return, + Pixmap *bitmap_return, + int *x_hot_return, int *y_hot_return) +{ + BITMAP *bitmap; + + if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL) + return BitmapOpenFailed; + + *width_return = bitmap->w; + *height_return = bitmap->h; + *x_hot_return = -1; + *y_hot_return = -1; + *bitmap_return = (Pixmap)bitmap; + + return BitmapSuccess; +} + +void XFreePixmap(Display *display, Pixmap pixmap) +{ + if (pixmap != DUMMY_MASK && + (is_memory_bitmap((BITMAP *)pixmap) || + is_screen_bitmap((BITMAP *)pixmap))) + destroy_bitmap((BITMAP *)pixmap); +} + +void XFreeGC(Display *display, GC gc) +{ + XGCValues *gcv; + + gcv = (XGCValues *)gc; + if (gcv) + free(gcv); +} + +void XCloseDisplay(Display *display) +{ + BITMAP *bitmap = video_bitmap; + + if (is_screen_bitmap(bitmap)) + destroy_bitmap(bitmap); + + if (display->screens) + free(display->screens); + + if (display) + free(display); + + /* return to text mode (or DOS box on Windows screen) */ + set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); +} + +void XNextEvent(Display *display, XEvent *event_return) +{ + while (!pending_events) + XPending(display); + + memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent)); + pending_events--; +} + +static void NewKeyEvent(int key_press_state, KeySym keysym) +{ + XKeyEvent *xkey; + + if (pending_events >= MAX_EVENT_BUFFER) + return; + + pending_events++; + xkey = (XKeyEvent *)&event_buffer[pending_events]; + xkey->type = key_press_state; + xkey->state = (unsigned int)keysym; +} + +#define HANDLE_RAW_KB_ALL_KEYS 0 +#define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY 1 + +static int modifier_scancode[] = +{ + KEY_LSHIFT, + KEY_RSHIFT, + KEY_LCONTROL, + KEY_RCONTROL, + KEY_ALT, + KEY_ALTGR, + KEY_LWIN, + KEY_RWIN, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_SCRLOCK, + -1 +}; + +static void HandleKeyboardRaw(int mode) +{ + int i; + + for (i=0; i> 8); + int ascii = (key_info & 0xff); + KeySym keysym = ScancodeToKeySym(scancode); + + if (scancode == KEY_PAD) + { + /* keys on the numeric keypad return just scancode 'KEY_PAD' + for some reason, so we must handle them separately */ + + if (ascii >= '0' && ascii <= '9') + keysym = XK_KP_0 + (KeySym)(ascii - '0'); + else if (ascii == '.') + keysym = XK_KP_Separator; + } + + NewKeyEvent(KeyPress, keysym); + } + else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG)) + { + /* the allegro function keypressed() does not give us single pressed + modifier keys, so we must detect them with the internal global + allegro variable 'key_shifts' and then handle them separately */ + + HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY); + } +} + +int XPending(Display *display) +{ + XButtonEvent *xbutton; + XMotionEvent *xmotion; + int i; + + /* keyboard event */ + if (game_status == PLAYING) + HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS); + else + HandleKeyboardEvent(); + + /* mouse motion event */ + /* generate mouse motion event only if any mouse buttons are pressed */ + if (mouse_pos != last_mouse_pos && mouse_b) + { + last_mouse_pos = mouse_pos; + pending_events++; + xmotion = (XMotionEvent *)&event_buffer[pending_events]; + xmotion->type = MotionNotify; + xmotion->x = mouse_x - display->screens[display->default_screen].x; + xmotion->y = mouse_y - display->screens[display->default_screen].y; + } + + /* mouse button event */ + if (mouse_b != last_mouse_b) + { + for (i=0; i<3; i++) /* check all three mouse buttons */ + { + int bitmask = (1 << i); + + if ((last_mouse_b & bitmask) != (mouse_b & bitmask)) + { + int mapping[3] = { 1, 3, 2 }; + + pending_events++; + xbutton = (XButtonEvent *)&event_buffer[pending_events]; + xbutton->type = (mouse_b & bitmask ? ButtonPress : ButtonRelease); + xbutton->button = mapping[i]; + xbutton->x = mouse_x - display->screens[display->default_screen].x; + xbutton->y = mouse_y - display->screens[display->default_screen].y; + } + } + last_mouse_b = mouse_b; + } + + return pending_events; +} + +KeySym XLookupKeysym(XKeyEvent *key_event, int index) +{ + return key_event->state; +} + +void NetworkServer(int port, int serveronly) +{ + Error(ERR_WARN, "networking not supported in DOS version"); +} + +#endif /* MSDOS */ diff --git a/src/msdos.h b/src/msdos.h new file mode 100644 index 00000000..c344414e --- /dev/null +++ b/src/msdos.h @@ -0,0 +1,709 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* ©1995 Artsoft Development * +* Holger Schemel * +* 33659 Bielefeld-Senne * +* Telefon: (0521) 493245 * +* eMail: aeglos@valinor.owl.de * +* aeglos@uni-paderborn.de * +* q99492@pbhrzx.uni-paderborn.de * +*----------------------------------------------------------* +* msdos.h * +***********************************************************/ + +#include +#include + +/* allegro defines TRUE as -1 */ +#ifdef TRUE +#undef TRUE +#undef FALSE +#endif + +#define TRUE 1 +#define FALSE 0 + +#define XRES 800 +#define YRES 600 + +/* additional Allegro keyboard mapping */ + +/* The following are all undefined in Allegro */ +#define NEW_KEY_BACKSLASH 86 +#define NEW_KEY_1_PAD 101 +#define NEW_KEY_2_PAD 102 +#define NEW_KEY_3_PAD 103 +#define NEW_KEY_4_PAD 104 +#define NEW_KEY_5_PAD 105 +#define NEW_KEY_6_PAD 106 +#define NEW_KEY_7_PAD 107 +#define NEW_KEY_8_PAD 108 +#define NEW_KEY_9_PAD 109 +#define NEW_KEY_0_PAD 110 +#define NEW_KEY_STOP_PAD 111 +#define NEW_KEY_EQUALS_PAD 112 +#define NEW_KEY_SLASH_PAD 113 +#define NEW_KEY_ASTERISK_PAD 114 +#define NEW_KEY_ENTER_PAD 115 + +/* X11 keyboard mapping (from 'keysymdef.h') */ + +#define XK_VoidSymbol 0xFFFFFF /* void symbol */ + +/* + * TTY Functions, cleverly chosen to map to ascii, for convenience of + * programming, but could have been arbitrary (at the cost of lookup + * tables in client code. + */ + +#define XK_BackSpace 0xFF08 /* back space, back char */ +#define XK_Tab 0xFF09 +#define XK_Linefeed 0xFF0A /* Linefeed, LF */ +#define XK_Clear 0xFF0B +#define XK_Return 0xFF0D /* Return, enter */ +#define XK_Pause 0xFF13 /* Pause, hold */ +#define XK_Scroll_Lock 0xFF14 +#define XK_Sys_Req 0xFF15 +#define XK_Escape 0xFF1B +#define XK_Delete 0xFFFF /* Delete, rubout */ + +/* International & multi-key character composition */ + +#define XK_Multi_key 0xFF20 /* Multi-key character compose */ +#define XK_SingleCandidate 0xFF3C +#define XK_MultipleCandidate 0xFF3D +#define XK_PreviousCandidate 0xFF3E + +/* Cursor control & motion */ + +#define XK_Home 0xFF50 +#define XK_Left 0xFF51 /* Move left, left arrow */ +#define XK_Up 0xFF52 /* Move up, up arrow */ +#define XK_Right 0xFF53 /* Move right, right arrow */ +#define XK_Down 0xFF54 /* Move down, down arrow */ +#define XK_Prior 0xFF55 /* Prior, previous */ +#define XK_Page_Up 0xFF55 +#define XK_Next 0xFF56 /* Next */ +#define XK_Page_Down 0xFF56 +#define XK_End 0xFF57 /* EOL */ +#define XK_Begin 0xFF58 /* BOL */ + +/* Misc Functions */ + +#define XK_Select 0xFF60 /* Select, mark */ +#define XK_Print 0xFF61 +#define XK_Execute 0xFF62 /* Execute, run, do */ +#define XK_Insert 0xFF63 /* Insert, insert here */ +#define XK_Undo 0xFF65 /* Undo, oops */ +#define XK_Redo 0xFF66 /* redo, again */ +#define XK_Menu 0xFF67 +#define XK_Find 0xFF68 /* Find, search */ +#define XK_Cancel 0xFF69 /* Cancel, stop, abort, exit */ +#define XK_Help 0xFF6A /* Help */ +#define XK_Break 0xFF6B +#define XK_Mode_switch 0xFF7E /* Character set switch */ +#define XK_script_switch 0xFF7E /* Alias for mode_switch */ +#define XK_Num_Lock 0xFF7F + +/* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ + +#define XK_KP_Space 0xFF80 /* space */ +#define XK_KP_Tab 0xFF89 +#define XK_KP_Enter 0xFF8D /* enter */ +#define XK_KP_F1 0xFF91 /* PF1, KP_A, ... */ +#define XK_KP_F2 0xFF92 +#define XK_KP_F3 0xFF93 +#define XK_KP_F4 0xFF94 +#define XK_KP_Home 0xFF95 +#define XK_KP_Left 0xFF96 +#define XK_KP_Up 0xFF97 +#define XK_KP_Right 0xFF98 +#define XK_KP_Down 0xFF99 +#define XK_KP_Prior 0xFF9A +#define XK_KP_Page_Up 0xFF9A +#define XK_KP_Next 0xFF9B +#define XK_KP_Page_Down 0xFF9B +#define XK_KP_End 0xFF9C +#define XK_KP_Begin 0xFF9D +#define XK_KP_Insert 0xFF9E +#define XK_KP_Delete 0xFF9F +#define XK_KP_Equal 0xFFBD /* equals */ +#define XK_KP_Multiply 0xFFAA +#define XK_KP_Add 0xFFAB +#define XK_KP_Separator 0xFFAC /* separator, often comma */ +#define XK_KP_Subtract 0xFFAD +#define XK_KP_Decimal 0xFFAE +#define XK_KP_Divide 0xFFAF + +#define XK_KP_0 0xFFB0 +#define XK_KP_1 0xFFB1 +#define XK_KP_2 0xFFB2 +#define XK_KP_3 0xFFB3 +#define XK_KP_4 0xFFB4 +#define XK_KP_5 0xFFB5 +#define XK_KP_6 0xFFB6 +#define XK_KP_7 0xFFB7 +#define XK_KP_8 0xFFB8 +#define XK_KP_9 0xFFB9 + +/* + * Auxilliary Functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufactures have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + +#define XK_F1 0xFFBE +#define XK_F2 0xFFBF +#define XK_F3 0xFFC0 +#define XK_F4 0xFFC1 +#define XK_F5 0xFFC2 +#define XK_F6 0xFFC3 +#define XK_F7 0xFFC4 +#define XK_F8 0xFFC5 +#define XK_F9 0xFFC6 +#define XK_F10 0xFFC7 +#define XK_F11 0xFFC8 +#define XK_L1 0xFFC8 +#define XK_F12 0xFFC9 +#define XK_L2 0xFFC9 +#define XK_F13 0xFFCA +#define XK_L3 0xFFCA +#define XK_F14 0xFFCB +#define XK_L4 0xFFCB +#define XK_F15 0xFFCC +#define XK_L5 0xFFCC +#define XK_F16 0xFFCD +#define XK_L6 0xFFCD +#define XK_F17 0xFFCE +#define XK_L7 0xFFCE +#define XK_F18 0xFFCF +#define XK_L8 0xFFCF +#define XK_F19 0xFFD0 +#define XK_L9 0xFFD0 +#define XK_F20 0xFFD1 +#define XK_L10 0xFFD1 +#define XK_F21 0xFFD2 +#define XK_R1 0xFFD2 +#define XK_F22 0xFFD3 +#define XK_R2 0xFFD3 +#define XK_F23 0xFFD4 +#define XK_R3 0xFFD4 +#define XK_F24 0xFFD5 +#define XK_R4 0xFFD5 +#define XK_F25 0xFFD6 +#define XK_R5 0xFFD6 +#define XK_F26 0xFFD7 +#define XK_R6 0xFFD7 +#define XK_F27 0xFFD8 +#define XK_R7 0xFFD8 +#define XK_F28 0xFFD9 +#define XK_R8 0xFFD9 +#define XK_F29 0xFFDA +#define XK_R9 0xFFDA +#define XK_F30 0xFFDB +#define XK_R10 0xFFDB +#define XK_F31 0xFFDC +#define XK_R11 0xFFDC +#define XK_F32 0xFFDD +#define XK_R12 0xFFDD +#define XK_F33 0xFFDE +#define XK_R13 0xFFDE +#define XK_F34 0xFFDF +#define XK_R14 0xFFDF +#define XK_F35 0xFFE0 +#define XK_R15 0xFFE0 + +/* Modifiers */ + +#define XK_Shift_L 0xFFE1 /* Left shift */ +#define XK_Shift_R 0xFFE2 /* Right shift */ +#define XK_Control_L 0xFFE3 /* Left control */ +#define XK_Control_R 0xFFE4 /* Right control */ +#define XK_Caps_Lock 0xFFE5 /* Caps lock */ +#define XK_Shift_Lock 0xFFE6 /* Shift lock */ + +#define XK_Meta_L 0xFFE7 /* Left meta */ +#define XK_Meta_R 0xFFE8 /* Right meta */ +#define XK_Alt_L 0xFFE9 /* Left alt */ +#define XK_Alt_R 0xFFEA /* Right alt */ +#define XK_Super_L 0xFFEB /* Left super */ +#define XK_Super_R 0xFFEC /* Right super */ +#define XK_Hyper_L 0xFFED /* Left hyper */ +#define XK_Hyper_R 0xFFEE /* Right hyper */ + +/* + * Latin 1 + * Byte 3 = 0 + */ + +#define XK_space 0x020 +#define XK_exclam 0x021 +#define XK_quotedbl 0x022 +#define XK_numbersign 0x023 +#define XK_dollar 0x024 +#define XK_percent 0x025 +#define XK_ampersand 0x026 +#define XK_apostrophe 0x027 +#define XK_quoteright 0x027 /* deprecated */ +#define XK_parenleft 0x028 +#define XK_parenright 0x029 +#define XK_asterisk 0x02a +#define XK_plus 0x02b +#define XK_comma 0x02c +#define XK_minus 0x02d +#define XK_period 0x02e +#define XK_slash 0x02f +#define XK_0 0x030 +#define XK_1 0x031 +#define XK_2 0x032 +#define XK_3 0x033 +#define XK_4 0x034 +#define XK_5 0x035 +#define XK_6 0x036 +#define XK_7 0x037 +#define XK_8 0x038 +#define XK_9 0x039 +#define XK_colon 0x03a +#define XK_semicolon 0x03b +#define XK_less 0x03c +#define XK_equal 0x03d +#define XK_greater 0x03e +#define XK_question 0x03f +#define XK_at 0x040 +#define XK_A 0x041 +#define XK_B 0x042 +#define XK_C 0x043 +#define XK_D 0x044 +#define XK_E 0x045 +#define XK_F 0x046 +#define XK_G 0x047 +#define XK_H 0x048 +#define XK_I 0x049 +#define XK_J 0x04a +#define XK_K 0x04b +#define XK_L 0x04c +#define XK_M 0x04d +#define XK_N 0x04e +#define XK_O 0x04f +#define XK_P 0x050 +#define XK_Q 0x051 +#define XK_R 0x052 +#define XK_S 0x053 +#define XK_T 0x054 +#define XK_U 0x055 +#define XK_V 0x056 +#define XK_W 0x057 +#define XK_X 0x058 +#define XK_Y 0x059 +#define XK_Z 0x05a +#define XK_bracketleft 0x05b +#define XK_backslash 0x05c +#define XK_bracketright 0x05d +#define XK_asciicircum 0x05e +#define XK_underscore 0x05f +#define XK_grave 0x060 +#define XK_quoteleft 0x060 /* deprecated */ +#define XK_a 0x061 +#define XK_b 0x062 +#define XK_c 0x063 +#define XK_d 0x064 +#define XK_e 0x065 +#define XK_f 0x066 +#define XK_g 0x067 +#define XK_h 0x068 +#define XK_i 0x069 +#define XK_j 0x06a +#define XK_k 0x06b +#define XK_l 0x06c +#define XK_m 0x06d +#define XK_n 0x06e +#define XK_o 0x06f +#define XK_p 0x070 +#define XK_q 0x071 +#define XK_r 0x072 +#define XK_s 0x073 +#define XK_t 0x074 +#define XK_u 0x075 +#define XK_v 0x076 +#define XK_w 0x077 +#define XK_x 0x078 +#define XK_y 0x079 +#define XK_z 0x07a +#define XK_braceleft 0x07b +#define XK_bar 0x07c +#define XK_braceright 0x07d +#define XK_asciitilde 0x07e + +#define XK_nobreakspace 0x0a0 +#define XK_exclamdown 0x0a1 +#define XK_cent 0x0a2 +#define XK_sterling 0x0a3 +#define XK_currency 0x0a4 +#define XK_yen 0x0a5 +#define XK_brokenbar 0x0a6 +#define XK_section 0x0a7 +#define XK_diaeresis 0x0a8 +#define XK_copyright 0x0a9 +#define XK_ordfeminine 0x0aa +#define XK_guillemotleft 0x0ab /* left angle quotation mark */ +#define XK_notsign 0x0ac +#define XK_hyphen 0x0ad +#define XK_registered 0x0ae +#define XK_macron 0x0af +#define XK_degree 0x0b0 +#define XK_plusminus 0x0b1 +#define XK_twosuperior 0x0b2 +#define XK_threesuperior 0x0b3 +#define XK_acute 0x0b4 +#define XK_mu 0x0b5 +#define XK_paragraph 0x0b6 +#define XK_periodcentered 0x0b7 +#define XK_cedilla 0x0b8 +#define XK_onesuperior 0x0b9 +#define XK_masculine 0x0ba +#define XK_guillemotright 0x0bb /* right angle quotation mark */ +#define XK_onequarter 0x0bc +#define XK_onehalf 0x0bd +#define XK_threequarters 0x0be +#define XK_questiondown 0x0bf +#define XK_Agrave 0x0c0 +#define XK_Aacute 0x0c1 +#define XK_Acircumflex 0x0c2 +#define XK_Atilde 0x0c3 +#define XK_Adiaeresis 0x0c4 +#define XK_Aring 0x0c5 +#define XK_AE 0x0c6 +#define XK_Ccedilla 0x0c7 +#define XK_Egrave 0x0c8 +#define XK_Eacute 0x0c9 +#define XK_Ecircumflex 0x0ca +#define XK_Ediaeresis 0x0cb +#define XK_Igrave 0x0cc +#define XK_Iacute 0x0cd +#define XK_Icircumflex 0x0ce +#define XK_Idiaeresis 0x0cf +#define XK_ETH 0x0d0 +#define XK_Eth 0x0d0 /* deprecated */ +#define XK_Ntilde 0x0d1 +#define XK_Ograve 0x0d2 +#define XK_Oacute 0x0d3 +#define XK_Ocircumflex 0x0d4 +#define XK_Otilde 0x0d5 +#define XK_Odiaeresis 0x0d6 +#define XK_multiply 0x0d7 +#define XK_Ooblique 0x0d8 +#define XK_Ugrave 0x0d9 +#define XK_Uacute 0x0da +#define XK_Ucircumflex 0x0db +#define XK_Udiaeresis 0x0dc +#define XK_Yacute 0x0dd +#define XK_THORN 0x0de +#define XK_Thorn 0x0de /* deprecated */ +#define XK_ssharp 0x0df +#define XK_agrave 0x0e0 +#define XK_aacute 0x0e1 +#define XK_acircumflex 0x0e2 +#define XK_atilde 0x0e3 +#define XK_adiaeresis 0x0e4 +#define XK_aring 0x0e5 +#define XK_ae 0x0e6 +#define XK_ccedilla 0x0e7 +#define XK_egrave 0x0e8 +#define XK_eacute 0x0e9 +#define XK_ecircumflex 0x0ea +#define XK_ediaeresis 0x0eb +#define XK_igrave 0x0ec +#define XK_iacute 0x0ed +#define XK_icircumflex 0x0ee +#define XK_idiaeresis 0x0ef +#define XK_eth 0x0f0 +#define XK_ntilde 0x0f1 +#define XK_ograve 0x0f2 +#define XK_oacute 0x0f3 +#define XK_ocircumflex 0x0f4 +#define XK_otilde 0x0f5 +#define XK_odiaeresis 0x0f6 +#define XK_division 0x0f7 +#define XK_oslash 0x0f8 +#define XK_ugrave 0x0f9 +#define XK_uacute 0x0fa +#define XK_ucircumflex 0x0fb +#define XK_udiaeresis 0x0fc +#define XK_yacute 0x0fd +#define XK_thorn 0x0fe +#define XK_ydiaeresis 0x0ff + +/* end of X11 keyboard mapping */ + +#define MOUSE_FILENAME "mouse.pcx" +#define JOYSTICK_FILENAME "joystick.cnf" + +#define screen myscreen + +#define XFlush(a) +#define XGetImage(a,b,c,d,e,f,g,h) ((XImage *) NULL) +#define XAutoRepeatOn(a) +#define XAutoRepeatOff(a) +#define XDisplayName(a) ((char *) NULL) +#define XFreeColors(a,b,c,d,e) +#define XpmFreeAttributes(a) +#define XSelectInput(a,b,c) +#define XDefaultDepth(a,b) (8) +#define XSetWMProperties(a,b,c,d,e,f,g,h,i) + +#define MAX_EVENT_BUFFER 256 +#define MAX_SCANCODES 128 + +#define True 1 +#define False 0 +#define None 0L + +#define DUMMY_FILE ((void *) -1) +#define DUMMY_MASK (-1) + +#define KeyPressMask (1L << 0) +#define KeyReleaseMask (1L << 1) +#define ButtonPressMask (1L << 2) +#define ButtonReleaseMask (1L << 3) +#define ButtonMotionMask (1L << 13) +#define ExposureMask (1L << 15) +#define StructureNotifyMask (1L << 17) +#define FocusChangeMask (1L << 21) + +#define KeyPress 2 +#define KeyRelease 3 +#define ButtonPress 4 +#define ButtonRelease 5 +#define MotionNotify 6 +#define FocusIn 9 +#define FocusOut 10 +#define Expose 12 +#define UnmapNotify 18 +#define MapNotify 19 +#define ClientMessage 33 + +#define GCForeground (1L << 2) +#define GCBackground (1L << 3) +#define GCGraphicsExposures (1L << 16) +#define GCClipMask (1L << 19) + +#define NormalState 1 /* most applications want to start this way */ +#define InputHint (1L << 0) +#define StateHint (1L << 1) +#define IconPixmapHint (1L << 2) +#define IconMaskHint (1L << 5) +#define PSize (1L << 3) /* program specified size */ +#define PMinSize (1L << 4) /* program specified minimum size */ +#define PMaxSize (1L << 5) /* program specified maximum size */ + +#define XpmSuccess 0 +#define XpmOpenFailed -1 +#define XpmFileInvalid -2 +#define XpmNoMemory -3 +#define XpmColorFailed -4 + +#define XpmCloseness (1L << 12) + +#define PCX_Success 0 +#define PCX_OpenFailed -1 +#define PCX_ReadFailed -2 +#define PCX_FileInvalid -3 +#define PCX_NoMemory -4 +#define PCX_ColorFailed -5 + +#define BitmapSuccess 0 +#define BitmapOpenFailed 1 +#define BitmapFileInvalid 2 +#define BitmapNoMemory 3 + +#define ZPixmap 2 /* depth == drawable depth */ + +#define DefaultScreen(dpy) (((_XPrivDisplay)dpy)->default_screen) +#define DefaultColormap(dpy, scr) (ScreenOfDisplay(dpy,scr)->cmap) +#define ScreenOfDisplay(dpy, scr) (&((_XPrivDisplay)dpy)->screens[scr]) +#define BlackPixel(dpy, scr) (ScreenOfDisplay(dpy,scr)->black_pixel) +#define WhitePixel(dpy, scr) (ScreenOfDisplay(dpy,scr)->white_pixel) +#define RootWindow(dpy, scr) (ScreenOfDisplay(dpy,scr)->root) +#define AllPlanes ((unsigned long)~0L) + +#define DefaultVisual(dpy, scr) (NULL) +#define DefaultDepth(dpy, scr) (NULL) +#define XDisplayWidth(dpy, scr) (XRES) +#define XDisplayHeight(dpy, scr) (YRES) + +#define XGetPixel(ximage, x, y) \ + ((*((ximage)->f.get_pixel))((ximage), (x), (y))) + +typedef unsigned long Pixel; /* Index into colormap */ +typedef unsigned long XID; +typedef XID Window; +typedef XID Drawable; +typedef XID Pixmap; +typedef XID Colormap; +typedef XID KeySym; +typedef XID GContext; +typedef struct _XDisplay Display; +typedef long Visual; +typedef long XVisualInfo; +typedef long Atom; +typedef int Status; +typedef int Bool; + +typedef struct _XGC +{ + GContext gid; /* protocol ID for graphics context */ +} *GC; + +typedef struct +{ + Colormap cmap; /* default color map */ + Window root; /* root window id */ + unsigned long white_pixel; /* white pixel value */ + unsigned long black_pixel; /* black pixel value */ + int x; + int y; + unsigned int width; + unsigned int height; + BITMAP *video_bitmap; +} Screen; + +typedef struct _XDisplay +{ + int default_screen; /* default screen for operations */ + Screen *screens; /* pointer to list of screens */ + BITMAP *mouse_ptr; +} *_XPrivDisplay; + +typedef struct _XImage +{ + struct funcs + { + unsigned long (*get_pixel) (struct _XImage *, int, int); + } f; +} XImage; + +typedef struct +{ + long flags; /* marks which fields in this structure are defined */ + int width, height; /* should set so old wm's don't mess up */ + int min_width, min_height; + int max_width, max_height; +} XSizeHints; + +typedef struct +{ + long flags; /* marks which fields in this structure are defined */ + Bool input; /* does this application rely on the window manager to + get keyboard input? */ + int initial_state; /* see below */ + Pixmap icon_pixmap; /* pixmap to be used as icon */ + Pixmap icon_mask; /* icon mask bitmap */ +} XWMHints; + +typedef struct +{ + char *res_name; + char *res_class; +} XClassHint; + +typedef struct +{ + unsigned char *value; /* same as Property routines */ +} XTextProperty; + +typedef struct +{ + unsigned long foreground; /* foreground pixel */ + unsigned long background; /* background pixel */ + Bool graphics_exposures; /* boolean, should exposures be generated */ + Pixmap clip_mask; /* bitmap clipping; other calls for rects */ + int clip_x_origin; /* x origin for clipping */ + int clip_y_origin; /* y origin for clipping */ + unsigned long value_mask; +} XGCValues; + +typedef struct +{ + unsigned long valuemask; /* specifies which attributes are */ + unsigned int closeness; /* allowable RGB deviation */ + Pixel *pixels; /* list of used color pixels */ + unsigned int npixels; /* number of used pixels */ +} XpmAttributes; + +typedef struct +{ + int type; + int x, y; + int width, height; +} XExposeEvent; + +typedef struct +{ + int type; /* of event */ + int x, y; /* pointer x, y coordinates in event window */ + unsigned int button; /* detail */ +} XButtonEvent; + +typedef struct +{ + int type; + int x, y; /* pointer x, y coordinates in event window */ +} XMotionEvent; + +typedef struct +{ + int type; /* of event */ + unsigned int state; /* key or button mask */ +} XKeyEvent; + +typedef struct +{ + int type; /* FocusIn or FocusOut */ +} XFocusChangeEvent; + +typedef struct +{ + int type; /* ClientMessage */ +} XClientMessageEvent; + +typedef union _XEvent +{ + int type; /* must not be changed; first element */ + XExposeEvent xexpose; + XButtonEvent xbutton; + XMotionEvent xmotion; + XKeyEvent xkey; +} XEvent; + +unsigned char get_ascii(KeySym); +void XMapWindow(Display *, Window); +Display *XOpenDisplay(char *); +Window XCreateSimpleWindow(Display *, Window, int, int, + unsigned int, unsigned int, unsigned int, + unsigned long, unsigned long); +Status XStringListToTextProperty(char **, int, XTextProperty *); +void XFree(void *); +GC XCreateGC(Display *, Drawable, unsigned long, XGCValues *); +void XSetClipMask(Display *, GC, Pixmap); +void XSetClipOrigin(Display *, GC, int, int); +void XFillRectangle(Display *, Drawable, GC, int, int, + unsigned int, unsigned int); +Pixmap XCreatePixmap(Display *, Drawable, unsigned int, unsigned int, + unsigned int); +void XSync(Display *, Bool); +inline void XCopyArea(Display *, Drawable, Drawable, GC, int, int, + unsigned int, unsigned int, int, int); +int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *); +int XpmReadFileToPixmap(Display *, Drawable, char *, Pixmap *, Pixmap *, + XpmAttributes *); +int XReadBitmapFile(Display *, Drawable, char *, + unsigned int *, unsigned int *, Pixmap *, int *, int *); +void XFreePixmap(Display *, Pixmap); +void XFreeGC(Display *, GC); +void XCloseDisplay(Display *); +void XNextEvent(Display *, XEvent *); +int XPending(Display *); +KeySym XLookupKeysym(XKeyEvent *, int); +void NetworkServer(int, int); diff --git a/src/netserv.c b/src/netserv.c new file mode 100644 index 00000000..a9ffa6a7 --- /dev/null +++ b/src/netserv.c @@ -0,0 +1,665 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* network.c * +***********************************************************/ + +#ifndef MSDOS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netserv.h" +#include "misc.h" + +static int clients = 0; +static int onceonly = 0; + +struct NetworkServerPlayerInfo +{ + int fd; + char player_name[16]; + unsigned char number; + struct NetworkServerPlayerInfo *next; + char active; + char introduced; + unsigned char readbuffer[MAX_BUFFER_SIZE]; + unsigned char writbuffer[MAX_BUFFER_SIZE]; + int nread, nwrite; + byte action; + boolean action_received; +}; + +static struct NetworkServerPlayerInfo *first_player = NULL; + +#define NEXT(player) ((player)->next ? (player)->next : first_player) + +static struct sockaddr_in saddr; +static int lfd; +static unsigned char realbuffer[512], *buffer = realbuffer + 4; + +static int interrupt; +static int tcp = -1; + +static unsigned long ServerFrameCounter = 0; + +static fd_set fds; + +static void addtobuffer(struct NetworkServerPlayerInfo *player, + unsigned char *b, int len) +{ + if (player->nwrite + len >= MAX_BUFFER_SIZE) + Error(ERR_EXIT_NETWORK_SERVER, + "internal error: network send buffer overflow"); + + memcpy(player->writbuffer + player->nwrite, b, len); + player->nwrite += len; +} + +static void flushuser(struct NetworkServerPlayerInfo *player) +{ + if (player->nwrite) + { + write(player->fd, player->writbuffer, player->nwrite); + player->nwrite = 0; + } +} + +static void broadcast(struct NetworkServerPlayerInfo *except, + int len, int activeonly) +{ + struct NetworkServerPlayerInfo *player; + + realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; + realbuffer[3] = (unsigned char)len; + for (player=first_player; player; player=player->next) + if (player != except && (player->active || !activeonly) && player->introduced) + addtobuffer(player, realbuffer, 4 + len); +} + +static void sendtoone(struct NetworkServerPlayerInfo *to, int len) +{ + realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; + realbuffer[3] = (unsigned char)len; + addtobuffer(to, realbuffer, 4 + len); +} + +static void RemovePlayer(struct NetworkServerPlayerInfo *player) +{ + struct NetworkServerPlayerInfo *v; + + if (options.verbose) + Error(ERR_NETWORK_SERVER, "dropping client %d (%s)", + player->number, player->player_name); + + if (player == first_player) + first_player = player->next; + else + { + for (v=first_player; v; v=v->next) + { + if (v->next && v->next == player) + { + v->next = player->next; + break; + } + } + } + close(player->fd); + + if (player->introduced) + { + buffer[0] = player->number; + buffer[1] = OP_PLAYER_DISCONNECTED; + broadcast(player, 2, 0); + } + + free(player); + clients--; + + if (onceonly && clients == 0) + { + if (options.verbose) + { + Error(ERR_NETWORK_SERVER, "no clients left"); + Error(ERR_NETWORK_SERVER, "aborting"); + } + exit(0); + } +} + +static void AddPlayer(int fd) +{ + struct NetworkServerPlayerInfo *player, *v; + unsigned char nxn; + + player = checked_malloc(sizeof (struct NetworkServerPlayerInfo)); + + player->fd = fd; + player->player_name[0] = 0; + player->next = first_player; + player->active = 0; + player->nread = 0; + player->nwrite = 0; + player->introduced = 0; + player->action = 0; + player->action_received = FALSE; + + first_player = player; + + nxn = 1; + + again: + v = player->next; + while(v) + { + if (v->number == nxn) + { + nxn++; + goto again; + } + v = v->next; + } + + player->number = nxn; + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d connecting from %s", + nxn, inet_ntoa(saddr.sin_addr)); + clients++; + + buffer[0] = 0; + buffer[1] = OP_YOUR_NUMBER; + buffer[2] = player->number; + sendtoone(player, 3); +} + +static void Handle_OP_PROTOCOL_VERSION(struct NetworkServerPlayerInfo *player, + unsigned int len) +{ + if (len != 5 || + buffer[2] != PROTOCOL_VERSION_1 || + buffer[3] != PROTOCOL_VERSION_2) + { + if (options.verbose) + Error(ERR_NETWORK_SERVER, + "client %d (%s) has wrong protocol version %d.%d.%d", + player->number, player->player_name, buffer[2], buffer[3], buffer[4]); + + buffer[0] = 0; + buffer[1] = OP_BAD_PROTOCOL_VERSION; + buffer[2] = PROTOCOL_VERSION_1; + buffer[3] = PROTOCOL_VERSION_2; + buffer[4] = PROTOCOL_VERSION_3; + sendtoone(player, 5); + flushuser(player); + + RemovePlayer(player); + interrupt = 1; + } + else + { + if (options.verbose) + Error(ERR_NETWORK_SERVER, + "client %d (%s) uses protocol version %d.%d.%d", + player->number, player->player_name, buffer[2], buffer[3], buffer[4]); + } +} + +static void Handle_OP_NUMBER_WANTED(struct NetworkServerPlayerInfo *player) +{ + struct NetworkServerPlayerInfo *v; + int client_nr = player->number; + int nr_wanted = buffer[2]; + int nr_is_free = 1; + + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d (%s) wants to switch to # %d", + player->number, player->player_name, nr_wanted); + + for (v=first_player; v; v=v->next) + { + if (v->number == nr_wanted) + { + nr_is_free = 0; + break; + } + } + + if (options.verbose) + { + if (nr_is_free) + Error(ERR_NETWORK_SERVER, "client %d (%s) switches to # %d", + player->number, player->player_name, nr_wanted); + else if (player->number == nr_wanted) + Error(ERR_NETWORK_SERVER, "client %d (%s) still has # %d", + player->number, player->player_name, nr_wanted); + else + Error(ERR_NETWORK_SERVER, + "client %d (%s) cannot switch (client %d still exists)", + player->number, player->player_name, nr_wanted); + } + + if (nr_is_free) + player->number = nr_wanted; + + buffer[0] = client_nr; + buffer[1] = OP_NUMBER_WANTED; + buffer[2] = nr_wanted; + buffer[3] = player->number; + + /* + sendtoone(player, 4); + */ + + broadcast(NULL, 4, 0); +} + +static void Handle_OP_PLAYER_NAME(struct NetworkServerPlayerInfo *player, + unsigned int len) +{ + struct NetworkServerPlayerInfo *v; + int i; + + if (len>16) + len=16; + memcpy(player->player_name, &buffer[2], len-2); + player->player_name[len-2] = 0; + for (i=0; iplayer_name[i] < ' ' || + ((unsigned char)(player->player_name[i]) > 0x7e && + (unsigned char)(player->player_name[i]) <= 0xa0)) + { + player->player_name[i] = 0; + break; + } + } + + if (!player->introduced) + { + buffer[0] = player->number; + buffer[1] = OP_PLAYER_CONNECTED; + broadcast(player, 2, 0); + } + + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d calls itself \"%s\"", + player->number, player->player_name); + buffer[1] = OP_PLAYER_NAME; + broadcast(player, len, 0); + + if (!player->introduced) + { + for (v=first_player; v; v=v->next) + { + if (v != player && v->introduced) + { + buffer[0] = v->number; + buffer[1] = OP_PLAYER_CONNECTED; + sendtoone(player, 2); + buffer[1] = OP_PLAYER_NAME; + memcpy(&buffer[2], v->player_name, 14); + sendtoone(player, 2+strlen(v->player_name)); + } + } + } + + player->introduced = 1; +} + +static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) +{ + struct NetworkServerPlayerInfo *v, *w; + + if (options.verbose) + Error(ERR_NETWORK_SERVER, + "client %d (%s) starts game [level %d from levedir %d (%s)]", + player->number, player->player_name, + (buffer[2] << 8) + buffer[3], + (buffer[4] << 8) + buffer[5], + &buffer[6]); + + for (w=first_player; w; w=w->next) + if (w->introduced) + w->active = 1; + + /* reset frame counter */ + ServerFrameCounter = 0; + + /* reset player actions */ + for (v=first_player; v; v=v->next) + { + v->action = 0; + v->action_received = FALSE; + } + + broadcast(NULL, 10 + strlen((char *)&buffer[10])+1, 0); +} + +static void Handle_OP_PAUSE_PLAYING(struct NetworkServerPlayerInfo *player) +{ + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d (%s) pauses game", + player->number, player->player_name); + broadcast(NULL, 2, 0); +} + +static void Handle_OP_CONTINUE_PLAYING(struct NetworkServerPlayerInfo *player) +{ + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d (%s) continues game", + player->number, player->player_name); + broadcast(NULL, 2, 0); +} + +static void Handle_OP_STOP_PLAYING(struct NetworkServerPlayerInfo *player) +{ + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d (%s) stops game", + player->number, player->player_name); + broadcast(NULL, 2, 0); +} + +static void Handle_OP_MOVE_FIGURE(struct NetworkServerPlayerInfo *player) +{ + struct NetworkServerPlayerInfo *v; + int last_client_nr = 0; + int i; + + /* store player action */ + for (v=first_player; v; v=v->next) + { + if (v->number == player->number) + { + v->action = buffer[2]; + v->action_received = TRUE; + } + } + + /* check if server received action from each player */ + for (v=first_player; v; v=v->next) + { + if (!v->action_received) + return; + + if (v->number > last_client_nr) + last_client_nr = v->number; + } + + /* initialize all player actions to zero */ + for (i=0; inext) + { + buffer[6 + v->number-1] = v->action; + v->action = 0; + v->action_received = FALSE; + } + + buffer[2] = (unsigned char)((ServerFrameCounter >> 24) & 0xff); + buffer[3] = (unsigned char)((ServerFrameCounter >> 16) & 0xff); + buffer[4] = (unsigned char)((ServerFrameCounter >> 8) & 0xff); + buffer[5] = (unsigned char)((ServerFrameCounter >> 0) & 0xff); + + broadcast(NULL, 6 + last_client_nr, 0); + + ServerFrameCounter++; +} + +void NetworkServer(int port, int serveronly) +{ + int i, sl, on; + struct NetworkServerPlayerInfo *player; + int mfd; + int r; + unsigned int len; + struct protoent *tcpproto; + struct timeval tv; + int is_daemon = 0; + +#ifndef NeXT + struct sigaction sact; +#endif + + if (port == 0) + port = DEFAULT_SERVER_PORT; + + if (!serveronly) + onceonly = 1; + + if ((tcpproto = getprotobyname("tcp")) != NULL) + tcp = tcpproto->p_proto; + +#ifdef NeXT + signal(SIGPIPE, SIG_IGN); +#else + sact.sa_handler = SIG_IGN; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; + sigaction(SIGPIPE, &sact, NULL); +#endif + + + if ((lfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) + Error(ERR_EXIT_NETWORK_SERVER, "socket() failed"); + + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(port); + + on = 1; + + setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)); + if (bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) + Error(ERR_EXIT_NETWORK_SERVER, "bind() failed"); + + listen(lfd, 5); + + if (is_daemon) + { + /* become a daemon, breaking all ties with the controlling terminal */ + options.verbose = 0; + for (i=0; i<255; i++) + { + if (i != lfd) + close(i); + } + + if (fork()) + exit(0); + setsid(); + if (fork()) + exit(0); + chdir("/"); + + /* open a fake stdin, stdout, stderr, just in case */ + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); + } + + if (options.verbose) + { + Error(ERR_NETWORK_SERVER, "started up, listening on port %d", port); + Error(ERR_NETWORK_SERVER, "using protocol version %d.%d.%d", + PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3); + } + + while(1) + { + interrupt = 0; + + for (player=first_player; player; player=player->next) + flushuser(player); + + FD_ZERO(&fds); + mfd = lfd; + player = first_player; + while (player) + { + FD_SET(player->fd, &fds); + if (player->fd > mfd) + mfd = player->fd; + player = player->next; + } + FD_SET(lfd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 500000; + if ((sl = select(mfd + 1, &fds, NULL, NULL, &tv)) < 0) + { + if (errno != EINTR) + Error(ERR_EXIT_NETWORK_SERVER, "select() failed"); + else + continue; + } + + if (sl < 0) + continue; + + if (sl == 0) + continue; + + if (FD_ISSET(lfd, &fds)) + { + int newfd, slen; + + slen = sizeof(saddr); + newfd = accept(lfd, (struct sockaddr *)&saddr, &slen); + if (newfd < 0) + { + if (errno != EINTR) + Error(ERR_EXIT_NETWORK_SERVER, "accept() failed"); + } + else + { + if (tcp != -1) + { + on = 1; + setsockopt(newfd, tcp, TCP_NODELAY, (char *)&on, sizeof(int)); + } + AddPlayer(newfd); + } + continue; + } + + player = first_player; + + do + { + if (FD_ISSET(player->fd, &fds)) + { + r = read(player->fd, player->readbuffer + player->nread, MAX_BUFFER_SIZE - player->nread); + if (r <= 0) + { + if (options.verbose) + Error(ERR_NETWORK_SERVER, "EOF from client %d (%s)", + player->number, player->player_name); + RemovePlayer(player); + interrupt = 1; + break; + } + player->nread += r; + while (player->nread >= 4 && player->nread >= 4 + player->readbuffer[3]) + { + len = player->readbuffer[3]; + if (player->readbuffer[0] || player->readbuffer[1] || player->readbuffer[2]) + { + if (options.verbose) + Error(ERR_NETWORK_SERVER, "crap from client %d (%s)", + player->number, player->player_name); + RemovePlayer(player); + interrupt = 1; + break; + } + memcpy(buffer, &player->readbuffer[4], len); + player->nread -= 4 + len; + memmove(player->readbuffer, player->readbuffer + 4 + len, player->nread); + + buffer[0] = player->number; + if (!player->introduced && buffer[1] != OP_PLAYER_NAME) + { + if (options.verbose) + Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME)", buffer[0], buffer[1]); + + RemovePlayer(player); + interrupt = 1; + break; + } + + switch(buffer[1]) + { + case OP_PLAYER_NAME: + Handle_OP_PLAYER_NAME(player, len); + break; + + case OP_PROTOCOL_VERSION: + Handle_OP_PROTOCOL_VERSION(player, len); + break; + + case OP_NUMBER_WANTED: + Handle_OP_NUMBER_WANTED(player); + break; + + case OP_START_PLAYING: + Handle_OP_START_PLAYING(player); + break; + + case OP_PAUSE_PLAYING: + Handle_OP_PAUSE_PLAYING(player); + break; + + case OP_CONTINUE_PLAYING: + Handle_OP_CONTINUE_PLAYING(player); + break; + + case OP_STOP_PLAYING: + Handle_OP_STOP_PLAYING(player); + break; + + case OP_MOVE_FIGURE: + Handle_OP_MOVE_FIGURE(player); + break; + + case OP_BROADCAST_MESSAGE: + buffer[len] = '\0'; + if (options.verbose) + Error(ERR_NETWORK_SERVER, "client %d (%s) sends message: %s", + player->number, player->player_name, &buffer[2]); + broadcast(player, len, 0); + break; + + default: + if (options.verbose) + Error(ERR_NETWORK_SERVER, + "unknown opcode %d from client %d (%s)", + buffer[0], player->number, player->player_name); + } + } + } + + if (player && !interrupt) + player = player->next; + } + while (player && !interrupt); + } +} + +#endif /* !MSDOS */ diff --git a/src/netserv.h b/src/netserv.h new file mode 100644 index 00000000..5177fb4a --- /dev/null +++ b/src/netserv.h @@ -0,0 +1,43 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* netserv.h * +***********************************************************/ + +#ifndef NETSERV_H +#define NETSERV_H + +#include "main.h" + +#define DEFAULT_SERVER_PORT 19504 + +#define PROTOCOL_VERSION_1 1 +#define PROTOCOL_VERSION_2 2 +#define PROTOCOL_VERSION_3 0 + +#define OP_PROTOCOL_VERSION 1 +#define OP_BAD_PROTOCOL_VERSION 2 +#define OP_YOUR_NUMBER 3 +#define OP_NUMBER_WANTED 4 +#define OP_PLAYER_NAME 5 +#define OP_PLAYER_CONNECTED 6 +#define OP_PLAYER_DISCONNECTED 7 +#define OP_START_PLAYING 8 +#define OP_PAUSE_PLAYING 9 +#define OP_CONTINUE_PLAYING 10 +#define OP_STOP_PLAYING 11 +#define OP_MOVE_FIGURE 12 +#define OP_BROADCAST_MESSAGE 13 + +#define MAX_BUFFER_SIZE 4096 + +void NetworkServer(int, int); + +#endif diff --git a/src/network.c b/src/network.c new file mode 100644 index 00000000..5d137f05 --- /dev/null +++ b/src/network.c @@ -0,0 +1,610 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* network.c * +***********************************************************/ + +#ifndef MSDOS + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "network.h" +#include "netserv.h" +#include "game.h" +#include "tape.h" +#include "files.h" +#include "tools.h" +#include "buttons.h" +#include "screens.h" +#include "misc.h" + +#define MAX_PLAYER_NAME_LEN 14 + +struct NetworkClientPlayerInfo +{ + byte nr; + char name[MAX_PLAYER_NAME_LEN + 2]; + struct NetworkClientPlayerInfo *next; +}; + +static struct NetworkClientPlayerInfo first_player = +{ + 0, + EMPTY_PLAYER_NAME, + NULL +}; + +/* server stuff */ + +static int sfd; +static byte realbuffer[512]; +static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE]; +static byte *buffer = realbuffer + 4; +static int nread = 0, nwrite = 0; + +static void SendBufferToServer(int size) +{ + if (!options.network) + return; + + realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; + realbuffer[3] = (byte)size; + buffer[0] = 0; + + if (nwrite + 4 + size >= MAX_BUFFER_SIZE) + Error(ERR_EXIT, "internal error: network send buffer overflow"); + + memcpy(writbuffer + nwrite, realbuffer, 4 + size); + nwrite += 4 + size; + + /* directly send the buffer to the network server */ + write(sfd, writbuffer, nwrite); + nwrite = 0; +} + +struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr) +{ + struct NetworkClientPlayerInfo *player = NULL; + + for (player = &first_player; player; player = player->next) + if (player->nr == player_nr) + break; + + if (player == NULL) /* should not happen */ + Error(ERR_EXIT, "protocol error: reference to non-existing player %d", + player_nr); + + return player; +} + +char *getNetworkPlayerName(int player_nr) +{ + struct NetworkClientPlayerInfo *player; + + if (player_nr == 0) + return("the network game server"); + else if (player_nr == first_player.nr) + return("you"); + else + for (player=&first_player; player; player=player->next) + if (player->nr == player_nr && player->name && strlen(player->name)) + return(player->name); + + return(EMPTY_PLAYER_NAME); +} + +static void StartNetworkServer(int port) +{ + switch (fork()) + { + case 0: + NetworkServer(port, options.serveronly); + + /* never reached */ + exit(0); + + case -1: + Error(ERR_WARN, + "cannot create network server process - no network playing"); + options.network = FALSE; + return; + + default: + /* we are parent process -- resume normal operation */ + return; + } +} + +boolean ConnectToServer(char *hostname, int port) +{ + struct sockaddr_in s; + struct protoent *tcpproto; + int on = 1, i; + + if (hostname) + { + if ((s.sin_addr.s_addr = inet_addr(hostname)) == -1) + { + struct hostent *host; + + if ((host = gethostbyname(hostname)) == NULL) + Error(ERR_EXIT, "cannot locate host '%s'", hostname); + + s.sin_addr = *(struct in_addr *)(host->h_addr_list[0]); + } + } + else + s.sin_addr.s_addr = inet_addr("127.0.0.1"); /* localhost */ + + if (port == 0) + port = DEFAULT_SERVER_PORT; + + s.sin_port = htons(port); + s.sin_family = AF_INET; + + sfd = socket(PF_INET, SOCK_STREAM, 0); + if (sfd < 0) + Error(ERR_EXIT, "out of file descriptors"); + + if ((tcpproto = getprotobyname("tcp")) != NULL) + setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int)); + + if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) == 0) /* connected */ + return TRUE; + + if (hostname) /* connect to specified server failed */ + return FALSE; + + printf("No rocksndiamonds server on localhost - starting up one ...\n"); + StartNetworkServer(port); + + /* wait for server to start up and try connecting several times */ + for (i=0; i<6; i++) + { + Delay(500); /* wait 500 ms == 0.5 seconds */ + close(sfd); + + sfd = socket(PF_INET, SOCK_STREAM, 0); + if (sfd < 0) + Error(ERR_EXIT, "out of file descriptors"); + + setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int)); + + if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0) /* connected */ + return TRUE; + } + + /* when reaching this point, connect to newly started server has failed */ + return FALSE; +} + +void SendToServer_PlayerName(char *player_name) +{ + int len_player_name = strlen(player_name); + + buffer[1] = OP_PLAYER_NAME; + memcpy(&buffer[2], player_name, len_player_name); + SendBufferToServer(2 + len_player_name); + Error(ERR_NETWORK_CLIENT, "you set your player name to \"%s\"", player_name); +} + +void SendToServer_ProtocolVersion() +{ + buffer[1] = OP_PROTOCOL_VERSION; + buffer[2] = PROTOCOL_VERSION_1; + buffer[3] = PROTOCOL_VERSION_2; + buffer[4] = PROTOCOL_VERSION_3; + + SendBufferToServer(5); +} + +void SendToServer_NrWanted(int nr_wanted) +{ + buffer[1] = OP_NUMBER_WANTED; + buffer[2] = nr_wanted; + + SendBufferToServer(3); +} + +void SendToServer_StartPlaying() +{ + unsigned long new_random_seed = InitRND(NEW_RANDOMIZE); + + buffer[1] = OP_START_PLAYING; + buffer[2] = (byte)(level_nr >> 8); + buffer[3] = (byte)(level_nr & 0xff); + buffer[4] = (byte)(leveldir_nr >> 8); + buffer[5] = (byte)(leveldir_nr & 0xff); + + buffer[6] = (unsigned char)((new_random_seed >> 24) & 0xff); + buffer[7] = (unsigned char)((new_random_seed >> 16) & 0xff); + buffer[8] = (unsigned char)((new_random_seed >> 8) & 0xff); + buffer[9] = (unsigned char)((new_random_seed >> 0) & 0xff); + + strcpy((char *)&buffer[10], leveldir[leveldir_nr].name); + + SendBufferToServer(10 + strlen(leveldir[leveldir_nr].name)+1); +} + +void SendToServer_PausePlaying() +{ + buffer[1] = OP_PAUSE_PLAYING; + + SendBufferToServer(2); +} + +void SendToServer_ContinuePlaying() +{ + buffer[1] = OP_CONTINUE_PLAYING; + + SendBufferToServer(2); +} + +void SendToServer_StopPlaying() +{ + buffer[1] = OP_STOP_PLAYING; + + SendBufferToServer(2); +} + +void SendToServer_MovePlayer(byte player_action) +{ + buffer[1] = OP_MOVE_FIGURE; + buffer[2] = player_action; + + SendBufferToServer(3); +} + +static void Handle_OP_BAD_PROTOCOL_VERSION() +{ + Error(ERR_WARN, "protocol version mismatch"); + Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d", + buffer[2], buffer[3], + PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3); +} + +static void Handle_OP_YOUR_NUMBER() +{ + int new_client_nr = buffer[2]; + int new_index_nr = new_client_nr - 1; + struct PlayerInfo *old_local_player = local_player; + struct PlayerInfo *new_local_player = &stored_player[new_index_nr]; + + printf("OP_YOUR_NUMBER: %d\n", buffer[0]); + first_player.nr = new_client_nr; + + if (old_local_player != new_local_player) + { + /* copy existing player settings and change to new player */ + + *new_local_player = *old_local_player; + old_local_player->connected = FALSE; + local_player = new_local_player; + } + + if (first_player.nr > MAX_PLAYERS) + Error(ERR_EXIT, "sorry - no more than %d players", MAX_PLAYERS); + + Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr); +} + +static void Handle_OP_NUMBER_WANTED() +{ + int client_nr_wanted = buffer[2]; + int old_client_nr = buffer[0]; + int new_client_nr = buffer[3]; + int old_index_nr = old_client_nr - 1; + int new_index_nr = new_client_nr - 1; + int index_nr_wanted = client_nr_wanted - 1; + struct PlayerInfo *old_player = &stored_player[old_index_nr]; + struct PlayerInfo *new_player = &stored_player[new_index_nr]; + + printf("OP_NUMBER_WANTED: %d\n", buffer[0]); + + if (new_client_nr == client_nr_wanted) /* switching succeeded */ + { + struct NetworkClientPlayerInfo *player; + + if (old_client_nr != client_nr_wanted) /* client's nr has changed */ + Error(ERR_NETWORK_CLIENT, "client %d switches to # %d", + old_client_nr, new_client_nr); + else if (old_client_nr == first_player.nr) /* local player keeps his nr */ + Error(ERR_NETWORK_CLIENT, "keeping client # %d", new_client_nr); + + if (old_client_nr != new_client_nr) + { + /* copy existing player settings and change to new player */ + + *new_player = *old_player; + old_player->connected = FALSE; + } + + player = getNetworkPlayer(old_client_nr); + player->nr = new_client_nr; + + if (old_player == local_player) /* local player switched */ + local_player = new_player; + } + else if (old_client_nr == first_player.nr) /* failed -- local player? */ + { + char *color[] = { "yellow", "red", "green", "blue" }; + char request[100]; + + sprintf(request, "Sorry ! %s player still exists ! You are %s player !", + color[index_nr_wanted], color[new_index_nr]); + Request(request, REQ_CONFIRM); + + Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d", + new_client_nr); + } +} + +static void Handle_OP_PLAYER_NAME(unsigned int len) +{ + struct NetworkClientPlayerInfo *player; + int player_nr = (int)buffer[0]; + + printf("OP_PLAYER_NAME: %d\n", player_nr); + player = getNetworkPlayer(player_nr); + buffer[len] = 0; + Error(ERR_NETWORK_CLIENT, "client %d calls itself \"%s\"", + buffer[0], &buffer[2]); + strncpy(player->name, (char *)&buffer[2], MAX_PLAYER_NAME_LEN); +} + +static void Handle_OP_PLAYER_CONNECTED() +{ + struct NetworkClientPlayerInfo *player, *last_player = NULL; + int new_client_nr = (int)buffer[0]; + int new_index_nr = new_client_nr - 1; + + printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr); + Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr); + + for (player=&first_player; player; player=player->next) + { + if (player->nr == new_client_nr) + Error(ERR_EXIT, "multiplayer server sent duplicate player id"); + + last_player = player; + } + + last_player->next = player = + checked_malloc(sizeof(struct NetworkClientPlayerInfo)); + player->nr = new_client_nr; + player->name[0] = '\0'; + player->next = NULL; + + stored_player[new_index_nr].connected = TRUE; +} + +static void Handle_OP_PLAYER_DISCONNECTED() +{ + struct NetworkClientPlayerInfo *player, *player_disconnected; + int player_nr = (int)buffer[0]; + + printf("OP_PLAYER_DISCONNECTED: %d\n", player_nr); + player_disconnected = getNetworkPlayer(player_nr); + Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected", + player_nr, getNetworkPlayerName(buffer[0])); + + for (player=&first_player; player; player=player->next) + if (player->next == player_disconnected) + player->next = player_disconnected->next; + free(player_disconnected); +} + +static void Handle_OP_START_PLAYING() +{ + int new_level_nr, new_leveldir_nr; + unsigned long new_random_seed; + char *new_leveldir_name; + + new_level_nr = (buffer[2] << 8) + buffer[3]; + new_leveldir_nr = (buffer[4] << 8) + buffer[5]; + new_random_seed = + (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]); + new_leveldir_name = (char *)&buffer[10]; + + printf("OP_START_PLAYING: %d\n", buffer[0]); + Error(ERR_NETWORK_CLIENT, + "client %d starts game [level %d from levedir %d (%s)]\n", + buffer[0], new_level_nr, new_leveldir_nr, new_leveldir_name); + + if (strcmp(leveldir[new_leveldir_nr].name, new_leveldir_name) != 0) + Error(ERR_WARN, "no such level directory: '%s'",new_leveldir_name); + + leveldir_nr = new_leveldir_nr; + level_nr = new_level_nr; + + TapeErase(); + LoadTape(level_nr); + LoadLevel(level_nr); + + if (setup.autorecord) + TapeStartRecording(); + + if (tape.recording) + tape.random_seed = new_random_seed; + + InitRND(new_random_seed); + + game_status = PLAYING; + InitGame(); +} + +static void Handle_OP_PAUSE_PLAYING() +{ + printf("OP_PAUSE_PLAYING: %d\n", buffer[0]); + Error(ERR_NETWORK_CLIENT, "client %d pauses game", buffer[0]); + + tape.pausing = TRUE; + DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0); +} + +static void Handle_OP_CONTINUE_PLAYING() +{ + printf("OP_CONTINUE_PLAYING: %d\n", buffer[0]); + Error(ERR_NETWORK_CLIENT, "client %d continues game", buffer[0]); + + tape.pausing = FALSE; + DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); +} + +static void Handle_OP_STOP_PLAYING() +{ + printf("OP_STOP_PLAYING: %d\n", buffer[0]); + Error(ERR_NETWORK_CLIENT, "client %d stops game", buffer[0]); + + game_status = MAINMENU; + DrawMainMenu(); +} + +static void Handle_OP_MOVE_FIGURE(unsigned int len) +{ + int server_frame_counter; + int i; + + if (!network_playing) + return; + + server_frame_counter = + (buffer[2] << 24) | (buffer[3] << 16) | (buffer[4] << 8) | (buffer[5]); + + if (server_frame_counter != FrameCounter) + { + Error(ERR_RETURN, "client and servers frame counters out of sync"); + Error(ERR_RETURN, "frame counter of client is %d", FrameCounter); + Error(ERR_RETURN, "frame counter of server is %d", server_frame_counter); + Error(ERR_EXIT, "this should not happen -- please debug"); + } + + /* copy valid player actions */ + for (i=0; i= 4 && nread >= 4 + readbuffer[3]) + { + message_length = readbuffer[3]; + if (readbuffer[0] || readbuffer[1] || readbuffer[2]) + Error(ERR_EXIT, "wrong network server line length"); + + memcpy(buffer, &readbuffer[4], message_length); + nread -= 4 + message_length; + memmove(readbuffer, readbuffer + 4 + message_length, nread); + + switch(buffer[1]) + { + case OP_BAD_PROTOCOL_VERSION: + Handle_OP_BAD_PROTOCOL_VERSION(); + break; + + case OP_YOUR_NUMBER: + Handle_OP_YOUR_NUMBER(); + break; + + case OP_NUMBER_WANTED: + Handle_OP_NUMBER_WANTED(); + break; + + case OP_PLAYER_NAME: + Handle_OP_PLAYER_NAME(message_length); + break; + + case OP_PLAYER_CONNECTED: + Handle_OP_PLAYER_CONNECTED(); + break; + + case OP_PLAYER_DISCONNECTED: + Handle_OP_PLAYER_DISCONNECTED(); + break; + + case OP_START_PLAYING: + Handle_OP_START_PLAYING(); + break; + + case OP_PAUSE_PLAYING: + Handle_OP_PAUSE_PLAYING(); + break; + + case OP_CONTINUE_PLAYING: + Handle_OP_CONTINUE_PLAYING(); + break; + + case OP_STOP_PLAYING: + Handle_OP_STOP_PLAYING(); + break; + + case OP_MOVE_FIGURE: + Handle_OP_MOVE_FIGURE(message_length); + break; + + case OP_BROADCAST_MESSAGE: + printf("OP_BROADCAST_MESSAGE: %d\n", buffer[0]); + Error(ERR_NETWORK_CLIENT, "client %d sends message", buffer[0]); + break; + } + } + + fflush(stdout); +} + +void HandleNetworking() +{ + static struct timeval tv = { 0, 0 }; + fd_set rfds; + int r = 0; + + FD_ZERO(&rfds); + FD_SET(sfd, &rfds); + + r = select(sfd + 1, &rfds, NULL, NULL, &tv); + + if (r < 0 && errno != EINTR) + Error(ERR_EXIT, "HandleNetworking(): select() failed"); + + if (r < 0) + FD_ZERO(&rfds); + + if (FD_ISSET(sfd, &rfds)) + { + int r; + + r = read(sfd, readbuffer + nread, MAX_BUFFER_SIZE - nread); + + if (r < 0) + Error(ERR_EXIT, "error reading from network server"); + + if (r == 0) + Error(ERR_EXIT, "connection to network server lost"); + + nread += r; + + HandleNetworkingMessages(); + } +} + +#endif /* !MSDOS */ diff --git a/src/network.h b/src/network.h new file mode 100644 index 00000000..162f0f7d --- /dev/null +++ b/src/network.h @@ -0,0 +1,30 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* network.h * +***********************************************************/ + +#ifndef NETWORK_H +#define NETWORK_H + +#include "main.h" + +boolean ConnectToServer(char *, int); +void SendToServer_PlayerName(char *); +void SendToServer_ProtocolVersion(void); +void SendToServer_NrWanted(int); +void SendToServer_StartPlaying(void); +void SendToServer_PausePlaying(void); +void SendToServer_ContinuePlaying(void); +void SendToServer_StopPlaying(void); +void SendToServer_MovePlayer(byte); +void HandleNetworking(void); + +#endif diff --git a/src/pcx.c b/src/pcx.c new file mode 100644 index 00000000..514d30de --- /dev/null +++ b/src/pcx.c @@ -0,0 +1,228 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* pcx.c * +***********************************************************/ + +#include "pcx.h" +#include "image.h" +#include "misc.h" + +#define PCX_MAGIC 0x0a /* first byte in a PCX image file */ +#define PCX_LAST_VERSION 5 /* last acceptable version number */ +#define PCX_ENCODING 1 /* PCX encoding method */ +#define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */ +#define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */ +#define PCX_MAXCOLORS 256 /* maximum number of colors */ + +#define PCX_HEADER_SIZE 128 +#define PCX_COLORMAP_SIZE (3 * PCX_MAXCOLORS) + +struct PCX_Header +{ + unsigned char signature; /* PCX file identifier */ + unsigned char version; /* version compatibility level */ + unsigned char encoding; /* encoding method */ + unsigned char bits_per_pixel; /* bits per pixel, or depth */ + unsigned short xmin; /* X position of left edge */ + unsigned short ymin; /* Y position of top edge */ + unsigned short xmax; /* X position of right edge */ + unsigned short ymax; /* Y position of bottom edge */ + unsigned short hres; /* X screen resolution of source image */ + unsigned short vres; /* Y screen resolution of source image */ + unsigned char palette[16][3]; /* PCX color map */ + unsigned char reserved; /* should be 0, 1 if std res fax */ + unsigned char color_planes; /* bit planes in image */ + unsigned short bytes_per_line;/* byte delta between scanlines */ + unsigned short palette_type; /* 0 = undef, 1 = color, 2 = grayscale */ + unsigned char filler[58]; /* fill to struct size of 128 */ +}; + +static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) +{ + /* Run Length Encoding: If the two high bits are set, + * then the low 6 bits contain a repeat count, and the byte to + * repeat is the next byte in the file. If the two high bits are + * not set, then this is the byte to write. + */ + + unsigned int bytes_per_pixel = (image->depth + 7) / 8; + register byte *bitmap_ptr, *bitmap_last; + register byte value, count; + + bitmap_ptr = image->data; + bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel); + + while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last) + { + value = *buffer_ptr++; + + if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ + { + count = value & 0x3f; /* extract repeat count from byte */ + value = *buffer_ptr++; /* next byte is value to repeat */ + + for (; count && bitmap_ptr < bitmap_last; count--) + *bitmap_ptr++ = value; + + if (count) /* repeat count spans end of bitmap */ + return NULL; + } + else + *bitmap_ptr++ = value; + + image->rgb.color_used[value] = TRUE; + } + + /* check if end of buffer was reached before end of bitmap */ + if (bitmap_ptr < bitmap_last) + return NULL; + + /* return current buffer position for next decoding function */ + return buffer_ptr; +} + +static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) +{ + int i, magic; + + /* read colormap magic byte */ + magic = *buffer_ptr++; + + /* check magic colormap header byte */ + if (magic != PCX_256COLORS_MAGIC) + return NULL; + + /* check if enough bytes left for a complete colormap */ + if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last) + return NULL; + + /* read 256 colors from PCX colormap */ + for (i=0; irgb.red[i] = *buffer_ptr++ << 8; + image->rgb.green[i] = *buffer_ptr++ << 8; + image->rgb.blue[i] = *buffer_ptr++ << 8; + } + + /* return current buffer position for next decoding function */ + return buffer_ptr; +} + +Image *Read_PCX_to_Image(char *filename) +{ + FILE *file; + byte *file_buffer; + byte *buffer_ptr, *buffer_last; + unsigned int file_length; + struct PCX_Header pcx; + Image *image; + int width, height, depth; + int i; + + if (!(file = fopen(filename, "r"))) + return NULL; + + if (fseek(file, 0, SEEK_END) == -1) + { + fclose(file); + return NULL; + } + + file_length = ftell(file); + rewind(file); + + if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE) + { + fclose(file); + return NULL; + } + + file_buffer = checked_malloc(file_length); + + if (fread(file_buffer, 1, file_length, file) != file_length) + { + fclose(file); + return NULL; + } + + fclose(file); + + pcx.signature = file_buffer[0]; + pcx.version = file_buffer[1]; + pcx.encoding = file_buffer[2]; + pcx.bits_per_pixel = file_buffer[3]; + pcx.xmin = file_buffer[4] + 256 * file_buffer[5]; + pcx.ymin = file_buffer[6] + 256 * file_buffer[7]; + pcx.xmax = file_buffer[8] + 256 * file_buffer[9]; + pcx.ymax = file_buffer[10] + 256 * file_buffer[11]; + pcx.color_planes = file_buffer[65]; + pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67]; + pcx.palette_type = file_buffer[68] + 256 * file_buffer[69]; + + width = pcx.xmax - pcx.xmin + 1; + height = pcx.ymax - pcx.ymin + 1; + depth = pcx.bits_per_pixel; + + if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION || + pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH || + width < 0 || height < 0) + { + free(file_buffer); + return NULL; + } + + if (options.verbose) + { + printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n", + filename, pcx.xmax, pcx.ymax, + pcx.color_planes); + printf("depth: %d\n", pcx.bits_per_pixel); + printf("bytes_per_line: %d\n", pcx.bytes_per_line); + printf("palette type: %s\n", + (pcx.palette_type == 1 ? "color" : + pcx.palette_type == 2 ? "grayscale" : "undefined")); + } + + /* allocate new image structure */ + image = newImage(width, height, depth); + + buffer_ptr = file_buffer + PCX_HEADER_SIZE; + buffer_last = file_buffer + file_length; + + /* read compressed bitmap data */ + if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL) + { + free(file_buffer); + freeImage(image); + return NULL; + } + + /* read colormap data */ + if (!PCX_ReadColormap(image, buffer_ptr, buffer_last)) + { + free(file_buffer); + freeImage(image); + return NULL; + } + + free(file_buffer); + + /* determine number of used colormap entries */ + image->rgb.used = 0; + for (i=0; irgb.color_used[i]) + image->rgb.used++; + + if (options.verbose) + printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used); + + return image; +} diff --git a/src/pcx.h b/src/pcx.h new file mode 100644 index 00000000..b1fa1c63 --- /dev/null +++ b/src/pcx.h @@ -0,0 +1,29 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* pcx.h * +***********************************************************/ + +#ifndef PCX_H +#define PCX_H + +#include "main.h" +#include "image.h" + +#define PCX_Success 0 +#define PCX_OpenFailed -1 +#define PCX_ReadFailed -2 +#define PCX_FileInvalid -3 +#define PCX_NoMemory -4 +#define PCX_ColorFailed -5 + +Image *Read_PCX_to_Image(char *); + +#endif /* PCX_H */ diff --git a/src/random.c b/src/random.c new file mode 100644 index 00000000..864f3dcc --- /dev/null +++ b/src/random.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + */ + +#include +#include +#include + +#include "random.h" + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initiallized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroeth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroeth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least thi + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroeth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static long int randtbl[DEG_3 + 1] = +{ + TYPE_3, + -851904987, -43806228, -2029755270, 1390239686, -1912102820, + -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, + -1714531963, 1800685987, -2015299881, 654595283, -1149023258, + -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, + -607508183, -205999574, -1696891592, 1492211999, -1528267240, + -952028296, -189082757, 362343714, 1424981831, 2039449641, +}; + +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + +static long int *fptr = &randtbl[SEP_3 + 1]; +static long int *rptr = &randtbl[1]; + + + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroeth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + +static long int *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ + +void srandom_linux_libc(unsigned int x) +{ + state[0] = x; + if (rand_type != TYPE_0) + { + register long int i; + for (i = 1; i < rand_deg; ++i) + state[i] = (1103515145 * state[i - 1]) + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; ++i) + (void) random_linux_libc(); + } +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all ther other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int random_linux_libc() +{ + if (rand_type == TYPE_0) + { + state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; + return state[0]; + } + else + { + long int i; + *fptr += *rptr; + /* Chucking least random bit. */ + i = (*fptr >> 1) & LONG_MAX; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + return i; + } +} diff --git a/src/random.h b/src/random.h new file mode 100644 index 00000000..366d1ff5 --- /dev/null +++ b/src/random.h @@ -0,0 +1,20 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* random.h * +***********************************************************/ + +#ifndef RANDOM_H +#define RANDOM_H + +void srandom_linux_libc(unsigned int); +long int random_linux_libc(void); + +#endif diff --git a/src/screens.c b/src/screens.c index 5246fa82..c0a3b8c6 100644 --- a/src/screens.c +++ b/src/screens.c @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * screens.c * ***********************************************************/ @@ -21,55 +20,95 @@ #include "misc.h" #include "files.h" #include "buttons.h" +#include "tape.h" +#include "joystick.h" +#include "cartoons.h" +#include "network.h" +#include "init.h" + +/* for DrawSetupScreen(), HandleSetupScreen() */ +#define SETUP_SCREEN_POS_START 2 +#define SETUP_SCREEN_POS_END 16 +#define SETUP_SCREEN_POS_EMPTY1 (SETUP_SCREEN_POS_END - 2) +#define SETUP_SCREEN_POS_EMPTY2 (SETUP_SCREEN_POS_END - 2) + +/* for HandleSetupInputScreen() */ +#define SETUPINPUT_SCREEN_POS_START 2 +#define SETUPINPUT_SCREEN_POS_END 15 +#define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3) +#define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1) + +/* for HandleChooseLevel() */ +#define MAX_LEVEL_SERIES_ON_SCREEN 15 + +#ifdef MSDOS +extern unsigned char get_ascii(KeySym); +#endif + +void DrawHeadline() +{ + int x = SX + (SXSIZE - strlen(GAMETITLE_STRING) * FONT1_XSIZE) / 2; + + DrawText(x, SY + 8, GAMETITLE_STRING, FS_BIG, FC_YELLOW); + DrawTextFCentered(46, FC_RED, COPYRIGHT_STRING); +} void DrawMainMenu() { int i; + char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:"); FadeSounds(); GetPlayerConfig(); LoadLevel(level_nr); ClearWindow(); - DrawText(SX+16, SY+8, "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW); - DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel", - FS_SMALL,FC_RED); - DrawText(SX+32, SY+64, "Name:",FS_BIG,FC_GREEN); - DrawText(SX+192,SY+64, player.alias_name,FS_BIG,FC_RED); - DrawText(SX+32, SY+96, "Level:",FS_BIG,FC_GREEN); - DrawText(SX+352,SY+96, int2str(level_nr,3),FS_BIG, - (level_nr10) + else if (y > 10) y = 10; } @@ -112,114 +154,122 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) y = choice; } - if (y==4 && ((x==11 && level_nr>0) || - (x==15 && level_nr 0) || + (x == 15 && level_nr < leveldir[leveldir_nr].levels - 1)) && button) { - static long level_delay = 0; - int step = (button==1 ? 1 : button==2 ? 5 : 10); - - if (!DelayReached(&level_delay,20)) + static unsigned long level_delay = 0; + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int new_level_nr, old_level_nr = level_nr; + int font_color = (leveldir[leveldir_nr].readonly ? FC_RED : FC_YELLOW); + + new_level_nr = level_nr + (x == 11 ? -step : +step); + if (new_level_nr < 0) + new_level_nr = 0; + if (new_level_nr > leveldir[leveldir_nr].levels - 1) + new_level_nr = leveldir[leveldir_nr].levels - 1; + + if (old_level_nr == new_level_nr || !DelayReached(&level_delay, 150)) goto out; - level_nr += (x==11 ? -step : +step); - if (level_nr<0) - level_nr = 0; - if (level_nr>LEVELDIR_SIZE(leveldir[leveldir_nr])-1) - level_nr = LEVELDIR_SIZE(leveldir[leveldir_nr])-1; - - if (level_nr>player.handicap && level_nr=3 && y<=10) + else if (x == 1 && y >= 3 && y <= 10) { if (button) { - if (y!=choice) + if (y != choice) { - DrawGraphic(0,y-1,GFX_KUGEL_ROT); - DrawGraphic(0,choice-1,GFX_KUGEL_BLAU); + DrawGraphic(0, y-1, GFX_KUGEL_ROT); + DrawGraphic(0, choice - 1, GFX_KUGEL_BLAU); + choice = y; } - choice = y; } else { - if (y==3) + if (y == 3) { game_status = TYPENAME; - HandleTypeName(strlen(player.alias_name),0); + HandleTypeName(strlen(setup.player_name), 0); } - else if (y==4) + else if (y == 4) { if (num_leveldirs) { game_status = CHOOSELEVEL; + SaveLevelSetup(); DrawChooseLevel(); - redraw = TRUE; } } - else if (y==5) + else if (y == 5) { game_status = HALLOFFAME; DrawHallOfFame(-1); - redraw = TRUE; } - else if (y==6) + else if (y == 6) { + if (leveldir[leveldir_nr].readonly) + Request("This level is read only !", REQ_CONFIRM); game_status = LEVELED; DrawLevelEd(); - redraw = TRUE; } - else if (y==7) + else if (y == 7) { game_status = HELPSCREEN; DrawHelpScreen(); - redraw = TRUE; } - else if (y==8) + else if (y == 8) { - if (autorecord_on && !tape.playing) - TapeInitRecording(); + if (setup.autorecord) + TapeStartRecording(); - game_status = PLAYING; - InitGame(); - redraw = TRUE; +#ifndef MSDOS + if (options.network) + SendToServer_StartPlaying(); + else +#endif + { + game_status = PLAYING; + InitGame(); + } } - else if (y==9) + else if (y == 9) { game_status = SETUP; DrawSetupScreen(); - redraw = TRUE; } - else if (y==10) + else if (y == 10) { - if (AreYouSure("Do you really want to quit ?",AYS_ASK|AYS_STAY_CLOSED)) + SaveLevelSetup(); + if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED)) game_status = EXITGAME; } + + redraw = TRUE; } } BackToFront(); out: - if (game_status==MAINMENU) + if (game_status == MAINMENU) DoAnimation(); } @@ -233,25 +283,49 @@ static int helpscreen_frame[MAX_HELPSCREEN_ELS]; static int helpscreen_delay[MAX_HELPSCREEN_ELS]; static int helpscreen_action[] = { + GFX_SPIELER1_DOWN,4,2, + GFX_SPIELER1_UP,4,2, + GFX_SPIELER1_LEFT,4,2, + GFX_SPIELER1_RIGHT,4,2, + GFX_SPIELER1_PUSH_LEFT,4,2, + GFX_SPIELER1_PUSH_RIGHT,4,2, HA_NEXT, GFX_ERDREICH,1,100, HA_NEXT, GFX_LEERRAUM,1,100, HA_NEXT, GFX_MORAST_LEER,1,100, HA_NEXT, GFX_BETON,1,100, HA_NEXT, GFX_MAUERWERK,1,100, HA_NEXT, + GFX_MAUER_R1,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10, + GFX_MAUER_L1,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10, HA_NEXT, + GFX_UNSICHTBAR,1,100, HA_NEXT, GFX_FELSBODEN,1,100, HA_NEXT, + GFX_CHAR_A,30,4, GFX_CHAR_AUSRUF,32,4, HA_NEXT, GFX_EDELSTEIN,2,5, HA_NEXT, GFX_DIAMANT,2,5, HA_NEXT, + GFX_EDELSTEIN_BD,2,5, HA_NEXT, + GFX_EDELSTEIN_GELB,2,5, GFX_EDELSTEIN_ROT,2,5, + GFX_EDELSTEIN_LILA,2,5, HA_NEXT, GFX_FELSBROCKEN,4,5, HA_NEXT, GFX_BOMBE,1,50, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10, HA_NEXT, GFX_KOKOSNUSS,1,50, GFX_CRACKINGNUT,3,1, GFX_EDELSTEIN,1,10, HA_NEXT, GFX_ERZ_EDEL,1,50, GFX_EXPLOSION,8,1, GFX_EDELSTEIN,1,10, HA_NEXT, GFX_ERZ_DIAM,1,50, GFX_EXPLOSION,8,1, GFX_DIAMANT,1,10, HA_NEXT, + GFX_ERZ_EDEL_BD,1,50, GFX_EXPLOSION,8,1,GFX_EDELSTEIN_BD,1,10,HA_NEXT, + GFX_ERZ_EDEL_GELB,1,50, GFX_EXPLOSION,8,1, + GFX_EDELSTEIN_GELB,1,10, GFX_ERZ_EDEL_ROT,1,50, + GFX_EXPLOSION,8,1, GFX_EDELSTEIN_ROT,1,10, + GFX_ERZ_EDEL_LILA,1,50, GFX_EXPLOSION,8,1, + GFX_EDELSTEIN_LILA,1,10, HA_NEXT, GFX_GEBLUBBER,4,4, HA_NEXT, - GFX_SCHLUESSEL1,4,33, HA_NEXT, - GFX_PFORTE1,4,33, HA_NEXT, - GFX_PFORTE1X,4,33, HA_NEXT, + GFX_SCHLUESSEL1,4,25, HA_NEXT, + GFX_PFORTE1,4,25, HA_NEXT, + GFX_PFORTE1X,4,25, HA_NEXT, GFX_DYNAMIT_AUS,1,100, HA_NEXT, GFX_DYNAMIT,7,6, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10, HA_NEXT, + GFX_DYNABOMB+0,4,3, GFX_DYNABOMB+3,1,3, GFX_DYNABOMB+2,1,3, + GFX_DYNABOMB+1,1,3, GFX_DYNABOMB+0,1,3, GFX_EXPLOSION,8,1, + GFX_LEERRAUM,1,10, HA_NEXT, + GFX_DYNABOMB_NR,1,100, HA_NEXT, + GFX_DYNABOMB_SZ,1,100, HA_NEXT, GFX_FLIEGER+4,1,3, GFX_FLIEGER+0,1,3, GFX_FLIEGER+4,1,3, GFX_FLIEGER+5,1,3, GFX_FLIEGER+1,1,3, GFX_FLIEGER+5,1,3, GFX_FLIEGER+6,1,3, GFX_FLIEGER+2,1,3, GFX_FLIEGER+6,1,3, @@ -260,69 +334,133 @@ static int helpscreen_action[] = GFX_KAEFER+5,1,1, GFX_KAEFER+1,1,1, GFX_KAEFER+5,1,1, GFX_KAEFER+6,1,1, GFX_KAEFER+2,1,1, GFX_KAEFER+6,1,1, GFX_KAEFER+7,1,1, GFX_KAEFER+3,1,1, GFX_KAEFER+7,1,1, HA_NEXT, + GFX_BUTTERFLY,2,2, HA_NEXT, + GFX_FIREFLY,2,2, HA_NEXT, GFX_PACMAN+0,1,3, GFX_PACMAN+4,1,2, GFX_PACMAN+0,1,3, GFX_PACMAN+1,1,3, GFX_PACMAN+5,1,2, GFX_PACMAN+1,1,3, GFX_PACMAN+2,1,3, GFX_PACMAN+6,1,2, GFX_PACMAN+2,1,3, GFX_PACMAN+3,1,3, GFX_PACMAN+7,1,2, GFX_PACMAN+3,1,3, HA_NEXT, - GFX_MAMPFER+0,4,0, GFX_MAMPFER+3,1,0, GFX_MAMPFER+2,1,0, - GFX_MAMPFER+1,1,0, HA_NEXT, - GFX_ZOMBIE+0,4,0, GFX_ZOMBIE+3,1,0, GFX_ZOMBIE+2,1,0, - GFX_ZOMBIE+1,1,0, HA_NEXT, + GFX_MAMPFER+0,4,1, GFX_MAMPFER+3,1,1, GFX_MAMPFER+2,1,1, + GFX_MAMPFER+1,1,1, GFX_MAMPFER+0,1,1, HA_NEXT, + GFX_MAMPFER2+0,4,1, GFX_MAMPFER2+3,1,1, GFX_MAMPFER2+2,1,1, + GFX_MAMPFER2+1,1,1, GFX_MAMPFER2+0,1,1, HA_NEXT, + GFX_ROBOT+0,4,1, GFX_ROBOT+3,1,1, GFX_ROBOT+2,1,1, + GFX_ROBOT+1,1,1, GFX_ROBOT+0,1,1, HA_NEXT, + GFX_MAULWURF_DOWN,4,2, + GFX_MAULWURF_UP,4,2, + GFX_MAULWURF_LEFT,4,2, + GFX_MAULWURF_RIGHT,4,2, HA_NEXT, + GFX_PINGUIN_DOWN,4,2, + GFX_PINGUIN_UP,4,2, + GFX_PINGUIN_LEFT,4,2, + GFX_PINGUIN_RIGHT,4,2, HA_NEXT, + GFX_SCHWEIN_DOWN,4,2, + GFX_SCHWEIN_UP,4,2, + GFX_SCHWEIN_LEFT,4,2, + GFX_SCHWEIN_RIGHT,4,2, HA_NEXT, + GFX_DRACHE_DOWN,4,2, + GFX_DRACHE_UP,4,2, + GFX_DRACHE_LEFT,4,2, + GFX_DRACHE_RIGHT,4,2, HA_NEXT, + GFX_SONDE_START,8,1, HA_NEXT, GFX_ABLENK,4,1, HA_NEXT, - GFX_AMOEBE_LEBT,4,40, HA_NEXT, + GFX_BIRNE_AUS,1,25, GFX_BIRNE_EIN,1,25, HA_NEXT, + GFX_ZEIT_VOLL,1,25, GFX_ZEIT_LEER,1,25, HA_NEXT, + GFX_TROPFEN,1,25, GFX_AMOEBING,4,1, GFX_AMOEBE_LEBT,1,10, HA_NEXT, GFX_AMOEBE_TOT+2,2,50, GFX_AMOEBE_TOT,2,50, HA_NEXT, + GFX_AMOEBE_LEBT,4,40, HA_NEXT, + GFX_AMOEBE_LEBT,1,10, GFX_AMOEBING,4,2, HA_NEXT, + GFX_AMOEBE_LEBT,1,25, GFX_AMOEBE_TOT,1,25, GFX_EXPLOSION,8,1, + GFX_DIAMANT,1,10, HA_NEXT, + GFX_LIFE,1,100, HA_NEXT, + GFX_LIFE_ASYNC,1,100, HA_NEXT, GFX_SIEB_LEER,4,2, HA_NEXT, + GFX_SIEB2_LEER,4,2, HA_NEXT, + GFX_AUSGANG_ZU,1,100, GFX_AUSGANG_ACT,4,2, + GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2, + GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2, HA_NEXT, + GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2, + GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2, HA_NEXT, HA_END }; static char *helpscreen_eltext[][2] = { - "Normal sand:", "You can dig through it", - "Empty field:", "You can walk through it", - "Quicksand: You cannot pass it,", "but rocks can fall though it", - "Massive Wall:", "Nothing can go through it", - "Normal Wall: You can't go through", "it, but you can bomb it away", - "Old Wall: Like normal wall, but", "some things can fall down from it", - "Emerald: You must collect enough of", "them to finish a level", - "Diamond: Counts as 3 emeralds;", "Can be destroyed by rocks", - "Rock: Smashes several things;", "Can be moved by the player", - "Bomb: You can move it, but be", "careful when dropping it", - "Nut: Throw a rock on it to open it;", "Each nut contains an emerald", - "Wall with an Emerald inside:", "Bomb the wall away to get it", - "Wall with a Diamond inside:", "Bomb the wall away to get it", - "Acid: Destroys everything that", "falls or walks into it", - "Key: Opens the door that has the", "same color (red/yellow/green/blue)", - "Door: Can be opened by the key", "with the same color", - "Door: You have to find out the", "right color of the key for it", - "Dynamite: Collect it and use it to", "destroy walls or kill enemies", - "Dynamite: This one explodes after", "a few seconds", - "Spaceship: Moves at the left side", "of walls; don't touch it!", - "Bug: Moves at the right side of", "walls; don't touch it!", - "Pacman: Eats the amoeba and you,", "if you're not careful", - "Cruncher: Eats diamonds and you,", "if you're not careful", - "Robot: Tries to kill the player", "", - "Magic Wheel: Touch it to get rid of", "the robots for some seconds", - "Living Amoeba: Grows through empty", "fields, sand and quicksand", - "Dead Amoeba: Does not grow, but", "can still kill bugs and spaceships", - "Magic Wall: Changes rocks, emeralds", "and diamonds when they pass it", + {"THE HERO:", "(Is _this_ guy good old Rockford?)"}, + {"Normal sand:", "You can dig through it"}, + {"Empty field:", "You can walk through it"}, + {"Quicksand: You cannot pass it,", "but rocks can fall though it"}, + {"Massive Wall:", "Nothing can go through it"}, + {"Normal Wall: You can't go through", "it, but you can bomb it away"}, + {"Growing Wall: Grows to the left or", "right if there is an empty field"}, + {"Invisible Wall: Behaves like normal","wall, but is invisible"}, + {"Old Wall: Like normal wall, but", "some things can fall down from it"}, + {"Letter Wall: Looks like a letter,", "behaves like a normal wall"}, + {"Emerald: You must collect enough of","them to finish a level"}, + {"Diamond: Counts as 3 emeralds, but", "can be destroyed by rocks"}, + {"Diamond (BD style): Counts like one","emerald and behaves a bit different"}, + {"Colorful Gems:", "Seem to behave like Emeralds"}, + {"Rock: Smashes several things;", "Can be moved by the player"}, + {"Bomb: You can move it, but be", "careful when dropping it"}, + {"Nut: Throw a rock on it to open it;","Each nut contains an emerald"}, + {"Wall with an emerald inside:", "Bomb the wall away to get it"}, + {"Wall with a diamond inside:", "Bomb the wall away to get it"}, + {"Wall with BD style diamond inside:", "Bomb the wall away to get it"}, + {"Wall with colorful gem inside:", "Bomb the wall away to get it"}, + {"Acid: Things that fall in are gone", "forever (including our hero)"}, + {"Key: Opens the door that has the", "same color (red/yellow/green/blue)"}, + {"Door: Can be opened by the key", "with the same color"}, + {"Door: You have to find out the", "right color of the key for it"}, + {"Dynamite: Collect it and use it to", "destroy walls or kill enemies"}, + {"Dynamite: This one explodes after", "a few seconds"}, + {"Dyna Bomb: Explodes in 4 directions","with variable explosion size"}, + {"Dyna Bomb: Increases the number of", "dyna bombs available at a time"}, + {"Dyna Bomb: Increases the size of", "explosion of dyna bombs"}, + {"Spaceship: Moves at the left side", "of walls; don't touch it!"}, + {"Bug: Moves at the right side", "of walls; don't touch it!"}, + {"Butterfly: Moves at the right side", "of walls; don't touch it!"}, + {"Firefly: Moves at the left side", "of walls; don't touch it!"}, + {"Pacman: Eats the amoeba and you,", "if you're not careful"}, + {"Cruncher: Eats diamonds and you,", "if you're not careful"}, + {"Cruncher (BD style):", "Eats almost everything"}, + {"Robot: Tries to kill the player", ""}, + {"The mole: You must guide him savely","to the exit; he will follow you"}, + {"The penguin: Guide him to the exit,","but keep him away from monsters!"}, + {"The Pig: Harmless, but eats all", "gems it can get"}, + {"The Dragon: Breathes fire,", "especially to some monsters"}, + {"Sonde: Follows you everywhere;", "harmless, but may block your way"}, + {"Magic Wheel: Touch it to get rid of","the robots for some seconds"}, + {"Light Bulb: All of them must be", "switched on to finish a level"}, + {"Extra Time Orb: Adds some seconds", "to the time available for the level"}, + {"Amoeba Drop: Grows to an amoeba on", "the ground - don't touch it"}, + {"Dead Amoeba: Does not grow, but", "can still kill bugs and spaceships"}, + {"Normal Amoeba: Grows through empty", "fields, sand and quicksand"}, + {"Dropping Amoeba: This one makes", "drops that grow to a new amoeba"}, + {"Living Amoeba (BD style): Contains", "other element, when surrounded"}, + {"Game Of Life: Behaves like the well","known 'Game Of Life' (2333 style)"}, + {"Biomaze: A bit like the 'Game Of", "Life', but builds crazy mazes"}, + {"Magic Wall: Changes rocks, emeralds","and diamonds when they pass it"}, + {"Magic Wall (BD style):", "Changes rocks and BD style diamonds"}, + {"Exit door: Opens if you have enough","emeralds to finish the level"}, + {"Open exit door: Enter here to leave","the level and exit the actual game"}, }; static int num_helpscreen_els = sizeof(helpscreen_eltext)/(2*sizeof(char *)); static char *helpscreen_music[][3] = { - "Alchemy", "Ian Boddy", "Drive", - "The Chase", "Propaganda", "A Secret Wish", - "Network 23", "Tangerine Dream", "Exit", - "Czardasz", "Robert Pieculewicz", "Czardasz", - "21st Century Common Man", "Tangerine Dream", "Tyger", - "Voyager", "The Alan Parsons Project","Pyramid", - "Twilight Painter", "Tangerine Dream", "Heartbreakers" + { "Alchemy", "Ian Boddy", "Drive" }, + { "The Chase", "Propaganda", "A Secret Wish" }, + { "Network 23", "Tangerine Dream", "Exit" }, + { "Czardasz", "Robert Pieculewicz", "Czardasz" }, + { "21st Century Common Man", "Tangerine Dream", "Tyger" }, + { "Voyager", "The Alan Parsons Project","Pyramid" }, + { "Twilight Painter", "Tangerine Dream", "Heartbreakers" } }; static int helpscreen_musicpos; void DrawHelpScreenElAction(int start) { int i = 0, j = 0; - int frame, delay, graphic; + int frame, graphic; int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4; while(helpscreen_action[j] != HA_END) @@ -355,8 +493,7 @@ void DrawHelpScreenElAction(int start) helpscreen_frame[i-start] = helpscreen_action[j++]-1; } - delay = helpscreen_action[j++]; - helpscreen_delay[i-start] = delay; + helpscreen_delay[i-start] = helpscreen_action[j++] - 1; if (helpscreen_action[j] == HA_NEXT) { @@ -372,82 +509,65 @@ void DrawHelpScreenElAction(int start) } j++; - DrawGraphicExtHiRes(drawto,gc,xstart,ystart+(i-start)*ystep, - graphic+frame); + DrawGraphicExt(drawto, gc, xstart, ystart+(i-start)*ystep, graphic+frame); i++; } - redraw_tiles += 28; for(i=2;i<16;i++) - redraw[0][i] = redraw[1][i] = TRUE; - redraw_mask |= REDRAW_TILES; + { + MarkTileDirty(0,i); + MarkTileDirty(1,i); + } } void DrawHelpScreenElText(int start) { int i; - int xstart = SX+56, ystart = SY+65+2*32, ystep = TILEY+4; - char text[FULL_SXSIZE/FONT2_XSIZE+10]; + int xstart = SX + 56, ystart = SY + 65 + 2 * 32, ystep = TILEY + 4; + int ybottom = SYSIZE - 20; ClearWindow(); - DrawText(SX+16, SY+8, "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW); - DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel", - FS_SMALL,FC_RED); + DrawHeadline(); - sprintf(text,"The game elements:"); - DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100, - text,FS_SMALL,FC_GREEN); + DrawTextFCentered(100, FC_GREEN, "The game elements:"); - for(i=start;i=XK_A && key<=XK_Z) || (key>=XK_a && key<=XK_z && - xpos= XK_A && key <= XK_Z) || (key >= XK_a && key <= XK_z)) && + xpos < MAX_NAMELEN - 1) { - if (key>=XK_A && key<=XK_Z) - ascii = 'A'+(char)(key-XK_A); - if (key>=XK_a && key<=XK_z) - ascii = 'a'+(char)(key-XK_a); - player.alias_name[xpos] = ascii; - player.alias_name[xpos+1] = 0; + char ascii; + + if (key >= XK_A && key <= XK_Z) + ascii = 'A' + (char)(key - XK_A); + else + ascii = 'a' + (char)(key - XK_a); + + setup.player_name[xpos] = ascii; + setup.player_name[xpos + 1] = 0; xpos++; - DrawTextExt(drawto,gc,SX+6*32,SY+ypos*32, - player.alias_name,FS_BIG,FC_YELLOW); - DrawTextExt(window,gc,SX+6*32,SY+ypos*32, - player.alias_name,FS_BIG,FC_YELLOW); - DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT); + DrawTextExt(drawto, gc, SX + 6*32, SY + ypos*32, + setup.player_name, FS_BIG, FC_YELLOW); + DrawTextExt(window, gc, SX + 6*32, SY + ypos*32, + setup.player_name, FS_BIG, FC_YELLOW); + DrawGraphic(xpos + 6, ypos, GFX_KUGEL_ROT); } - else if (key==XK_Delete && xpos>0) + else if ((key == XK_Delete || key == XK_BackSpace) && xpos > 0) { - player.alias_name[xpos] = 0; xpos--; - DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT); - DrawGraphic(xpos+7,ypos,GFX_LEERRAUM); + setup.player_name[xpos] = 0; + DrawGraphic(xpos + 6, ypos, GFX_KUGEL_ROT); + DrawGraphic(xpos + 7, ypos, GFX_LEERRAUM); } - else if (key==XK_Return && xpos>0) + else if (key == XK_Return && xpos > 0) { - DrawText(SX+6*32,SY+ypos*32,player.alias_name,FS_BIG,FC_RED); - DrawGraphic(xpos+6,ypos,GFX_LEERRAUM); - SavePlayerInfo(PLAYER_SETUP); - CheckCheat(); + DrawText(SX + 6*32, SY + ypos*32, setup.player_name, FS_BIG, FC_RED); + DrawGraphic(xpos + 6, ypos, GFX_LEERRAUM); + SaveSetup(); game_status = MAINMENU; - DrawMainMenu(); } + BackToFront(); } void DrawChooseLevel() { - int i; - CloseDoor(DOOR_CLOSE_2); + FadeToFront(); + InitAnimation(); + HandleChooseLevel(0,0, 0,0, MB_MENU_INITIALIZE); +} + +static void drawChooseLevelList(int first_entry, int num_page_entries) +{ + int i; + char buffer[SCR_FIELDX]; + ClearWindow(); - DrawText(SX,SY,"Level Directories",FS_BIG,FC_GREEN); - for(i=0;i 0) + DrawGraphic(0, 1, GFX_PFEIL_O); + + if (first_entry + num_page_entries < num_leveldirs) + DrawGraphic(0, MAX_LEVEL_SERIES_ON_SCREEN + 1, GFX_PFEIL_U); +} + +static void drawChooseLevelInfo(int leveldir_nr) +{ + XFillRectangle(display, drawto, gc, SX + 32, SY + 32, SXSIZE - 32, 32); + DrawTextFCentered(40, FC_RED, "%3d levels (%s)", + leveldir[leveldir_nr].levels, + leveldir[leveldir_nr].readonly ? "readonly" : "writable"); } void HandleChooseLevel(int mx, int my, int dx, int dy, int button) { static int choice = 3; + static int first_entry = 0; + static unsigned long choose_delay = 0; static int redraw = TRUE; - int x = (mx+32-SX)/32, y = (my+32-SY)/32; + int x = (mx + 32 - SX) / 32, y = (my + 32 - SY) / 32; + int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int num_page_entries; + + if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN) + num_page_entries = num_leveldirs; + else + num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1; + + if (button == MB_MENU_INITIALIZE) + { + redraw = TRUE; + choice = leveldir_nr + 3 - first_entry; + + if (choice > num_page_entries + 2) + { + choice = num_page_entries + 2; + first_entry = num_leveldirs - num_page_entries; + } + + drawChooseLevelList(first_entry, num_page_entries); + drawChooseLevelInfo(leveldir_nr); + } if (redraw) { - DrawGraphic(0,choice-1,GFX_KUGEL_ROT); + DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); redraw = FALSE; } + if (button == MB_MENU_INITIALIZE) + return; + if (dx || dy) { if (dy) { x = 1; - y = choice+dy; + y = choice + dy; } else x = y = 0; + } - if (y<3) - y = 3; - else if (y>num_leveldirs+2) - y = num_leveldirs+2; + if (x == 1 && y == 2) + { + if (first_entry > 0 && + (dy || DelayReached(&choose_delay, 150))) + { +#if 0 + first_entry--; +#else + first_entry -= step; + if (first_entry < 0) + first_entry = 0; +#endif + drawChooseLevelList(first_entry, num_page_entries); + drawChooseLevelInfo(first_entry); + DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); + return; + } + } + else if (x == 1 && y > num_page_entries + 2) + { + if (first_entry + num_page_entries < num_leveldirs && + (dy || DelayReached(&choose_delay, 150))) + { +#if 0 + first_entry++; +#else + first_entry += step; + if (first_entry + num_page_entries > num_leveldirs) + first_entry = num_leveldirs - num_page_entries; +#endif + drawChooseLevelList(first_entry, num_page_entries); + drawChooseLevelInfo(first_entry + num_page_entries - 1); + DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); + return; + } } if (!mx && !my && !dx && !dy) @@ -679,57 +890,62 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) y = choice; } - if (x==1 && y>=3 && y<=num_leveldirs+2) + if (x == 1 && y >= 3 && y <= num_page_entries + 2) { if (button) { - if (y!=choice) + if (y != choice) { - DrawGraphic(0,y-1,GFX_KUGEL_ROT); - DrawGraphic(0,choice-1,GFX_KUGEL_BLAU); + DrawGraphic(0, y - 1, GFX_KUGEL_ROT); + DrawGraphic(0, choice - 1, GFX_KUGEL_BLAU); + drawChooseLevelInfo(first_entry + y - 3); + choice = y; } - choice = y; } else { - player.leveldir_nr = leveldir_nr = y-3; - LoadPlayerInfo(PLAYER_LEVEL); - SavePlayerInfo(PLAYER_SETUP); - CheckCheat(); + leveldir_nr = first_entry + y - 3; + level_nr = + getLastPlayedLevelOfLevelSeries(leveldir[leveldir_nr].filename); + + SaveLevelSetup(); + TapeErase(); game_status = MAINMENU; DrawMainMenu(); redraw = TRUE; } } + BackToFront(); - if (game_status==CHOOSELEVEL) + if (game_status == CHOOSELEVEL) DoAnimation(); } -void DrawHallOfFame(int pos) +void DrawHallOfFame(int highlight_position) { - int y; - char txt[40]; + int i; CloseDoor(DOOR_CLOSE_2); - if (pos<0) + if (highlight_position < 0) LoadScore(level_nr); + ClearWindow(); - DrawText(SX+64,SY+10,"Hall Of Fame",FS_BIG,FC_YELLOW); - sprintf(txt,"HighScores of Level %d",level_nr); - DrawText(SX+256-strlen(txt)*7,SY+48,txt,FS_SMALL,FC_RED); - for(y=0;y= SETUP_SCREEN_POS_EMPTY1 && i <= SETUP_SCREEN_POS_EMPTY2)) + { + DrawGraphic(0,i,GFX_KUGEL_BLAU); + DrawText(SX+32,SY+i*32, setup_info[base].text, FS_BIG,FC_GREEN); + } - if (SETUP_2ND_JOYSTICK_ON(player.setup)) - DrawText(SX+14*32, SY+10*32,"2nd",FS_BIG,FC_YELLOW); - else - DrawText(SX+14*32, SY+10*32,"1st",FS_BIG,FC_YELLOW); + if (setup_info[base].value) + { + int setting_value = *setup_info[base].value; - for(i=2;i<15;i++) - if (i!=12) - DrawGraphic(0,i,GFX_KUGEL_BLAU); + DrawText(SX+14*32, SY+i*32, (setting_value ? "on" : "off"), + FS_BIG, (setting_value ? FC_YELLOW : FC_BLUE)); + } + } FadeToFront(); InitAnimation(); - HandleSetupScreen(0,0,0,0,MB_MENU_MARK); + HandleSetupScreen(0,0,0,0,MB_MENU_INITIALIZE); } void HandleSetupScreen(int mx, int my, int dx, int dy, int button) @@ -833,6 +1027,13 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) static int choice = 3; static int redraw = TRUE; int x = (mx+32-SX)/32, y = (my+32-SY)/32; + int pos_start = SETUP_SCREEN_POS_START + 1; + int pos_empty1 = SETUP_SCREEN_POS_EMPTY1 + 1; + int pos_empty2 = SETUP_SCREEN_POS_EMPTY2 + 1; + int pos_end = SETUP_SCREEN_POS_END + 1; + + if (button == MB_MENU_INITIALIZE) + redraw = TRUE; if (redraw) { @@ -840,6 +1041,9 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) redraw = FALSE; } + if (button == MB_MENU_INITIALIZE) + return; + if (dx || dy) { if (dy) @@ -850,13 +1054,13 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) else x = y = 0; - if (y==13) - y = (dy>0 ? 14 : 12); + if (y >= pos_empty1 && y <= pos_empty2) + y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1); - if (y<3) - y = 3; - else if (y>15) - y = 15; + if (y < pos_start) + y = pos_start; + else if (y > pos_end) + y = pos_end; } if (!mx && !my && !dx && !dy) @@ -865,7 +1069,8 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) y = choice; } - if (x==1 && y>=3 && y<=15 && y!=13) + if (x==1 && y >= pos_start && y <= pos_end && + !(y >= pos_empty1 && y <= pos_empty2)) { if (button) { @@ -882,87 +1087,134 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) if (y==3 && sound_status==SOUND_AVAILABLE) { - if (SETUP_SOUND_ON(player.setup)) + if (setup.sound) + { DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); + DrawText(SX+14*32, SY+(yy+1)*32,"off",FS_BIG,FC_BLUE); + DrawText(SX+14*32, SY+(yy+2)*32,"off",FS_BIG,FC_BLUE); + setup.sound_loops = FALSE; + setup.sound_music = FALSE; + } else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_SOUND; + setup.sound = !setup.sound; } else if (y==4 && sound_loops_allowed) { - if (SETUP_SOUND_LOOPS_ON(player.setup)) + if (setup.sound_loops) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else + { DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_SOUND_LOOPS; + DrawText(SX+14*32, SY+(yy-1)*32,"on ",FS_BIG,FC_YELLOW); + setup.sound = TRUE; + } + setup.sound_loops = !setup.sound_loops; } else if (y==5 && sound_loops_allowed) { - if (SETUP_SOUND_MUSIC_ON(player.setup)) + if (setup.sound_music) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else + { DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_SOUND_MUSIC; + DrawText(SX+14*32, SY+(yy-2)*32,"on ",FS_BIG,FC_YELLOW); + setup.sound = TRUE; + } + setup.sound_music = !setup.sound_music; } else if (y==6) { - if (SETUP_TOONS_ON(player.setup)) + if (setup.toons) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_TOONS; + setup.toons = !setup.toons; } else if (y==7) { - if (!SETUP_DIRECT_DRAW_ON(player.setup)) +#if 0 + if (setup.double_buffering) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_DIRECT_DRAW; + setup.double_buffering = !setup.double_buffering; + setup.direct_draw = !setup.double_buffering; +#else + DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); + setup.double_buffering = TRUE; + setup.direct_draw = !setup.double_buffering; +#endif } else if (y==8) { - if (SETUP_FADING_ON(player.setup)) + if (setup.scroll_delay) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_FADING; + setup.scroll_delay = !setup.scroll_delay; } else if (y==9) { - if (SETUP_QUICK_DOORS_ON(player.setup)) + if (setup.soft_scrolling) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_QUICK_DOORS; + setup.soft_scrolling = !setup.soft_scrolling; } else if (y==10) { - if (SETUP_RECORD_EACH_GAME_ON(player.setup)) + if (setup.fading) DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_RECORD_EACH_GAME; + setup.fading = !setup.fading; } else if (y==11) { - if (SETUP_2ND_JOYSTICK_ON(player.setup)) - DrawText(SX+14*32, SY+yy*32,"1st",FS_BIG,FC_YELLOW); + if (setup.quick_doors) + DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); else - DrawText(SX+14*32, SY+yy*32,"2nd",FS_BIG,FC_YELLOW); - player.setup ^= SETUP_2ND_JOYSTICK; + DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); + setup.quick_doors = !setup.quick_doors; } else if (y==12) { - CalibrateJoystick(); + if (setup.autorecord) + DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); + else + DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); + setup.autorecord = !setup.autorecord; + } + else if (y==13) + { + if (setup.team_mode) + DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE); + else + DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW); + setup.team_mode = !setup.team_mode; + } + else if (y==14) + { + game_status = SETUPINPUT; + DrawSetupInputScreen(); redraw = TRUE; } - else if (y==14 || y==15) + else if (y==pos_end-1 || y==pos_end) { - if (y==15) + if (y==pos_end) { - SavePlayerInfo(PLAYER_SETUP); + SaveSetup(); + + /* SaveJoystickData(); + */ + +#ifdef MSDOS + save_joystick_data(JOYSTICK_FILENAME); +#endif + + } game_status = MAINMENU; @@ -977,96 +1229,756 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) DoAnimation(); } -void CalibrateJoystick() +void DrawSetupInputScreen() { -#ifdef __FreeBSD__ - struct joystick joy_ctrl; -#else - struct joystick_control - { - int buttons; - int x; - int y; - } joy_ctrl; -#endif + ClearWindow(); + DrawText(SX+16, SY+16, "SETUP INPUT", FS_BIG, FC_YELLOW); - int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle; - int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle; + DrawGraphic(0, 2, GFX_KUGEL_BLAU); + DrawGraphic(0, 3, GFX_KUGEL_BLAU); + DrawGraphic(0, 4, GFX_KUGEL_BLAU); + DrawGraphic(0, 15, GFX_KUGEL_BLAU); + DrawGraphic(10, 2, GFX_PFEIL_L); + DrawGraphic(12, 2, GFX_PFEIL_R); - if (joystick_status==JOYSTICK_OFF) - goto error_out; + DrawText(SX+32, SY+2*32, "Player:", FS_BIG, FC_GREEN); + DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN); + DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN); - ClearWindow(); - DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); - DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW); - DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); - BackToFront(); + DrawTextFCentered(SYSIZE - 20, FC_BLUE, + "Joysticks deactivated on this screen"); -#ifdef __FreeBSD__ - joy_ctrl.b1 = joy_ctrl.b2 = 0; -#else - joy_ctrl.buttons = 0; -#endif - while(Joystick() & JOY_BUTTON); -#ifdef __FreeBSD__ - while(!(joy_ctrl.b1||joy_ctrl.b2)) -#else - while(!joy_ctrl.buttons) -#endif - { - if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) - { - joystick_status=JOYSTICK_OFF; - goto error_out; - } - Delay(10000); - } + HandleSetupInputScreen(0,0, 0,0, MB_MENU_INITIALIZE); + FadeToFront(); + InitAnimation(); +} - new_joystick_xleft = joy_ctrl.x; - new_joystick_yupper = joy_ctrl.y; +static void setJoystickDeviceToNr(char *device_name, int device_nr) +{ + if (device_name == NULL) + return; - ClearWindow(); - DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); - DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW); - DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); - BackToFront(); + if (device_nr < 0 || device_nr >= MAX_PLAYERS) + device_nr = 0; -#ifdef __FreeBSD__ - joy_ctrl.b1 = joy_ctrl.b2 = 0; -#else - joy_ctrl.buttons = 0; -#endif - while(Joystick() & JOY_BUTTON); -#ifdef __FreeBSD__ - while(!(joy_ctrl.b1||joy_ctrl.b2)) -#else - while(!joy_ctrl.buttons) -#endif + if (strlen(device_name) > 1) { - if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) - { - joystick_status=JOYSTICK_OFF; - goto error_out; - } - Delay(10000); + char c1 = device_name[strlen(device_name) - 1]; + char c2 = device_name[strlen(device_name) - 2]; + + if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9')) + device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10); } + else + strncpy(device_name, joystick_device_name[device_nr], strlen(device_name)); +} - new_joystick_xright = joy_ctrl.x; - new_joystick_ylower = joy_ctrl.y; +static void drawPlayerSetupInputInfo(int player_nr) +{ + int i; + static struct SetupKeyboardInfo custom_key; + static struct + { + KeySym *keysym; + char *text; + } custom[] = + { + { &custom_key.left, "Joystick Left" }, + { &custom_key.right, "Joystick Right" }, + { &custom_key.up, "Joystick Up" }, + { &custom_key.down, "Joystick Down" }, + { &custom_key.snap, "Button 1" }, + { &custom_key.bomb, "Button 2" } + }; + static char *joystick_name[MAX_PLAYERS] = + { + "Joystick1", + "Joystick2", + "Joystick3", + "Joystick4" + }; - ClearWindow(); - DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW); - DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); - BackToFront(); + custom_key = setup.input[player_nr].key; -#ifdef __FreeBSD__ + DrawText(SX+11*32, SY+2*32, int2str(player_nr + 1, 1), FS_BIG, FC_RED); + DrawGraphic(8, 2, GFX_SPIELER1 + player_nr); + + if (setup.input[player_nr].use_joystick) + { + char *device_name = setup.input[player_nr].joy.device_name; + + DrawText(SX+8*32, SY+3*32, + joystick_name[getJoystickNrFromDeviceName(device_name)], + FS_BIG, FC_YELLOW); + DrawText(SX+32, SY+4*32, "Calibrate", FS_BIG, FC_GREEN); + } + else + { + DrawText(SX+8*32, SY+3*32, "Keyboard ", FS_BIG, FC_YELLOW); + DrawText(SX+32, SY+4*32, "Customize", FS_BIG, FC_GREEN); + } + + DrawText(SX+32, SY+5*32, "Actual Settings:", FS_BIG, FC_GREEN); + DrawGraphic(1, 6, GFX_PFEIL_L); + DrawGraphic(1, 7, GFX_PFEIL_R); + DrawGraphic(1, 8, GFX_PFEIL_O); + DrawGraphic(1, 9, GFX_PFEIL_U); + DrawText(SX+2*32, SY+6*32, ":", FS_BIG, FC_BLUE); + DrawText(SX+2*32, SY+7*32, ":", FS_BIG, FC_BLUE); + DrawText(SX+2*32, SY+8*32, ":", FS_BIG, FC_BLUE); + DrawText(SX+2*32, SY+9*32, ":", FS_BIG, FC_BLUE); + DrawText(SX+32, SY+10*32, "Snap Field:", FS_BIG, FC_BLUE); + DrawText(SX+32, SY+12*32, "Place Bomb:", FS_BIG, FC_BLUE); + + for (i=0; i<6; i++) + { + int ypos = 6 + i + (i > 3 ? i-3 : 0); + + DrawText(SX + 3*32, SY + ypos*32, + " ", FS_BIG, FC_YELLOW); + DrawText(SX + 3*32, SY + ypos*32, + (setup.input[player_nr].use_joystick ? + custom[i].text : + getKeyNameFromKeySym(*custom[i].keysym)), + FS_BIG, FC_YELLOW); + } +} + +void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button) +{ + static int choice = 3; + static int player_nr = 0; + static int redraw = TRUE; + int x = (mx+32-SX)/32, y = (my+32-SY)/32; + int pos_start = SETUPINPUT_SCREEN_POS_START + 1; + int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1 + 1; + int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2 + 1; + int pos_end = SETUPINPUT_SCREEN_POS_END + 1; + + if (button == MB_MENU_INITIALIZE) + { + drawPlayerSetupInputInfo(player_nr); + redraw = TRUE; + } + + if (redraw) + { + DrawGraphic(0,choice-1,GFX_KUGEL_ROT); + redraw = FALSE; + } + + if (button == MB_MENU_INITIALIZE) + return; + + if (dx || dy) + { + if (dx && choice == 3) + { + x = (dx < 0 ? 11 : 13); + y = 3; + } + else if (dx && choice == 4) + { + button = MB_MENU_CHOICE; + x = 1; + y = 4; + } + else if (dy) + { + x = 1; + y = choice + dy; + } + else + x = y = 0; + + if (y >= pos_empty1 && y <= pos_empty2) + y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1); + + if (y < pos_start) + y = pos_start; + else if (y > pos_end) + y = pos_end; + } + + if (!mx && !my && !dx && !dy) + { + x = 1; + y = choice; + } + + if (y == 3 && ((x == 1 && !button) || ((x == 11 || x == 13) && button))) + { + static unsigned long delay = 0; + + if (!DelayReached(&delay, 150)) + goto out; + + player_nr = (player_nr + (x == 11 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS; + + drawPlayerSetupInputInfo(player_nr); + } + else if (x==1 && y >= pos_start && y <= pos_end && + !(y >= pos_empty1 && y <= pos_empty2)) + { + if (button) + { + if (y != choice) + { + DrawGraphic(0, y-1, GFX_KUGEL_ROT); + DrawGraphic(0, choice-1, GFX_KUGEL_BLAU); + } + choice = y; + } + else + { + if (y == 4) + { + char *device_name = setup.input[player_nr].joy.device_name; + + if (!setup.input[player_nr].use_joystick) + { + int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1); + + setJoystickDeviceToNr(device_name, new_device_nr); + setup.input[player_nr].use_joystick = TRUE; + } + else + { + int device_nr = getJoystickNrFromDeviceName(device_name); + int new_device_nr = device_nr + (dx >= 0 ? +1 : -1); + + if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS) + setup.input[player_nr].use_joystick = FALSE; + else + setJoystickDeviceToNr(device_name, new_device_nr); + } + + + /* + InitJoysticks(); + */ + + +#if 0 + int one_joystick_nr = (dx >= 0 ? 0 : 1); + int the_other_joystick_nr = (dx >= 0 ? 1 : 0); + + if (setup.input[player_nr].use_joystick) + { + if (setup.input[player_nr].joystick_nr == one_joystick_nr) + setup.input[player_nr].joystick_nr = the_other_joystick_nr; + else + setup.input[player_nr].use_joystick = FALSE; + } + else + { + setup.input[player_nr].use_joystick = TRUE; + setup.input[player_nr].joystick_nr = one_joystick_nr; + } +#endif + + drawPlayerSetupInputInfo(player_nr); + } + else if (y == 5) + { + if (setup.input[player_nr].use_joystick) + { + InitJoysticks(); + game_status = CALIBRATION; + CalibrateJoystick(player_nr); + game_status = SETUPINPUT; + } + else + CustomizeKeyboard(player_nr); + + redraw = TRUE; + } + else if (y == pos_end) + { + InitJoysticks(); + + game_status = SETUP; + DrawSetupScreen(); + redraw = TRUE; + } + } + } + BackToFront(); + + out: + + if (game_status == SETUPINPUT) + DoAnimation(); +} + +void CustomizeKeyboard(int player_nr) +{ + int i; + int step_nr; + boolean finished = FALSE; + static struct SetupKeyboardInfo custom_key; + static struct + { + KeySym *keysym; + char *text; + } customize_step[] = + { + { &custom_key.left, "Move Left" }, + { &custom_key.right, "Move Right" }, + { &custom_key.up, "Move Up" }, + { &custom_key.down, "Move Down" }, + { &custom_key.snap, "Snap Field" }, + { &custom_key.bomb, "Place Bomb" } + }; + + /* read existing key bindings from player setup */ + custom_key = setup.input[player_nr].key; + + ClearWindow(); + DrawText(SX + 16, SY + 16, "Keyboard Input", FS_BIG, FC_YELLOW); + + BackToFront(); + InitAnimation(); + + step_nr = 0; + DrawText(SX, SY + (2+2*step_nr)*32, + customize_step[step_nr].text, FS_BIG, FC_RED); + DrawText(SX, SY + (2+2*step_nr+1)*32, + "Key:", FS_BIG, FC_RED); + DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32, + getKeyNameFromKeySym(*customize_step[step_nr].keysym), + FS_BIG, FC_BLUE); + + while(!finished) + { + if (XPending(display)) /* got event from X server */ + { + XEvent event; + + XNextEvent(display, &event); + + switch(event.type) + { + case KeyPress: + { + KeySym key = XLookupKeysym((XKeyEvent *)&event, + ((XKeyEvent *)&event)->state); + + if (key == XK_Escape || (key == XK_Return && step_nr == 6)) + { + finished = TRUE; + break; + } + + /* press 'Enter' to keep the existing key binding */ + if (key == XK_Return || step_nr == 6) + key = *customize_step[step_nr].keysym; + + /* check if key already used */ + for (i=0; istate)) + { + case XK_Return: + if (check_remaining == 0) + result = 1; + break; + + case XK_Escape: + result = 0; + break; + + default: + break; + } + break; + + case KeyRelease: + key_joystick_mapping = 0; + break; + + default: + HandleOtherEvents(&event); + break; + } + } + +#ifndef MSDOS + if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) + { + joystick_status = JOYSTICK_OFF; + goto error_out; + } + + new_joystick_xleft = MIN(new_joystick_xleft, joy_ctrl.x); + new_joystick_xright = MAX(new_joystick_xright, joy_ctrl.x); + new_joystick_yupper = MIN(new_joystick_yupper, joy_ctrl.y); + new_joystick_ylower = MAX(new_joystick_ylower, joy_ctrl.y); + + new_joystick_xmiddle = + new_joystick_xleft + (new_joystick_xright - new_joystick_xleft) / 2; + new_joystick_ymiddle = + new_joystick_yupper + (new_joystick_ylower - new_joystick_yupper) / 2; + + setup.input[player_nr].joy.xleft = new_joystick_xleft; + setup.input[player_nr].joy.yupper = new_joystick_yupper; + setup.input[player_nr].joy.xright = new_joystick_xright; + setup.input[player_nr].joy.ylower = new_joystick_ylower; + setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle; + setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle; + + CheckJoystickData(); +#endif + + joy_value = Joystick(player_nr); + + if (joy_value & JOY_BUTTON && check_remaining == 0) + { + result = 1; + +#ifdef MSDOS + if (calibration_step == 1) + { + remove_joystick(); + InitJoysticks(); + } + else if (calibrate_joystick(joystick_fd) != 0) + { + joystick_status = JOYSTICK_OFF; + goto error_out; + } + + if (joy[joystick_fd].flags & JOYFLAG_CALIBRATE) + { + calibration_step++; + result = -1; + + DrawText(SX, SY + 7*32, " MOVE JOYSTICK ", FS_BIG, FC_YELLOW); + DrawText(SX + 16, SY + 8*32, " TO ", FS_BIG, FC_YELLOW); + + if (calibration_step == 2) + DrawText(SX + 16, SY + 9*32," THE UPPER LEFT ", FS_BIG, FC_YELLOW); + else + DrawText(SX, SY + 9*32," THE LOWER RIGHT ", FS_BIG, FC_YELLOW); + + DrawText(SX, SY + 10*32, " AND ", FS_BIG, FC_YELLOW); + DrawText(SX, SY + 11*32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW); + + BackToFront(); + + while(Joystick(player_nr) & JOY_BUTTON) + DoAnimation(); + } +#endif + } + + x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0); + y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0); + + if (x != last_x || y != last_y) + { +#ifndef MSDOS + DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_GELB); +#else + DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_BLAU); +#endif + DrawGraphic(xpos + x, ypos + y, GFX_KUGEL_ROT); + + last_x = x; + last_y = y; + + if (check_remaining > 0 && !check[x+1][y+1]) + { + check[x+1][y+1] = TRUE; + check_remaining--; + } + +#if 0 + printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n", + setup.input[player_nr].joy.xleft, + setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xright); + printf("UP / MIDDLE / DOWN == %d / %d / %d\n", + setup.input[player_nr].joy.yupper, + setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.ylower); +#endif + + } + + BackToFront(); + DoAnimation(); + + /* don't eat all CPU time */ + Delay(10); + } + + StopAnimation(); + + DrawSetupInputScreen(); + while(Joystick(player_nr) & JOY_BUTTON); + return; + + error_out: + + ClearWindow(); + DrawText(SX + 16, SY + 6*32, " JOYSTICK NOT ", FS_BIG, FC_YELLOW); + DrawText(SX, SY + 7*32, " AVAILABLE ", FS_BIG, FC_YELLOW); + BackToFront(); + Delay(2000); + DrawSetupInputScreen(); +} + + + +#if 0 + +void CalibrateJoystick_OLD() +{ +#ifdef __FreeBSD__ + struct joystick joy_ctrl; +#else + struct joystick_control + { + int buttons; + int x; + int y; + } joy_ctrl; +#endif + +#ifdef MSDOS + char joy_nr[4]; +#endif + + int joystick_nr = setup.input[0].joystick_nr; + int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle; + int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle; + + if (joystick_status == JOYSTICK_OFF) + goto error_out; + +#ifndef MSDOS + ClearWindow(); + DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); + DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW); + DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); + BackToFront(); + +#ifdef __FreeBSD__ + joy_ctrl.b1 = joy_ctrl.b2 = 0; +#else + joy_ctrl.buttons = 0; +#endif + while(Joystick() & JOY_BUTTON); +#ifdef __FreeBSD__ + while(!(joy_ctrl.b1 || joy_ctrl.b2)) +#else + while(!joy_ctrl.buttons) +#endif + { + if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) + { + joystick_status=JOYSTICK_OFF; + goto error_out; + } + Delay(10); + } + + new_joystick_xleft = joy_ctrl.x; + new_joystick_yupper = joy_ctrl.y; + + ClearWindow(); + DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); + DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW); + DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); + BackToFront(); + +#ifdef __FreeBSD__ + joy_ctrl.b1 = joy_ctrl.b2 = 0; +#else + joy_ctrl.buttons = 0; +#endif + while(Joystick() & JOY_BUTTON); +#ifdef __FreeBSD__ + while(!(joy_ctrl.b1 || joy_ctrl.b2)) +#else + while(!joy_ctrl.buttons) +#endif + { + if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) + { + joystick_status=JOYSTICK_OFF; + goto error_out; + } + Delay(10); + } + + new_joystick_xright = joy_ctrl.x; + new_joystick_ylower = joy_ctrl.y; + + ClearWindow(); + DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW); + DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW); + BackToFront(); + +#ifdef __FreeBSD__ joy_ctrl.b1 = joy_ctrl.b2 = 0; #else joy_ctrl.buttons = 0; #endif while(Joystick() & JOY_BUTTON); #ifdef __FreeBSD__ - while(!(joy_ctrl.b1||joy_ctrl.b2)) + while(!(joy_ctrl.b1 || joy_ctrl.b2)) #else while(!joy_ctrl.buttons) #endif @@ -1076,18 +1988,18 @@ void CalibrateJoystick() joystick_status=JOYSTICK_OFF; goto error_out; } - Delay(10000); + Delay(10); } new_joystick_xmiddle = joy_ctrl.x; new_joystick_ymiddle = joy_ctrl.y; - joystick[joystick_nr].xleft = new_joystick_xleft; - joystick[joystick_nr].yupper = new_joystick_yupper; - joystick[joystick_nr].xright = new_joystick_xright; - joystick[joystick_nr].ylower = new_joystick_ylower; - joystick[joystick_nr].xmiddle = new_joystick_xmiddle; - joystick[joystick_nr].ymiddle = new_joystick_ymiddle; + setup.input[player_nr].joy.xleft = new_joystick_xleft; + setup.input[player_nr].joy.yupper = new_joystick_yupper; + setup.input[player_nr].joy.xright = new_joystick_xright; + setup.input[player_nr].joy.ylower = new_joystick_ylower; + setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle; + setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle; CheckJoystickData(); @@ -1095,152 +2007,304 @@ void CalibrateJoystick() while(Joystick() & JOY_BUTTON); return; +#endif error_out: +#ifdef MSDOS + joy_nr[0] = '#'; + joy_nr[1] = SETUP_2ND_JOYSTICK_ON(local_player->setup)+49; + joy_nr[2] = '\0'; + + remove_joystick(); + ClearWindow(); + DrawText(SX+32, SY+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW); + DrawText(SX+16+7*32, SY+8*32, joy_nr, FS_BIG,FC_YELLOW); + DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW); + BackToFront(); + + for(clear_keybuf();!keypressed();); + install_joystick(JOY_TYPE_2PADS); + + ClearWindow(); + DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); + DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW); + DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW); + BackToFront(); + + for(clear_keybuf();!keypressed();); + calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup)); + + ClearWindow(); + DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW); + DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW); + DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW); + BackToFront(); + + for(clear_keybuf();!keypressed();); + calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup)); + + DrawSetupScreen(); + return; +#endif + ClearWindow(); DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW); DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW); - Delay(3000000); + BackToFront(); + Delay(3000); DrawSetupScreen(); } +#endif + + + +void HandleGameActions() +{ + if (game_status != PLAYING) + return; + + if (local_player->LevelSolved) + GameWon(); + + if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) + TapeStop(); + + GameActions(); + + BackToFront(); +} + void HandleVideoButtons(int mx, int my, int button) { - if (game_status!=MAINMENU && game_status!=PLAYING) + if (game_status != MAINMENU && game_status != PLAYING) return; switch(CheckVideoButtons(mx,my,button)) { case BUTTON_VIDEO_EJECT: TapeStop(); - if (!TAPE_IS_EMPTY(tape)) - SaveLevelTape(tape.level_nr); + if (TAPE_IS_EMPTY(tape)) + { + LoadTape(level_nr); + if (TAPE_IS_EMPTY(tape)) + Request("No tape for this level !",REQ_CONFIRM); + } else - AreYouSure("Tape is empty !",AYS_CONFIRM); + { + if (tape.changed) + SaveTape(tape.level_nr); + TapeErase(); + } DrawCompleteVideoDisplay(); break; + case BUTTON_VIDEO_STOP: TapeStop(); break; + case BUTTON_VIDEO_PAUSE: TapeTogglePause(); break; + case BUTTON_VIDEO_REC: - if (tape.pausing) - TapeTogglePause(); - else if (game_status==MAINMENU) - TapeInitRecording(); + if (TAPE_IS_STOPPED(tape)) + { + TapeStartRecording(); + +#ifndef MSDOS + if (options.network) + SendToServer_StartPlaying(); + else +#endif + { + game_status = PLAYING; + InitGame(); + } + } + else if (tape.pausing) + { + if (tape.playing) /* PLAYING -> PAUSING -> RECORDING */ + { + tape.pos[tape.counter].delay = tape.delay_played; + tape.playing = FALSE; + tape.recording = TRUE; + tape.changed = TRUE; + + DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0); + } + else + TapeTogglePause(); + } break; + case BUTTON_VIDEO_PLAY: - if (tape.pausing) - TapeTogglePause(); - else if (game_status==MAINMENU) - TapeInitPlaying(); + if (TAPE_IS_EMPTY(tape)) + break; + + if (TAPE_IS_STOPPED(tape)) + { + TapeStartPlaying(); + + game_status = PLAYING; + InitGame(); + } + else if (tape.playing) + { + if (tape.pausing) /* PAUSE -> PLAY */ + TapeTogglePause(); + else if (!tape.fast_forward) /* PLAY -> FAST FORWARD PLAY */ + { + tape.fast_forward = TRUE; + DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0); + } + else if (!tape.pause_before_death) /* FFWD PLAY -> + AUTO PAUSE */ + { + tape.pause_before_death = TRUE; + DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY); + } + else /* -> NORMAL PLAY */ + { + tape.fast_forward = FALSE; + tape.pause_before_death = FALSE; + DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_OFF, 0); + } + } break; + default: break; } + + BackToFront(); } void HandleSoundButtons(int mx, int my, int button) { - if (game_status!=PLAYING) + if (game_status != PLAYING) return; switch(CheckSoundButtons(mx,my,button)) { case BUTTON_SOUND_MUSIC: - if (sound_music_on) + if (setup.sound_music) { - sound_music_on = FALSE; - player.setup &= ~SETUP_SOUND_MUSIC; + setup.sound_music = FALSE; FadeSound(background_loop[level_nr % num_bg_loops]); DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF); } else if (sound_loops_allowed) { - sound_music_on = TRUE; - player.setup |= SETUP_SOUND_MUSIC; + setup.sound = setup.sound_music = TRUE; PlaySoundLoop(background_loop[level_nr % num_bg_loops]); DrawSoundDisplay(BUTTON_SOUND_MUSIC_ON); } else DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF); break; + case BUTTON_SOUND_LOOPS: - if (sound_loops_on) + if (setup.sound_loops) { - sound_loops_on = FALSE; - player.setup &= ~SETUP_SOUND_LOOPS; + setup.sound_loops = FALSE; DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF); } else if (sound_loops_allowed) { - sound_loops_on = TRUE; - player.setup |= SETUP_SOUND_LOOPS; + setup.sound = setup.sound_loops = TRUE; DrawSoundDisplay(BUTTON_SOUND_LOOPS_ON); } else DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF); break; - case BUTTON_SOUND_SOUND: - if (sound_on) + + case BUTTON_SOUND_SIMPLE: + if (setup.sound_simple) { - sound_on = FALSE; - player.setup &= ~SETUP_SOUND; - DrawSoundDisplay(BUTTON_SOUND_SOUND_OFF); + setup.sound_simple = FALSE; + DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF); } else if (sound_status==SOUND_AVAILABLE) { - sound_on = TRUE; - player.setup |= SETUP_SOUND; - DrawSoundDisplay(BUTTON_SOUND_SOUND_ON); + setup.sound = setup.sound_simple = TRUE; + DrawSoundDisplay(BUTTON_SOUND_SIMPLE_ON); } else - DrawSoundDisplay(BUTTON_SOUND_SOUND_OFF); + DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF); break; + default: break; } + + BackToFront(); } void HandleGameButtons(int mx, int my, int button) { - if (game_status!=PLAYING) + if (game_status != PLAYING) return; switch(CheckGameButtons(mx,my,button)) { case BUTTON_GAME_STOP: - if (AreYouSure("Do you really want to quit the game ?", - AYS_ASK | AYS_STAY_CLOSED)) - { + if (AllPlayersGone) + { + CloseDoor(DOOR_CLOSE_1); game_status = MAINMENU; DrawMainMenu(); + break; + } + + if (Request("Do you really want to quit the game ?", + REQ_ASK | REQ_STAY_CLOSED)) + { +#ifndef MSDOS + if (options.network) + SendToServer_StopPlaying(); + else +#endif + { + game_status = MAINMENU; + DrawMainMenu(); + } } else OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); break; + case BUTTON_GAME_PAUSE: - if (tape.pausing) + if (options.network) { - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); +#ifndef MSDOS + if (tape.pausing) + SendToServer_ContinuePlaying(); + else + SendToServer_PausePlaying(); +#endif } else - { - tape.pausing = TRUE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0); - } + TapeTogglePause(); break; + case BUTTON_GAME_PLAY: if (tape.pausing) { - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); +#ifndef MSDOS + if (options.network) + SendToServer_ContinuePlaying(); + else +#endif + { + tape.pausing = FALSE; + DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); + } } break; + default: break; } + + BackToFront(); } diff --git a/src/screens.h b/src/screens.h index 32a58401..39e30153 100644 --- a/src/screens.h +++ b/src/screens.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * screens.h * ***********************************************************/ @@ -17,24 +16,29 @@ #include "main.h" -void DrawMainMenu(); +void DrawHeadline(void); +void DrawMainMenu(void); void HandleMainMenu(int, int, int, int, int); void DrawHelpScreenElAction(int); void DrawHelpScreenElText(int); void DrawHelpScreenMusicText(int); void DrawHelpScreenCreditsText(void); -void DrawHelpScreen(); +void DrawHelpScreen(void); void HandleHelpScreen(int); void HandleTypeName(int, KeySym); void DrawChooseLevel(void); void HandleChooseLevel(int, int, int, int, int); void DrawHallOfFame(int); void HandleHallOfFame(int); -void DrawSetupScreen(); +void DrawSetupScreen(void); void HandleSetupScreen(int, int, int, int, int); -void CalibrateJoystick(void); +void DrawSetupInputScreen(void); +void HandleSetupInputScreen(int, int, int, int, int); +void CustomizeKeyboard(int); +void CalibrateJoystick(int); +void HandleGameActions(void); void HandleVideoButtons(int, int, int); void HandleSoundButtons(int, int, int); void HandleGameButtons(int, int, int); -#endif +#endif /* SCREENS_H */ diff --git a/src/sound.c b/src/sound.c index dc14ad55..340ec942 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1,45 +1,71 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * sound.c * ***********************************************************/ #include "sound.h" +#include "misc.h" /*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/ +static int playing_sounds = 0; static struct SoundControl playlist[MAX_SOUNDS_PLAYING]; static struct SoundControl emptySoundControl = { -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL }; + +#ifndef MSDOS static int stereo_volume[PSND_MAX_LEFT2RIGHT+1]; static char premix_first_buffer[SND_BLOCKSIZE]; +#ifdef VOXWARE static char premix_left_buffer[SND_BLOCKSIZE]; static char premix_right_buffer[SND_BLOCKSIZE]; static int premix_last_buffer[SND_BLOCKSIZE]; +#endif /* VOXWARE */ static unsigned char playing_buffer[SND_BLOCKSIZE]; -static int playing_sounds = 0; +#endif /* MSDOS */ + +/* forward declaration of internal functions */ +#ifdef VOXWARE +static void SoundServer_InsertNewSound(struct SoundControl); +#endif +#ifndef VOXWARE +static unsigned char linear_to_ulaw(int); +static int ulaw_to_linear(unsigned char); +#endif +#ifdef HPUX_AUDIO +static void HPUX_Audio_Control(); +#endif +#ifdef MSDOS +static void SoundServer_InsertNewSound(struct SoundControl); +static void SoundServer_StopSound(int); +static void SoundServer_StopAllSounds(); +#endif void SoundServer() { + int i; +#ifndef MSDOS struct SoundControl snd_ctrl; fd_set sound_fdset; - int i; close(sound_pipe[1]); /* no writing into pipe needed */ +#endif for(i=0;i=0) { @@ -238,12 +262,12 @@ void SoundServer() } } -#else /* von '#ifdef VOXWARE' */ +#else /* !VOXWARE */ if (snd_ctrl.active && !snd_ctrl.loop) { struct timeval delay = { 0, 0 }; - char *sample_ptr; + byte *sample_ptr; long sample_size, max_sample_size = SND_BLOCKSIZE; long sample_rate = 8000; /* standard "/dev/audio" sampling rate */ int wait_percent = 90; /* wait 90% of the real playing time */ @@ -259,9 +283,9 @@ void SoundServer() FD_SET(sound_pipe[0], &sound_fdset); /* get pointer and size of the actual sound sample */ - sample_ptr = snd_ctrl.data_ptr+snd_ctrl.playingpos; + sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos; sample_size = - MIN(max_sample_size,snd_ctrl.data_len-snd_ctrl.playingpos); + MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos); snd_ctrl.playingpos += sample_size; /* fill the first mixing buffer with original sample */ @@ -292,24 +316,81 @@ void SoundServer() } } -#endif /* von '#ifdef VOXWARE' */ +#endif /* !VOXWARE */ } +#endif /* !MSDOS */ } -void SoundServer_InsertNewSound(struct SoundControl snd_ctrl) +#ifdef MSDOS +static void sound_handler(struct SoundControl snd_ctrl) { - int i,k; + int i; + + if (snd_ctrl.fade_sound) + { + if (!playing_sounds) + return; - /* wenn voll, ältesten Sound 'rauswerfen */ + for (i=0; ilongest) { @@ -317,18 +398,22 @@ void SoundServer_InsertNewSound(struct SoundControl snd_ctrl) longest_nr=i; } } +#ifdef MSDOS + voice_set_volume(playlist[longest_nr].voice, 0); + deallocate_voice(playlist[longest_nr].voice); +#endif playlist[longest_nr] = emptySoundControl; playing_sounds--; } - /* nachsehen, ob (und ggf. wie oft) Sound bereits gespielt wird */ + /* check if sound is already being played (and how often) */ for(k=0,i=0;i=1 && snd_ctrl.loop) { for(i=0;i=2) { int longest=0, longest_nr=0; - /* den bereits am längsten gespielten (gleichen) Sound suchen */ + /* look for oldest equal sound */ for(i=0;i=longest) { longest=actual; longest_nr=i; } } +#ifdef MSDOS + voice_set_volume(playlist[longest_nr].voice, 0); + deallocate_voice(playlist[longest_nr].voice); +#endif playlist[longest_nr] = emptySoundControl; playing_sounds--; } @@ -373,6 +471,14 @@ void SoundServer_InsertNewSound(struct SoundControl snd_ctrl) { playlist[i] = snd_ctrl; playing_sounds++; +#ifdef MSDOS + playlist[i].voice = allocate_voice(Sound[snd_ctrl.nr].sample_ptr); + if(snd_ctrl.loop) + voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP); + voice_set_volume(playlist[i].voice, snd_ctrl.volume); + voice_set_pan(playlist[i].voice, snd_ctrl.stereo); + voice_start(playlist[i].voice); +#endif break; } } @@ -392,7 +498,7 @@ void SoundServer_FadeSound(int nr) } */ -void SoundServer_StopSound(int nr) +static void SoundServer_StopSound(int nr) { int i; @@ -402,49 +508,54 @@ void SoundServer_StopSound(int nr) for(i=0;i longword */ +{ + unsigned char *ptr = (unsigned char *)be; + + return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]); +} + +static unsigned long le2long(unsigned long *be) /* little-endian -> longword */ +{ + unsigned char *ptr = (unsigned char *)be; + + return(ptr[3]<<24 | ptr[2]<<16 | ptr[1]<<8 | ptr[0]); +} +#endif /* !MSDOS */ + +boolean LoadSound(struct SoundInfo *snd_info) { + char filename[256]; + char *sound_ext = "wav"; +#ifndef MSDOS + struct SoundHeader_WAV *sound_header; FILE *file; + int i; +#endif + + sprintf(filename, "%s/%s/%s.%s", + options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext); + +#ifndef MSDOS + + if ((file = fopen(filename, "r")) == NULL) + { + Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename); + return(FALSE); + } + + if (fseek(file, 0, SEEK_END) < 0) + { + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + fclose(file); + return(FALSE); + } + + snd_info->file_len = ftell(file); + rewind(file); + + snd_info->file_ptr = checked_malloc(snd_info->file_len); + + if (fread(snd_info->file_ptr, 1, snd_info->file_len, file) != + snd_info->file_len) + { + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + fclose(file); + return(FALSE); + } + + fclose(file); + + sound_header = (struct SoundHeader_WAV *)snd_info->file_ptr; + + if (strncmp(sound_header->magic_RIFF, "RIFF", 4) || + snd_info->file_len != le2long(&sound_header->header_size) + 8 || + strncmp(sound_header->magic_WAVE, "WAVE", 4) || + strncmp(sound_header->magic_DATA, "data", 4) || + snd_info->file_len != le2long(&sound_header->data_size) + 44) + { + Error(ERR_WARN, "'%s' is not a RIFF/WAVE file or broken - no sounds", + filename); + return(FALSE); + } + + snd_info->data_ptr = snd_info->file_ptr + 44; + snd_info->data_len = le2long(&sound_header->data_size); + + for (i=0; idata_len; i++) + snd_info->data_ptr[i] = snd_info->data_ptr[i]^0x80; + +#else /* MSDOS */ + + snd_info->sample_ptr = load_sample(filename); + if (!snd_info->sample_ptr) + { + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + return(FALSE); + } + +#endif /* MSDOS */ + + return(TRUE); +} + +boolean LoadSound_8SVX(struct SoundInfo *snd_info) +{ char filename[256]; +#ifndef MSDOS + struct SoundHeader_8SVX *sound_header; + FILE *file; + char *ptr; char *sound_ext = "8svx"; - struct SoundHeader_8SVX *snd_hdr; - unsigned char *ptr; +#else + char *sound_ext = "wav"; +#endif - sprintf(filename,"%s/%s.%s",SND_PATH,snd_info->name,sound_ext); + sprintf(filename, "%s/%s/%s.%s", + options.base_directory, SOUNDS_DIRECTORY, snd_info->name, sound_ext); +#ifndef MSDOS if (!(file=fopen(filename,"r"))) { - fprintf(stderr,"%s: cannot open sound file '%s' - no sounds\n", - progname,filename); + Error(ERR_WARN, "cannot open sound file '%s' - no sounds", filename); return(FALSE); } if (fseek(file,0,SEEK_END)<0) { - fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n", - progname,filename); + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); fclose(file); return(FALSE); } @@ -593,59 +800,74 @@ BOOL LoadSound(struct SoundInfo *snd_info) if (!(snd_info->file_ptr=malloc(snd_info->file_len))) { - fprintf(stderr,"%s: out of memory (this shouldn't happen :) - no sounds\n", - progname); + Error(ERR_WARN, "out of memory (this shouldn't happen :) - no sounds"); fclose(file); return(FALSE); } if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len) { - fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n", - progname,filename); + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); fclose(file); return(FALSE); } fclose(file); - snd_hdr = (struct SoundHeader_8SVX *)snd_info->file_ptr; + sound_header = (struct SoundHeader_8SVX *)snd_info->file_ptr; - if (strncmp(snd_hdr->magic_FORM,"FORM",4) || - snd_info->file_len!=be2long(&snd_hdr->chunk_size)+8 || - strncmp(snd_hdr->magic_8SVX,"8SVX",4)) + if (strncmp(sound_header->magic_FORM,"FORM",4) || + snd_info->file_len != be2long(&sound_header->chunk_size)+8 || + strncmp(sound_header->magic_8SVX,"8SVX",4)) { - fprintf(stderr,"%s: '%s' is not an IFF/8SVX file or broken- no sounds\n", - progname,filename); + Error(ERR_WARN, "'%s' is not an IFF/8SVX file or broken - no sounds", + filename); return(FALSE); } - ptr = (unsigned char *)snd_info->file_ptr; + ptr = (char *)snd_info->file_ptr + 12; - while(ptr<(unsigned char *)snd_info->file_ptr+snd_info->file_len) + while(ptr < (char *)(snd_info->file_ptr + snd_info->file_len)) { if (!strncmp(ptr,"VHDR",4)) { - ptr+=be2long((unsigned long *)(ptr+4)); + ptr += be2long((unsigned long *)(ptr + 4)) + 8; + continue; } - if (!strncmp(ptr,"ANNO",4)) + else if (!strncmp(ptr,"ANNO",4)) { - ptr+=be2long((unsigned long *)(ptr+4)); + ptr += be2long((unsigned long *)(ptr + 4)) + 8; + continue; } - if (!strncmp(ptr,"CHAN",4)) + else if (!strncmp(ptr,"CHAN",4)) { - ptr+=be2long((unsigned long *)(ptr+4)); + ptr += be2long((unsigned long *)(ptr + 4)) + 8; + continue; } - if (!strncmp(ptr,"BODY",4)) + else if (!strncmp(ptr,"BODY",4)) { - snd_info->data_ptr = ptr+8; - snd_info->data_len = be2long((unsigned long *)(ptr+4)); + snd_info->data_ptr = (byte *)ptr + 8; + snd_info->data_len = be2long((unsigned long *)(ptr + 4)); return(TRUE); } - ptr++; + else + { + /* other chunk not recognized here */ + ptr += be2long((unsigned long *)(ptr + 4)) + 8; + continue; + } } return(FALSE); +#else /* MSDOS */ + snd_info->sample_ptr = load_sample(filename); + if(!snd_info->sample_ptr) + { + Error(ERR_WARN, "cannot read sound file '%s' - no sounds", filename); + return(FALSE); + } + return(TRUE); +#endif /* MSDOS */ } void PlaySound(int nr) @@ -663,11 +885,11 @@ void PlaySoundLoop(int nr) PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP); } -void PlaySoundExt(int nr, int volume, int stereo, BOOL loop) +void PlaySoundExt(int nr, int volume, int stereo, boolean loop) { struct SoundControl snd_ctrl = emptySoundControl; - if (sound_status==SOUND_OFF || !sound_on) + if (sound_status==SOUND_OFF || !setup.sound) return; if (volume +#include "main.h" #ifdef linux #include @@ -40,9 +39,14 @@ extern void ioctl(long, long, void *); #define HPUX_AUDIO #endif /* _HPUX_SOURCE */ +#ifndef MSDOS #define MAX_SOUNDS_PLAYING 16 +#else +#define MAX_SOUNDS_PLAYING 8 +#endif /* some values for PlaySound(), StopSound() and friends */ +#ifndef MSDOS #define PSND_SILENCE 0 #define PSND_MAX_VOLUME_BITS 7 #define PSND_MIN_VOLUME 0 @@ -56,6 +60,16 @@ extern void ioctl(long, long, void *); #define PSND_MAX_RIGHT (+PSND_MAX_STEREO) #define PSND_MAX_LEFT2RIGHT_BITS (PSND_MAX_STEREO_BITS+1) #define PSND_MAX_LEFT2RIGHT (1 << PSND_MAX_LEFT2RIGHT_BITS) +#else +#define PSND_SILENCE 0 +#define PSND_MIN_VOLUME 0 +#define PSND_MAX_VOLUME 255 +#define PSND_NO_LOOP 0 +#define PSND_LOOP 1 +#define PSND_MAX_LEFT 0 +#define PSND_MAX_RIGHT 255 +#define PSND_MIDDLE 128 +#endif #define SSND_FADE_SOUND (1<<0) #define SSND_FADE_ALL_SOUNDS (1<<1) @@ -65,9 +79,6 @@ extern void ioctl(long, long, void *); #define SSND_STOPPING(x) (x & (SSND_STOP_SOUND | SSND_STOP_ALL_SOUNDS)) #define SSND_ALL(x) (x&(SSND_FADE_ALL_SOUNDS|SSND_STOP_ALL_SOUNDS)) -#define TRUE 1 -#define FALSE 0 - /* settings for sound path, sound device, etc. */ #ifndef SND_PATH #define SND_PATH "./sounds" @@ -108,11 +119,25 @@ struct SoundHeader_8SVX char magic_8SVX[4]; }; +struct SoundHeader_WAV +{ + char magic_RIFF[4]; + unsigned long header_size; + char magic_WAVE[4]; + char some_stuff[24]; + char magic_DATA[4]; + unsigned long data_size; +}; + struct SoundInfo { char *name; - char *file_ptr, *data_ptr; + byte *file_ptr; + byte *data_ptr; long file_len, data_len; +#ifdef MSDOS + SAMPLE *sample_ptr; +#endif }; struct SoundControl @@ -120,35 +145,29 @@ struct SoundControl int nr; int volume; int stereo; - BOOL active; - BOOL loop; - BOOL fade_sound; - BOOL stop_sound; - BOOL stop_all_sounds; + boolean active; + boolean loop; + boolean fade_sound; + boolean stop_sound; + boolean stop_all_sounds; int playingtime; long playingpos; long data_len; - char *data_ptr; + byte *data_ptr; +#ifdef MSDOS + int voice; +#endif }; -/* function from "misc.c" */ -unsigned long be2long(unsigned long *); - -/* sound server functions */ +/* start sound server */ void SoundServer(void); -void SoundServer_InsertNewSound(struct SoundControl); -void SoundServer_StopSound(int); -void SoundServer_StopAllSounds(void); -void HPUX_Audio_Control(void); -unsigned char linear_to_ulaw(int); -int ulaw_to_linear(unsigned char); - -/* application functions */ -BOOL LoadSound(struct SoundInfo *); + +/* client functions */ +boolean LoadSound(struct SoundInfo *); void PlaySound(int); void PlaySoundStereo(int, int); void PlaySoundLoop(int); -void PlaySoundExt(int, int, int, BOOL); +void PlaySoundExt(int, int, int, boolean); void FadeSound(int); void FadeSounds(void); void StopSound(int); diff --git a/src/tape.c b/src/tape.c new file mode 100644 index 00000000..2cc0b399 --- /dev/null +++ b/src/tape.c @@ -0,0 +1,254 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * +*----------------------------------------------------------* +* tape.c * +***********************************************************/ + +#include "tape.h" +#include "misc.h" +#include "game.h" +#include "buttons.h" + +void TapeStartRecording() +{ + time_t zeit1 = time(NULL); + struct tm *zeit2 = localtime(&zeit1); + int i; + + if (!TAPE_IS_STOPPED(tape)) + TapeStop(); + + tape.level_nr = level_nr; + tape.length = 0; + tape.counter = 0; + tape.pos[tape.counter].delay = 0; + tape.recording = TRUE; + tape.playing = FALSE; + tape.pausing = FALSE; + tape.changed = TRUE; + tape.date = 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday; + tape.random_seed = InitRND(NEW_RANDOMIZE); + + for(i=0; i= MAX_TAPELEN-1) + { + TapeStopRecording(); + return; + } + + for(i=0; i= MAX_TAPELEN) + { + TapeStopRecording(); + return; + } + + tape.pos[tape.counter].delay++; + + if (tape.pos[tape.counter].delay >= 255) + { + for(i=0; i= tape.length) + { + TapeStop(); + return(NULL); + } + + if (tape.delay_played == tape.pos[tape.counter].delay) + { + tape.delay_played = 0; + tape.counter++; + + for(i=0; i tape.length_seconds - PAUSE_SECONDS_BEFORE_DEATH) + { + TapeTogglePause(); + return(FALSE); + } + } + + if (tape.counter >= tape.length) + { + TapeStop(); + return(TRUE); + } + + if (tape.delay_played < tape.pos[tape.counter].delay) + { + tape.delay_played++; + return(TRUE); + } + else + return(FALSE); +} + +void TapeStop() +{ + TapeStopRecording(); + TapeStopPlaying(); + + DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); + if (tape.date && tape.length) + { + DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); + DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); + } +} + +void TapeErase() +{ + tape.length = 0; +} + +unsigned int GetTapeLength() +{ + unsigned int tape_length = 0; + int i; + + if (TAPE_IS_EMPTY(tape)) + return(0); + + for(i=0;i + #ifdef __FreeBSD__ #include #endif @@ -22,43 +23,125 @@ #include "sound.h" #include "misc.h" #include "buttons.h" -#include +#include "joystick.h" +#include "cartoons.h" +#include "network.h" + +#ifdef MSDOS +extern boolean wait_for_vsync; +#endif + +void SetDrawtoField(int mode) +{ + if (mode == DRAW_BUFFERED && setup.soft_scrolling) + { + FX = TILEX; + FY = TILEY; + BX1 = -1; + BY1 = -1; + BX2 = SCR_FIELDX; + BY2 = SCR_FIELDY; + redraw_x1 = 1; + redraw_y1 = 1; + + drawto_field = fieldbuffer; + } + else /* DRAW_DIRECT, DRAW_BACKBUFFER */ + { + FX = SX; + FY = SY; + BX1 = 0; + BY1 = 0; + BX2 = SCR_FIELDX - 1; + BY2 = SCR_FIELDY - 1; + redraw_x1 = 0; + redraw_y1 = 0; + + drawto_field = (mode == DRAW_DIRECT ? window : backbuffer); + } +} void BackToFront() { int x,y; + Drawable buffer = (drawto_field == window ? backbuffer : drawto_field); - if (direct_draw_on && game_status==PLAYING) + if (setup.direct_draw && game_status == PLAYING) redraw_mask &= ~REDRAW_MAIN; + if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD) + redraw_mask |= REDRAW_FIELD; + + if (redraw_mask & REDRAW_FIELD) + redraw_mask &= ~REDRAW_TILES; + + /* + if (redraw_mask & REDRAW_FIELD || + (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING)) + redraw_mask &= ~REDRAW_TILES; + */ + if (!redraw_mask) return; - if (redraw_mask & REDRAW_ALL || - (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)) + /* synchronize X11 graphics at this point; if we would synchronize the + display immediately after the buffer switching (after the XFlush), + this could mean that we have to wait for the graphics to complete, + although we could go on doing calculations for the next frame */ + + XSync(display, FALSE); + + /* +#ifdef MSDOS + wait_for_vsync = TRUE; +#endif + */ + + if (redraw_mask & REDRAW_ALL) { XCopyArea(display,backbuffer,window,gc, 0,0, WIN_XSIZE,WIN_YSIZE, 0,0); redraw_mask = 0; } - else if (redraw_mask & REDRAW_FIELD) + + if (redraw_mask & REDRAW_FIELD) { - XCopyArea(display,backbuffer,window,gc, - REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, - REAL_SX,REAL_SY); + if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER) + XCopyArea(display,backbuffer,window,gc, + REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, + REAL_SX,REAL_SY); + else + { + int fx = FX, fy = FY; + + if (setup.soft_scrolling) + { + fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0); + fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0); + } + + if (setup.soft_scrolling || + ABS(ScreenGfxPos) + ScrollStepSize == TILEX || + ABS(ScreenGfxPos) == ScrollStepSize || + redraw_tiles > REDRAWTILES_THRESHOLD) + XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY); + } redraw_mask &= ~REDRAW_MAIN; } - else if (redraw_mask & REDRAW_DOORS) + + if (redraw_mask & REDRAW_DOORS) { if (redraw_mask & REDRAW_DOOR_1) XCopyArea(display,backbuffer,window,gc, - DX,DY, DXSIZE,DYSIZE, DX,DY); + DX,DY, DXSIZE,DYSIZE, + DX,DY); if (redraw_mask & REDRAW_DOOR_2) { if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2) XCopyArea(display,backbuffer,window,gc, - VX,VY, VXSIZE,VYSIZE, VX,VY); + VX,VY, VXSIZE,VYSIZE, + VX,VY); else { if (redraw_mask & REDRAW_VIDEO_1) @@ -94,31 +177,31 @@ void BackToFront() if (redraw_mask & REDRAW_TILES) { - if (redraw_tiles>REDRAWTILES_TH) - XCopyArea(display,backbuffer,window,gc,SX,SY,SXSIZE,SYSIZE,SX,SY); - else - for(x=0;xFC_SPECIAL2) - font_color = FC_RED; - - font_width = - (font==FS_BIG ? FONT1_XSIZE : - font_color FC_SPECIAL2) + font_type = FC_RED; + + font_width = (font_size == FS_BIG ? FONT1_XSIZE : + font_type < FC_SPECIAL1 ? FONT2_XSIZE : + font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE); + font_height = (font_size == FS_BIG ? FONT1_XSIZE : + font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE); + font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT); + font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) * + FONT_LINES_PER_FONT); while(*text) { char c = *text++; - if (c>='a' && c<='z') + if (c >= 'a' && c <= 'z') c = 'A' + (c - 'a'); - else if (c=='ä' || c=='Ä') + else if (c == 'ä' || c == 'Ä') c = 91; - else if (c=='ö' || c=='Ö') + else if (c == 'ö' || c == 'Ö') c = 92; - else if (c=='ü' || c=='Ü') + else if (c == 'ü' || c == 'Ü') c = 93; - if (c>=32 && c<=95) - XCopyArea(display,pix[font_pixmap],d,gc, - ((c-32) % FONT_CHARS_PER_LINE)*font_width, - ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start, - font_width,font_height, x,y); + if (c >= 32 && c <= 95) + XCopyArea(display, pix[font_pixmap], d, gc, + ((c - 32) % FONT_CHARS_PER_LINE) * font_width, + ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start, + font_width, font_height, x, y); x += font_width; } } -void DrawGraphic(int x, int y, int graphic) +void DrawAllPlayers() { - DrawGraphicExt(drawto_field, gc, x, y, graphic); - redraw_tiles++; - redraw[x][y] = TRUE; - redraw_mask |= REDRAW_TILES; + int i; + + for(i=0; ijx, jy = player->jy; + int last_jx = player->last_jx, last_jy = player->last_jy; + int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy); + int sx = SCREENX(jx), sy = SCREENY(jy); + int sxx = 0, syy = 0; + int element = Feld[jx][jy]; + int graphic, phase; + + if (!player->active || player->gone || + !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy))) + return; + +#if DEBUG + if (!IN_LEV_FIELD(jx,jy)) + { + printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy); + printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy); + printf("DrawPlayerField(): This should never happen!\n"); + return; + } +#endif + + if (element == EL_EXPLODING) + return; + + /* draw things in the field the player is leaving, if needed */ + + if (last_jx != jx || last_jy != jy) + { + if (Store[last_jx][last_jy]) + { + DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]); + DrawLevelFieldThruMask(last_jx, last_jy); + } + else if (Feld[last_jx][last_jy] == EL_DYNAMIT) + DrawDynamite(last_jx, last_jy); + else + DrawLevelField(last_jx, last_jy); + + if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy))) + { + if (player->GfxPos) + { + if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL) + DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER); + else + DrawLevelElement(next_jx, next_jy, EL_LEERRAUM); + } + else + DrawLevelField(next_jx, next_jy); + } + } + + if (!IN_SCR_FIELD(sx, sy)) + return; + + if (setup.direct_draw) + SetDrawtoField(DRAW_BUFFERED); + + /* draw things behind the player, if needed */ + + if (Store[jx][jy]) + DrawLevelElement(jx, jy, Store[jx][jy]); + else if (element != EL_DYNAMIT && element != EL_DYNABOMB) + DrawLevelField(jx, jy); + + /* draw player himself */ + + if (player->MovDir == MV_LEFT) + graphic = (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT); + else if (player->MovDir == MV_RIGHT) + graphic = (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT); + else if (player->MovDir == MV_UP) + graphic = GFX_SPIELER1_UP; + else /* MV_DOWN || MV_NO_MOVING */ + graphic = GFX_SPIELER1_DOWN; + + graphic += player->index_nr * 3*HEROES_PER_LINE; + graphic += player->Frame; + + if (player->GfxPos) { - graphic -= 256; - XCopyArea(display,pix[PIX_BIGFONT],d,gc, - (graphic % FONT_CHARS_PER_LINE)*TILEX, - (graphic / FONT_CHARS_PER_LINE)*TILEY + - FC_SPECIAL1*TILEY*FONT_LINES_PER_FONT, - TILEX,TILEY, x,y); + if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT) + sxx = player->GfxPos; + else + syy = player->GfxPos; } + + if (!setup.soft_scrolling && ScreenMovPos) + sxx = syy = 0; + + DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING); + + if (player->Pushing && player->GfxPos) + { + int px = SCREENX(next_jx), py = SCREENY(next_jy); + + if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER || + Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL) + DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT, + NO_CUTTING); + else + { + int element = Feld[next_jx][next_jy]; + int graphic = el2gfx(element); + + if (element == EL_FELSBROCKEN && sxx) + { + int phase = (player->GfxPos / (TILEX/4)); + + if (player->MovDir == MV_LEFT) + graphic += phase; + else + graphic += (phase+4)%4; + } + + DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING); + } + } + + /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */ + + if (element == EL_DYNAMIT || element == EL_DYNABOMB) + { + graphic = el2gfx(element); + + if (element == EL_DYNAMIT) + { + if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6) + phase = 6; + } + else + { + if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3) + phase = 7 - phase; + } + + DrawGraphicThruMask(sx, sy, graphic + phase); + } + + if ((last_jx != jx || last_jy != jy) && + Feld[last_jx][last_jy] == EL_EXPLODING) + { + int phase = Frame[last_jx][last_jy]; + int delay = 2; + + if (phase > 2) + DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), + GFX_EXPLOSION + ((phase - 1) / delay - 1)); + } + + if (setup.direct_draw) + { + int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX; + int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY; + int x_size = TILEX * (1 + ABS(jx - last_jx)); + int y_size = TILEY * (1 + ABS(jy - last_jy)); + + XCopyArea(display, drawto_field, window, gc, + dest_x, dest_y, x_size, y_size, dest_x, dest_y); + SetDrawtoField(DRAW_DIRECT); + } + + MarkTileDirty(sx,sy); } -void DrawGraphicThruMask(int x, int y, int graphic) +static int getGraphicAnimationPhase(int frames, int delay, int mode) { - int src_x,src_y, dest_x,dest_y; + int phase; - if (graphic<0 || graphic>255) + if (mode == ANIM_OSCILLATE) { - DrawGraphic(x,y,graphic); - return; + int max_anim_frames = 2 * frames - 2; + phase = (FrameCounter % (delay * max_anim_frames)) / delay; + phase = (phase < frames ? phase : max_anim_frames - phase); } + else + phase = (FrameCounter % (delay * frames)) / delay; - src_x = SX+(graphic % GFX_PER_LINE)*TILEX; - src_y = SY+(graphic / GFX_PER_LINE)*TILEY; - dest_x = SX+x*TILEX; - dest_y = SY+y*TILEY; + if (mode == ANIM_REVERSE) + phase = -phase; - XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y); - XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK], src_x,src_y, - TILEX,TILEY, dest_x,dest_y); + return(phase); +} - redraw_tiles++; - redraw[x][y]=TRUE; - redraw_mask|=REDRAW_TILES; +void DrawGraphicAnimationExt(int x, int y, int graphic, + int frames, int delay, int mode, int mask_mode) +{ + int phase = getGraphicAnimationPhase(frames, delay, mode); + + if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + if (mask_mode == USE_MASKING) + DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase); + else + DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase); + } } -void DrawElementThruMask(int x, int y, int element) +void DrawGraphicAnimation(int x, int y, int graphic, + int frames, int delay, int mode) { - DrawGraphicThruMask(x,y,el2gfx(element)); + DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING); } -void DrawMiniGraphic(int x, int y, int graphic) +void DrawGraphicAnimationThruMask(int x, int y, int graphic, + int frames, int delay, int mode) { - DrawMiniGraphicExt(drawto, gc, x, y, graphic); - redraw_tiles++; - redraw[x/2][y/2]=TRUE; - redraw_mask|=REDRAW_TILES; + DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING); } -void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic) +void DrawGraphic(int x, int y, int graphic) +{ +#if DEBUG + if (!IN_SCR_FIELD(x,y)) + { + printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic); + printf("DrawGraphic(): This should never happen!\n"); + return; + } +#endif + + DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic); + MarkTileDirty(x,y); +} + +void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic) +{ + if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN) + { + graphic -= GFX_START_ROCKSSCREEN; + XCopyArea(display, pix[PIX_BACK], d, gc, + SX + (graphic % GFX_PER_LINE) * TILEX, + SY + (graphic / GFX_PER_LINE) * TILEY, + TILEX, TILEY, x, y); + } + else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES) + { + graphic -= GFX_START_ROCKSHEROES; + XCopyArea(display, pix[PIX_HEROES], d, gc, + (graphic % HEROES_PER_LINE) * TILEX, + (graphic / HEROES_PER_LINE) * TILEY, + TILEX, TILEY, x, y); + } + else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT) + { + graphic -= GFX_START_ROCKSFONT; + XCopyArea(display, pix[PIX_BIGFONT], d, gc, + (graphic % FONT_CHARS_PER_LINE) * TILEX, + (graphic / FONT_CHARS_PER_LINE) * TILEY + + FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY, + TILEX, TILEY, x, y); + } + else + XFillRectangle(display, d, gc, x, y, TILEX, TILEY); +} + +void DrawGraphicThruMask(int x, int y, int graphic) { - DrawMiniGraphicExtHiRes(d,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic); +#if DEBUG + if (!IN_SCR_FIELD(x,y)) + { + printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic); + printf("DrawGraphicThruMask(): This should never happen!\n"); + return; + } +#endif + + DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic); + MarkTileDirty(x,y); } -void DrawMiniGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic) +void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic) { - if (graphic<0) - XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY); - else if (graphic<256) - XCopyArea(display,pix[PIX_BACK],d,gc, - MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX, - MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY, - MINI_TILEX,MINI_TILEY, x,y); + int src_x, src_y; + int tile = graphic; + Pixmap src_pixmap; + GC drawing_gc; + + if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN) + { + src_pixmap = pix[PIX_BACK]; + drawing_gc = clip_gc[PIX_BACK]; + graphic -= GFX_START_ROCKSSCREEN; + src_x = SX + (graphic % GFX_PER_LINE) * TILEX; + src_y = SY + (graphic / GFX_PER_LINE) * TILEY; + } + else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES) + { + src_pixmap = pix[PIX_HEROES]; + drawing_gc = clip_gc[PIX_HEROES]; + graphic -= GFX_START_ROCKSHEROES; + src_x = (graphic % HEROES_PER_LINE) * TILEX; + src_y = (graphic / HEROES_PER_LINE) * TILEY; + } else { - graphic -= 256; - XCopyArea(display,pix[PIX_SMALLFONT],d,gc, - (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE, - (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE + - FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT, - MINI_TILEX,MINI_TILEY, x,y); + DrawGraphicExt(d, gc, dest_x,dest_y, graphic); + return; + } + + if (tile_clipmask[tile] != None) + { + XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]); + XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y); + XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc, + src_x, src_y, TILEX, TILEY, dest_x, dest_y); + } + else + { +#if DEBUG + printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile); +#endif + + XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y); + XCopyArea(display, src_pixmap, drawto_field, drawing_gc, + src_x, src_y, TILEX, TILEY, dest_x, dest_y); + } +} + +void DrawMiniGraphic(int x, int y, int graphic) +{ + DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic); + MarkTileDirty(x/2, y/2); +} + +void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic) +{ + if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN) + { + graphic -= GFX_START_ROCKSSCREEN; + XCopyArea(display, pix[PIX_BACK], d, gc, + MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX, + MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY, + MINI_TILEX, MINI_TILEY, x, y); + } + else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT) + { + graphic -= GFX_START_ROCKSFONT; + XCopyArea(display, pix[PIX_SMALLFONT], d, gc, + (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE, + (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE + + FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT, + MINI_TILEX, MINI_TILEY, x, y); } + else + XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY); } -void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode) +void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, + int cut_mode, int mask_mode) { int width = TILEX, height = TILEY; int cx = 0, cy = 0; + int src_x, src_y, dest_x, dest_y; + int tile = graphic; + Pixmap src_pixmap; + GC drawing_gc; - if (graphic<0) + if (graphic < 0) { - DrawGraphic(x,y,graphic); + DrawGraphic(x, y, graphic); return; } if (dx || dy) /* Verschiebung der Grafik? */ { - if (x<0) /* Element kommt von links ins Bild */ + if (x < BX1) /* Element kommt von links ins Bild */ { - x=0; - width=dx; - cx=TILEX-dx; - dx=0; + x = BX1; + width = dx; + cx = TILEX - dx; + dx = 0; } - else if (x==SCR_FIELDX) /* Element kommt von rechts ins Bild */ + else if (x > BX2) /* Element kommt von rechts ins Bild */ { - x=SCR_FIELDX-1; - width=-dx; - dx=TILEX+dx; + x = BX2; + width = -dx; + dx = TILEX + dx; } - else if (x==0 && dx<0) /* Element verläßt links das Bild */ + else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */ { - width+=dx; - cx=-dx; - dx=0; + width += dx; + cx = -dx; + dx = 0; } - else if (x==SCR_FIELDX-1 && dx>0) /* El. verläßt rechts das Bild */ - width-=dx; + else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */ + width -= dx; else if (dx) /* allg. Bewegung in x-Richtung */ - redraw[x+SIGN(dx)][y]=TRUE; + MarkTileDirty(x + SIGN(dx), y); - if (y<0) /* Element kommt von oben ins Bild */ + if (y < BY1) /* Element kommt von oben ins Bild */ { if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */ return; - y=0; - height=dy; - cy=TILEY-dy; - dy=0; + y = BY1; + height = dy; + cy = TILEY - dy; + dy = 0; } - else if (y==SCR_FIELDY) /* Element kommt von unten ins Bild */ + else if (y > BY2) /* Element kommt von unten ins Bild */ { - y=SCR_FIELDY-1; - height=-dy; - dy=TILEY+dy; + y = BY2; + height = -dy; + dy = TILEY + dy; } - else if (y==0 && dy<0) /* Element verläßt oben das Bild */ + else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */ { - height+=dy; - cy=-dy; - dy=0; + height += dy; + cy = -dy; + dy = 0; } - else if (dy>0 && cut_mode==CUT_ABOVE) + else if (dy > 0 && cut_mode == CUT_ABOVE) { - if (y==SCR_FIELDY-1) /* Element unterhalb des Bildes */ + if (y == BY2) /* Element unterhalb des Bildes */ return; - height=dy; - cy=TILEY-dy; - dy=TILEY; - redraw[x][y+1]=TRUE; + height = dy; + cy = TILEY - dy; + dy = TILEY; + MarkTileDirty(x, y + 1); } /* Element verläßt unten das Bild */ - else if (dy>0 && (y==SCR_FIELDY-1 || cut_mode==CUT_BELOW)) - height-=dy; + else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW)) + height -= dy; else if (dy) /* allg. Bewegung in y-Richtung */ - redraw[x][y+SIGN(dy)]=TRUE; + MarkTileDirty(x, y + SIGN(dy)); } - XCopyArea(display,pix[PIX_BACK],drawto_field,gc, - SX+(graphic % GFX_PER_LINE)*TILEX+cx, - SY+(graphic / GFX_PER_LINE)*TILEY+cy, - width,height, SX+x*TILEX+dx,SY+y*TILEY+dy); + if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN) + { + src_pixmap = pix[PIX_BACK]; + drawing_gc = clip_gc[PIX_BACK]; + graphic -= GFX_START_ROCKSSCREEN; + src_x = SX + (graphic % GFX_PER_LINE) * TILEX + cx; + src_y = SY + (graphic / GFX_PER_LINE) * TILEY + cy; + } + else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES) + { + src_pixmap = pix[PIX_HEROES]; + drawing_gc = clip_gc[PIX_HEROES]; + graphic -= GFX_START_ROCKSHEROES; + src_x = (graphic % HEROES_PER_LINE) * TILEX + cx; + src_y = (graphic / HEROES_PER_LINE) * TILEY + cy; + } + else /* big font graphics currently not allowed (and not needed) */ + return; + + dest_x = FX + x * TILEX + dx; + dest_y = FY + y * TILEY + dy; - redraw_tiles++; - redraw[x][y]=TRUE; - redraw_mask|=REDRAW_TILES; +#if DEBUG + if (!IN_SCR_FIELD(x,y)) + { + printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic); + printf("DrawGraphicShifted(): This should never happen!\n"); + return; + } +#endif + + if (mask_mode == USE_MASKING) + { + if (tile_clipmask[tile] != None) + { + XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]); + XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y); + XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc, + src_x, src_y, TILEX, TILEY, dest_x, dest_y); + } + else + { +#if DEBUG + printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile); +#endif + + XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y); + XCopyArea(display, src_pixmap, drawto_field, drawing_gc, + src_x, src_y, width, height, dest_x, dest_y); + } + } + else + XCopyArea(display, src_pixmap, drawto_field, gc, + src_x, src_y, width, height, dest_x, dest_y); + + MarkTileDirty(x,y); +} + +void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic, + int cut_mode) +{ + DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING); } -void DrawElementShifted(int x, int y, int dx, int dy, int element,int cut_mode) +void DrawScreenElementExt(int x, int y, int dx, int dy, int element, + int cut_mode, int mask_mode) { - int ux = UNSCROLLX(x), uy = UNSCROLLY(y); + int ux = LEVELX(x), uy = LEVELY(y); int graphic = el2gfx(element); - int phase = ABS(MovPos[ux][uy])/(TILEX/2); + int phase4 = ABS(MovPos[ux][uy]) / (TILEX / 4); + int phase = phase4 / 2; int dir = MovDir[ux][uy]; - int horiz_move = (dir==MV_LEFT || dir==MV_RIGHT); - if (element==EL_PACMAN || - element==EL_KAEFER || - element==EL_FLIEGER) + if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER) { - if (element==EL_PACMAN) - graphic = GFX_PACMAN + 4*!phase; - else - graphic += 4*!phase; + graphic += 4*!phase; - if (dir==MV_UP) + if (dir == MV_UP) graphic += 1; - else if (dir==MV_LEFT) + else if (dir == MV_LEFT) graphic += 2; - else if (dir==MV_DOWN) + else if (dir == MV_DOWN) graphic += 3; } - else if ((element==EL_FELSBROCKEN || - element==EL_EDELSTEIN || - element==EL_DIAMANT) && horiz_move && phase) + else if (element == EL_MAULWURF || element == EL_PINGUIN || + element == EL_SCHWEIN || element == EL_DRACHE) { - if (element==EL_FELSBROCKEN) - graphic += 2; + if (dir == MV_LEFT) + graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT : + element == EL_PINGUIN ? GFX_PINGUIN_LEFT : + element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT); + else if (dir == MV_RIGHT) + graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT : + element == EL_PINGUIN ? GFX_PINGUIN_RIGHT : + element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT); + else if (dir == MV_UP) + graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP : + element == EL_PINGUIN ? GFX_PINGUIN_UP : + element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP); else - graphic += 1; + graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN : + element == EL_PINGUIN ? GFX_PINGUIN_DOWN : + element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN); + + graphic += phase4; } - else if ((element==EL_SIEB_LEER || - element==EL_SIEB_VOLL) && SiebAktiv) + else if (element == EL_SONDE) { - graphic += 3-(SiebAktiv%8)/2; + graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL); + } + else if (element == EL_SALZSAEURE) + { + graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL); + } + else if (element == EL_BUTTERFLY || element == EL_FIREFLY) + { + graphic += !phase; + } + else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode) + { + graphic += phase * (element == EL_FELSBROCKEN ? 2 : 1); + } + else if ((element == EL_SIEB_LEER || element == EL_SIEB2_LEER || + element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL) && SiebAktiv) + { + graphic += 3 - (SiebAktiv % 8) / 2; } else if (IS_AMOEBOID(element)) { - graphic = (element==EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT); - graphic += (x+2*y) % 4; + graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT); + graphic += (x + 2 * y + 4) % 4; + } + else if (element == EL_MAUER_LEBT) + { + boolean links_massiv = FALSE, rechts_massiv = FALSE; + + if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy])) + links_massiv = TRUE; + if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy])) + rechts_massiv = TRUE; + + if (links_massiv && rechts_massiv) + graphic = GFX_MAUERWERK; + else if (links_massiv) + graphic = GFX_MAUER_R; + else if (rechts_massiv) + graphic = GFX_MAUER_L; } if (dx || dy) - DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode); + DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode); + else if (mask_mode == USE_MASKING) + DrawGraphicThruMask(x, y, graphic); else - DrawGraphic(x,y, graphic); + DrawGraphic(x, y, graphic); +} + +void DrawLevelElementExt(int x, int y, int dx, int dy, int element, + int cut_mode, int mask_mode) +{ + if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element, + cut_mode, mask_mode); +} + +void DrawScreenElementShifted(int x, int y, int dx, int dy, int element, + int cut_mode) +{ + DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING); +} + +void DrawLevelElementShifted(int x, int y, int dx, int dy, int element, + int cut_mode) +{ + DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING); +} + +void DrawScreenElementThruMask(int x, int y, int element) +{ + DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); +} + +void DrawLevelElementThruMask(int x, int y, int element) +{ + DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); +} + +void DrawLevelFieldThruMask(int x, int y) +{ + DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING); } void ErdreichAnbroeckeln(int x, int y) { int i, width, height, cx,cy; - int ux = UNSCROLLX(x), uy = UNSCROLLY(y); + int ux = LEVELX(x), uy = LEVELY(y); int element, graphic; int snip = 4; static int xy[4][2] = { - 0,-1, - -1,0, - +1,0, - 0,+1 + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } }; - if (!IN_LEV_FIELD(ux,uy)) + if (!IN_LEV_FIELD(ux, uy)) return; element = Feld[ux][uy]; - if (element==EL_ERDREICH) + if (element == EL_ERDREICH) { - if (!IN_SCR_FIELD(x,y)) + if (!IN_SCR_FIELD(x, y)) return; graphic = GFX_ERDENRAND; - for(i=0;i<4;i++) + for(i=0; i<4; i++) { - int uxx,uyy; + int uxx, uyy; - uxx = ux+xy[i][0]; - uyy = uy+xy[i][1]; - if (!IN_LEV_FIELD(uxx,uyy)) + uxx = ux + xy[i][0]; + uyy = uy + xy[i][1]; + if (!IN_LEV_FIELD(uxx, uyy)) element = EL_BETON; else element = Feld[uxx][uyy]; -/* - if (element==EL_ERDREICH || IS_SOLID(element)) - continue; -*/ - if (element==EL_ERDREICH) + if (element == EL_ERDREICH) continue; - if (i==1 || i==2) + if (i == 1 || i == 2) { width = snip; height = TILEY; - cx = (i==2 ? TILEX-snip : 0); + cx = (i == 2 ? TILEX - snip : 0); cy = 0; } else @@ -533,45 +1059,39 @@ void ErdreichAnbroeckeln(int x, int y) width = TILEX; height = snip; cx = 0; - cy = (i==3 ? TILEY-snip : 0); + cy = (i == 3 ? TILEY - snip : 0); } - XCopyArea(display,pix[PIX_BACK],drawto_field,gc, - SX+(graphic % GFX_PER_LINE)*TILEX+cx, - SY+(graphic / GFX_PER_LINE)*TILEY+cy, - width,height, SX+x*TILEX+cx,SY+y*TILEY+cy); + XCopyArea(display, pix[PIX_BACK], drawto_field, gc, + SX + (graphic % GFX_PER_LINE) * TILEX + cx, + SY + (graphic / GFX_PER_LINE) * TILEY + cy, + width, height, FX + x * TILEX + cx, FY + y * TILEY + cy); } - redraw_tiles++; - redraw[x][y]=TRUE; + MarkTileDirty(x, y); } else { graphic = GFX_ERDENRAND; - for(i=0;i<4;i++) + for(i=0; i<4; i++) { - int xx,yy,uxx,uyy; + int xx, yy, uxx, uyy; - xx = x+xy[i][0]; - yy = y+xy[i][1]; - uxx = ux+xy[i][0]; - uyy = uy+xy[i][1]; -/* - if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH || - !IN_SCR_FIELD(xx,yy) || IS_SOLID(element)) - continue; -*/ + xx = x + xy[i][0]; + yy = y + xy[i][1]; + uxx = ux + xy[i][0]; + uyy = uy + xy[i][1]; - if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH || - !IN_SCR_FIELD(xx,yy)) + if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH || + !IN_SCR_FIELD(xx, yy)) continue; - if (i==1 || i==2) + if (i == 1 || i == 2) { width = snip; height = TILEY; - cx = (i==1 ? TILEX-snip : 0); + cx = (i == 1 ? TILEX - snip : 0); cy = 0; } else @@ -582,116 +1102,121 @@ void ErdreichAnbroeckeln(int x, int y) cy = (i==0 ? TILEY-snip : 0); } - XCopyArea(display,pix[PIX_BACK],drawto_field,gc, - SX+(graphic % GFX_PER_LINE)*TILEX+cx, - SY+(graphic / GFX_PER_LINE)*TILEY+cy, - width,height, SX+xx*TILEX+cx,SY+yy*TILEY+cy); + XCopyArea(display, pix[PIX_BACK], drawto_field, gc, + SX + (graphic % GFX_PER_LINE) * TILEX + cx, + SY + (graphic / GFX_PER_LINE) * TILEY + cy, + width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy); - redraw_tiles++; - redraw[xx][yy]=TRUE; + MarkTileDirty(xx, yy); } } } void DrawScreenElement(int x, int y, int element) { - DrawElementShifted(x,y,0,0,element,CUT_NO_CUTTING); - ErdreichAnbroeckeln(x,y); + DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING); + ErdreichAnbroeckeln(x, y); } void DrawLevelElement(int x, int y, int element) { - if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawScreenElement(SCROLLX(x),SCROLLY(y),element); + if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawScreenElement(SCREENX(x), SCREENY(y), element); } void DrawScreenField(int x, int y) { - int ux = UNSCROLLX(x), uy = UNSCROLLY(y); + int ux = LEVELX(x), uy = LEVELY(y); int element; - if (!IN_LEV_FIELD(ux,uy)) + if (!IN_LEV_FIELD(ux, uy)) { - DrawScreenElement(x,y,EL_BETON); + DrawScreenElement(x, y, EL_BETON); return; } element = Feld[ux][uy]; - if (IS_MOVING(ux,uy)) + if (IS_MOVING(ux, uy)) { - int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT); - BOOL cut_mode = CUT_NO_CUTTING; + int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT); + boolean cut_mode = NO_CUTTING; - if (Store[ux][uy]==EL_MORAST_LEER || - Store[ux][uy]==EL_SIEB_LEER || - Store[ux][uy]==EL_AMOEBE_NASS) + if (Store[ux][uy] == EL_MORAST_LEER || + Store[ux][uy] == EL_SIEB_LEER || + Store[ux][uy] == EL_SIEB2_LEER || + Store[ux][uy] == EL_AMOEBE_NASS) cut_mode = CUT_ABOVE; - else if (Store[ux][uy]==EL_MORAST_VOLL || - Store[ux][uy]==EL_SIEB_VOLL || - Store[ux][uy]==EL_SALZSAEURE) + else if (Store[ux][uy] == EL_MORAST_VOLL || + Store[ux][uy] == EL_SIEB_VOLL || + Store[ux][uy] == EL_SIEB2_VOLL) cut_mode = CUT_BELOW; - if (cut_mode==CUT_ABOVE) - DrawElementShifted(x,y,0,0,Store[ux][uy],CUT_NO_CUTTING); + if (cut_mode == CUT_ABOVE) + DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING); else - DrawScreenElement(x,y,EL_LEERRAUM); + DrawScreenElement(x, y, EL_LEERRAUM); if (horiz_move) - DrawElementShifted(x,y,MovPos[ux][uy],0,element,CUT_NO_CUTTING); + DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING); else - DrawElementShifted(x,y,0,MovPos[ux][uy],element,cut_mode); + DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode); + + if (Store[ux][uy] == EL_SALZSAEURE) + DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE); } - else if (IS_BLOCKED(ux,uy)) + else if (IS_BLOCKED(ux, uy)) { - int oldx,oldy; + int oldx, oldy; int sx, sy; int horiz_move; - BOOL cut_mode = CUT_NO_CUTTING; - - Blocked2Moving(ux,uy,&oldx,&oldy); - sx = SCROLLX(oldx); - sy = SCROLLY(oldy); - horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT); - - if (Store[oldx][oldy]==EL_MORAST_LEER || - Store[oldx][oldy]==EL_SIEB_LEER || - Store[oldx][oldy]==EL_AMOEBE_NASS) + boolean cut_mode = NO_CUTTING; + + Blocked2Moving(ux, uy, &oldx, &oldy); + sx = SCREENX(oldx); + sy = SCREENY(oldy); + horiz_move = (MovDir[oldx][oldy] == MV_LEFT || + MovDir[oldx][oldy] == MV_RIGHT); + + if (Store[oldx][oldy] == EL_MORAST_LEER || + Store[oldx][oldy] == EL_SIEB_LEER || + Store[oldx][oldy] == EL_SIEB2_LEER || + Store[oldx][oldy] == EL_AMOEBE_NASS) cut_mode = CUT_ABOVE; - DrawScreenElement(x,y,EL_LEERRAUM); + DrawScreenElement(x, y, EL_LEERRAUM); element = Feld[oldx][oldy]; if (horiz_move) - DrawElementShifted(sx,sy,MovPos[oldx][oldy],0,element,CUT_NO_CUTTING); + DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING); else - DrawElementShifted(sx,sy,0,MovPos[oldx][oldy],element,cut_mode); + DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode); } else if (IS_DRAWABLE(element)) - DrawScreenElement(x,y,element); + DrawScreenElement(x, y, element); else - DrawScreenElement(x,y,EL_LEERRAUM); + DrawScreenElement(x, y, EL_LEERRAUM); } void DrawLevelField(int x, int y) { - if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y))) - DrawScreenField(SCROLLX(x),SCROLLY(y)); - else if (IS_MOVING(x,y)) + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawScreenField(SCREENX(x), SCREENY(y)); + else if (IS_MOVING(x, y)) { int newx,newy; - Moving2Blocked(x,y,&newx,&newy); - if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy))) - DrawScreenField(SCROLLX(newx),SCROLLY(newy)); + Moving2Blocked(x, y, &newx, &newy); + if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) + DrawScreenField(SCREENX(newx), SCREENY(newy)); } - else if (IS_BLOCKED(x,y)) + else if (IS_BLOCKED(x, y)) { - int oldx,oldy; + int oldx, oldy; - Blocked2Moving(x,y,&oldx,&oldy); - if (IN_SCR_FIELD(SCROLLX(oldx),SCROLLY(oldy))) - DrawScreenField(SCROLLX(oldx),SCROLLY(oldy)); + Blocked2Moving(x, y, &oldx, &oldy); + if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy))) + DrawScreenField(SCREENX(oldx), SCREENY(oldy)); } } @@ -701,43 +1226,39 @@ void DrawMiniElement(int x, int y, int element) if (!element) { - DrawMiniGraphic(x,y,-1); + DrawMiniGraphic(x, y, -1); return; } graphic = el2gfx(element); - DrawMiniGraphic(x,y,graphic); - - redraw_tiles++; - redraw[x/2][y/2]=TRUE; - redraw_mask|=REDRAW_TILES; + DrawMiniGraphic(x, y, graphic); } -void DrawMiniElementOrWall(int x, int y, int scroll_x, int scroll_y) +void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y) { - if (x+scroll_x<-1 || x+scroll_x>lev_fieldx || - y+scroll_y<-1 || y+scroll_y>lev_fieldy) - DrawMiniElement(x,y,EL_LEERRAUM); - else if (x+scroll_x==-1 || x+scroll_x==lev_fieldx || - y+scroll_y==-1 || y+scroll_y==lev_fieldy) - DrawMiniElement(x,y,EL_BETON); + int x = sx + scroll_x, y = sy + scroll_y; + + if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy) + DrawMiniElement(sx, sy, EL_LEERRAUM); + else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy) + DrawMiniElement(sx, sy, EL_BETON); else - DrawMiniElement(x,y,Feld[x+scroll_x][y+scroll_y]); + DrawMiniElement(sx, sy, Feld[x][y]); } void DrawMicroElement(int xpos, int ypos, int element) { int graphic; - if (element==EL_LEERRAUM) + if (element == EL_LEERRAUM) return; graphic = el2gfx(element); - XCopyArea(display,pix[PIX_BACK],drawto,gc, - MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX, - MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY, - MICRO_TILEX,MICRO_TILEY, xpos,ypos); + XCopyArea(display, pix[PIX_BACK], drawto, gc, + MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX, + MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY, + MICRO_TILEX, MICRO_TILEY, xpos, ypos); } void DrawLevel() @@ -746,11 +1267,15 @@ void DrawLevel() ClearWindow(); - for(x=0;x=0 && x=0 && y=-1 && x=-1 && y= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy) + DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY, + Ur[x][y]); + else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1) + DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY, EL_BETON); - XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE); + XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE); if (level.name) { int len = strlen(level.name); - int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2; + int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2; int lypos = MICROLABEL_YPOS; - DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2); + DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2); } redraw_mask |= REDRAW_MICROLEV; } -int AYS_in_range(int x, int y) +int REQ_in_range(int x, int y) { - if (y>DY+249 && y DY+249 && y < DY+278) { - if (x>DX+1 && xDX+51 && x DX+1 && x < DX+48) + return 1; + else if (x > DX+51 && x < DX+98) + return 2; } - return(0); + return 0; } -BOOL AreYouSure(char *text, unsigned int ays_state) +boolean Request(char *text, unsigned int req_state) { - int mx,my, ty, result = -1; + int mx, my, ty, result = -1; + unsigned int old_door_state; + +#ifndef MSDOS + /* pause network game while waiting for request to answer */ + if (options.network && + game_status == PLAYING && + req_state & REQUEST_WAIT_FOR) + SendToServer_PausePlaying(); +#endif + + old_door_state = GetDoorState(); CloseDoor(DOOR_CLOSE_1); /* Alten Türinhalt sichern */ - XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE, - DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1); + XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, + DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1); /* Fragetext schreiben */ - XFillRectangle(display,pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE); + XFillRectangle(display, pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE); - for(ty=0;ty<13;ty++) + for(ty=0; ty<13; ty++) { - int tx,tl,tc; + int tx, tl, tc; char txt[256]; - if (!(*text)) + if (!*text) break; - for(tl=0,tx=0;tx<7;tl++,tx++) + + for(tl=0,tx=0; tx<7; tl++,tx++) { - tc=*(text+tx); - if (!tc || tc==32) + tc = *(text + tx); + if (!tc || tc == 32) break; } if (!tl) @@ -844,59 +1385,59 @@ BOOL AreYouSure(char *text, unsigned int ays_state) ty--; continue; } - sprintf(txt,text); - txt[tl]=0; - DrawTextExt(pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW); - text+=(tl+(tc==32)); - } - - if (ays_state & AYS_ASK) - XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS, - DXSIZE,OK_BUTTON_YSIZE, - DOOR_GFX_PAGEX1,OK_BUTTON_YPOS); - else if (ays_state & AYS_CONFIRM) - XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS, - DXSIZE,CONFIRM_BUTTON_YSIZE, - DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS); + sprintf(txt, text); + txt[tl] = 0; + DrawTextExt(pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16, + txt, FS_SMALL, FC_YELLOW); + text += tl + (tc == 32 ? 1 : 0); + } + + if (req_state & REQ_ASK) + { + DrawYesNoButton(BUTTON_OK, DB_INIT); + DrawYesNoButton(BUTTON_NO, DB_INIT); + } + else if (req_state & REQ_CONFIRM) + { + DrawConfirmButton(BUTTON_CONFIRM, DB_INIT); + } + else if (req_state & REQ_PLAYER) + { + DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT); + DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT); + DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT); + DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT); + } OpenDoor(DOOR_OPEN_1); + ClearEventQueue(); - if (!(ays_state & AYS_ASK) && !(ays_state & AYS_CONFIRM)) + if (!(req_state & REQUEST_WAIT_FOR)) return(FALSE); - if (game_status!=MAINMENU) + if (game_status != MAINMENU) InitAnimation(); button_status = MB_RELEASED; - while(result<0) + while(result < 0) { - DoAnimation(); - Delay(10000); - if (XPending(display)) { XEvent event; XNextEvent(display, &event); + switch(event.type) { - case Expose: - HandleExposeEvent((XExposeEvent *) &event); - break; - case UnmapNotify: - SleepWhileUnmapped(); - break; case ButtonPress: case ButtonRelease: case MotionNotify: { int choice; - if (event.type==MotionNotify) + if (event.type == MotionNotify) { motion_status = TRUE; mx = ((XMotionEvent *) &event)->x; @@ -913,10 +1454,12 @@ BOOL AreYouSure(char *text, unsigned int ays_state) button_status = MB_RELEASED; } - if (ays_state & AYS_ASK) - choice = CheckChooseButtons(mx,my,button_status); - else + if (req_state & REQ_ASK) + choice = CheckYesNoButtons(mx,my,button_status); + else if (req_state & REQ_CONFIRM) choice = CheckConfirmButton(mx,my,button_status); + else + choice = CheckPlayerButtons(mx,my,button_status); switch(choice) { @@ -927,56 +1470,80 @@ BOOL AreYouSure(char *text, unsigned int ays_state) result = FALSE; break; case BUTTON_CONFIRM: - result = TRUE|FALSE; + result = TRUE | FALSE; break; + + case BUTTON_PLAYER_1: + result = 1; + break; + case BUTTON_PLAYER_2: + result = 2; + break; + case BUTTON_PLAYER_3: + result = 3; + break; + case BUTTON_PLAYER_4: + result = 4; + break; + default: break; } break; } + case KeyPress: - key_status = KEY_PRESSED; switch(XLookupKeysym((XKeyEvent *)&event, ((XKeyEvent *)&event)->state)) { case XK_Return: result = 1; break; + case XK_Escape: result = 0; break; + + default: + break; } + if (req_state & REQ_PLAYER) + result = 0; break; - case FocusIn: - HandleFocusEvent(FOCUS_IN); - break; - case FocusOut: - HandleFocusEvent(FOCUS_OUT); + + case KeyRelease: + key_joystick_mapping = 0; break; + default: + HandleOtherEvents(&event); break; } } - else if (JoystickButton()==JOY_BUTTON_NEW_PRESSED) + else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED) { - int joy=Joystick(); + int joy = AnyJoystick(); if (joy & JOY_BUTTON_1) result = 1; else if (joy & JOY_BUTTON_2) result = 0; } + + DoAnimation(); + + /* don't eat all CPU time */ + Delay(10); } - if (game_status!=MAINMENU) + if (game_status != MAINMENU) StopAnimation(); - if (!(ays_state & AYS_STAY_OPEN)) + if (!(req_state & REQ_STAY_OPEN)) { CloseDoor(DOOR_CLOSE_1); - if (!(ays_state & AYS_STAY_CLOSED) && - (game_status==PLAYING || game_status==LEVELED)) + if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1)) { XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc, DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE, @@ -985,381 +1552,324 @@ BOOL AreYouSure(char *text, unsigned int ays_state) } } +#ifndef MSDOS + /* continue network game after request */ + if (options.network && + game_status == PLAYING && + req_state & REQUEST_WAIT_FOR) + SendToServer_ContinuePlaying(); +#endif + return(result); } -void OpenDoor(unsigned int door_state) +unsigned int OpenDoor(unsigned int door_state) { + unsigned int new_door_state; + if (door_state & DOOR_COPY_BACK) { - XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc, - DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1); + XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc, + DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); door_state &= ~DOOR_COPY_BACK; } - MoveDoor(door_state); - ClearEventQueue(); + new_door_state = MoveDoor(door_state); + + return(new_door_state); } -void CloseDoor(unsigned int door_state) +unsigned int CloseDoor(unsigned int door_state) { - XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc, - DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1); - XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc, - VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2); + unsigned int new_door_state; - MoveDoor(door_state); - ClearEventQueue(); + XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc, + DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); + XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc, + VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2); + + new_door_state = MoveDoor(door_state); + + return(new_door_state); +} + +unsigned int GetDoorState() +{ + return(MoveDoor(DOOR_GET_STATE)); } -void MoveDoor(unsigned int door_state) +unsigned int MoveDoor(unsigned int door_state) { static int door1 = DOOR_OPEN_1; static int door2 = DOOR_CLOSE_2; - int x, start, stepsize = 4, door_anim_delay = stepsize*5000; + static unsigned long door_delay = 0; + int x, start, stepsize = 2; + unsigned long door_delay_value = stepsize * 5; - if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1) + if (door_state == DOOR_GET_STATE) + return(door1 | door2); + + if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1) door_state &= ~DOOR_OPEN_1; - else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1) + else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1) door_state &= ~DOOR_CLOSE_1; - if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2) + if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2) door_state &= ~DOOR_OPEN_2; - else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2) + else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2) door_state &= ~DOOR_CLOSE_2; - if (quick_doors) + if (setup.quick_doors) { stepsize = 20; - door_anim_delay = 0; + door_delay_value = 0; StopSound(SND_OEFFNEN); } if (door_state & DOOR_ACTION) { if (!(door_state & DOOR_NO_DELAY)) - PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT); + PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT); start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0); - for(x=start;x<=DXSIZE;x+=stepsize) + for(x=start; x<=DXSIZE; x+=stepsize) { + WaitUntilDelayReached(&door_delay, door_delay_value); + if (door_state & DOOR_ACTION_1) { int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x); - int j = (DXSIZE - i)/3; - - XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2, - DXSIZE,DYSIZE-i/2, DX,DY); - - XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2); - - XSetClipOrigin(display,clip_gc[PIX_DOOR], - DX-i,(DY+j)-DOOR_GFX_PAGEY1); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j); - XSetClipOrigin(display,clip_gc[PIX_DOOR], - DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j)); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j); - - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63, - DX,DY+77-j); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77, - DX,DY+203-j); - XSetClipOrigin(display,clip_gc[PIX_DOOR], - DX-i,(DY+j)-DOOR_GFX_PAGEY1); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE,DOOR_GFX_PAGEY1+77, i,63, - DX+DXSIZE-i,DY+77+j); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j, - DX+DXSIZE-i,DY+203+j); + int j = (DXSIZE - i) / 3; + + XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2, + DXSIZE,DYSIZE - i/2, DX, DY); + + XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2); + + XSetClipOrigin(display, clip_gc[PIX_DOOR], + DX - i, (DY + j) - DOOR_GFX_PAGEY1); + XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR], + DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i, + DY + 140 + j); + XSetClipOrigin(display, clip_gc[PIX_DOOR], + DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j)); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j); + + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63, + DX, DY + 77 - j); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77, + DX, DY + 203 - j); + XSetClipOrigin(display, clip_gc[PIX_DOOR], + DX - i, (DY + j) - DOOR_GFX_PAGEY1); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63, + DX + DXSIZE - i, DY + 77 + j); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j, + DX + DXSIZE - i, DY + 203 + j); redraw_mask |= REDRAW_DOOR_1; } if (door_state & DOOR_ACTION_2) { - int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x); - int j = (VXSIZE - i)/3; - - XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc, - DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2, - VXSIZE,VYSIZE-i/2, VX,VY); - - XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2); - - XSetClipOrigin(display,clip_gc[PIX_DOOR], - VX-i,(VY+j)-DOOR_GFX_PAGEY2); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j); - XSetClipOrigin(display,clip_gc[PIX_DOOR], - VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j)); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY); - - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2, - VX,VY+VYSIZE/2-j); - XSetClipOrigin(display,clip_gc[PIX_DOOR], - VX-i,(VY+j)-DOOR_GFX_PAGEY2); - XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR], - VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j, - VX+VXSIZE-i,VY+VYSIZE/2+j); + int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x); + int j = (VXSIZE - i) / 3; + + XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc, + DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2, + VXSIZE, VYSIZE - i/2, VX, VY); + + XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2); + + XSetClipOrigin(display, clip_gc[PIX_DOOR], + VX - i, (VY + j) - DOOR_GFX_PAGEY2); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j); + XSetClipOrigin(display, clip_gc[PIX_DOOR], + VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j)); + XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR], + VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY); + + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2, + VX, VY + VYSIZE / 2 - j); + XSetClipOrigin(display, clip_gc[PIX_DOOR], + VX - i, (VY + j) - DOOR_GFX_PAGEY2); + XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR], + VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j, + VX + VXSIZE - i, VY + VYSIZE / 2 + j); redraw_mask |= REDRAW_DOOR_2; } BackToFront(); - Delay(door_anim_delay); - if (game_status==MAINMENU) + if (game_status == MAINMENU) DoAnimation(); } } + if (setup.quick_doors) + StopSound(SND_OEFFNEN); + if (door_state & DOOR_ACTION_1) door1 = door_state & DOOR_ACTION_1; if (door_state & DOOR_ACTION_2) door2 = door_state & DOOR_ACTION_2; + + return(door1 | door2); } int ReadPixel(Drawable d, int x, int y) { static XImage *pixelimage; - pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap); - return(XGetPixel(pixelimage,0,0)); -} - -void CheckJoystickData() -{ - int i; - int distance = 100; - - for(i=0;i<2;i++) - { - if (joystick[i].xmiddle <= distance) - joystick[i].xmiddle = distance; - if (joystick[i].ymiddle <= distance) - joystick[i].ymiddle = distance; - - if (joystick[i].xleft >= joystick[i].xmiddle) - joystick[i].xleft = joystick[i].xmiddle-distance; - if (joystick[i].xright <= joystick[i].xmiddle) - joystick[i].xright = joystick[i].xmiddle+distance; - - if (joystick[i].yupper >= joystick[i].ymiddle) - joystick[i].yupper = joystick[i].ymiddle-distance; - if (joystick[i].ylower <= joystick[i].ymiddle) - joystick[i].ylower = joystick[i].ymiddle+distance; - } -} - -int JoystickPosition(int middle, int margin, int actual) -{ - long range, pos; - int percentage; - - if (marginmiddle) - return(0); - if (margin>middle && actual100) - percentage = 100; - - return(percentage); -} - -int Joystick() -{ -#ifdef __FreeBSD__ - struct joystick joy_ctrl; -#else - struct joystick_control - { - int buttons; - int x; - int y; - } joy_ctrl; -#endif - - int js_x,js_y, js_b1,js_b2; - int left, right, up, down; - int result=0; - - if (joystick_status==JOYSTICK_OFF) - return(0); - - if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) - { - fprintf(stderr,"%s: cannot read joystick settings - no joystick support\n", - progname); - joystick_status = JOYSTICK_OFF; - return(0); - } - - js_x = joy_ctrl.x; - js_y = joy_ctrl.y; -#ifdef __FreeBSD__ - js_b1 = joy_ctrl.b1; - js_b2 = joy_ctrl.b2; -#else - js_b1 = joy_ctrl.buttons & 1; - js_b2 = joy_ctrl.buttons & 2; -#endif - - left = JoystickPosition(joystick[joystick_nr].xmiddle, - joystick[joystick_nr].xleft, js_x); - right = JoystickPosition(joystick[joystick_nr].xmiddle, - joystick[joystick_nr].xright, js_x); - up = JoystickPosition(joystick[joystick_nr].ymiddle, - joystick[joystick_nr].yupper, js_y); - down = JoystickPosition(joystick[joystick_nr].ymiddle, - joystick[joystick_nr].ylower, js_y); - - if (left>JOYSTICK_PERCENT) - result |= JOY_LEFT; - else if (right>JOYSTICK_PERCENT) - result |= JOY_RIGHT; - if (up>JOYSTICK_PERCENT) - result |= JOY_UP; - else if (down>JOYSTICK_PERCENT) - result |= JOY_DOWN; - if (js_b1) - result |= JOY_BUTTON_1; - if (js_b2) - result |= JOY_BUTTON_2; - - return(result); -} - -int JoystickButton() -{ - static int last_joy_button = 0; - int joy_button = (Joystick() & JOY_BUTTON); - int result; - - if (joy_button) - { - if (last_joy_button) - result = JOY_BUTTON_PRESSED; - else - result = JOY_BUTTON_NEW_PRESSED; - } - else - { - if (last_joy_button) - result = JOY_BUTTON_NEW_RELEASED; - else - result = JOY_BUTTON_NOT_PRESSED; - } - - last_joy_button = joy_button; - return(result); + pixelimage = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap); + return(XGetPixel(pixelimage, 0, 0)); } int el2gfx(int element) { switch(element) { - case EL_LEERRAUM: return(-1); - case EL_ERDREICH: return(GFX_ERDREICH); - case EL_MAUERWERK: return(GFX_MAUERWERK); - case EL_FELSBODEN: return(GFX_FELSBODEN); - case EL_FELSBROCKEN: return(GFX_FELSBROCKEN); - case EL_SCHLUESSEL: return(GFX_SCHLUESSEL); - case EL_EDELSTEIN: return(GFX_EDELSTEIN); - case EL_AUSGANG_ZU: return(GFX_AUSGANG_ZU); - case EL_AUSGANG_ACT: return(GFX_AUSGANG_ACT); - case EL_AUSGANG_AUF: return(GFX_AUSGANG_AUF); - case EL_SPIELFIGUR: return(GFX_SPIELFIGUR); - case EL_SPIELER1: return(GFX_SPIELER1); - case EL_SPIELER2: return(GFX_SPIELER2); - case EL_SPIELER3: return(GFX_SPIELER3); - case EL_SPIELER4: return(GFX_SPIELER4); - case EL_KAEFER: return(GFX_KAEFER); - case EL_KAEFER_R: return(GFX_KAEFER_R); - case EL_KAEFER_O: return(GFX_KAEFER_O); - case EL_KAEFER_L: return(GFX_KAEFER_L); - case EL_KAEFER_U: return(GFX_KAEFER_U); - case EL_FLIEGER: return(GFX_FLIEGER); - case EL_FLIEGER_R: return(GFX_FLIEGER_R); - case EL_FLIEGER_O: return(GFX_FLIEGER_O); - case EL_FLIEGER_L: return(GFX_FLIEGER_L); - case EL_FLIEGER_U: return(GFX_FLIEGER_U); - case EL_MAMPFER: return(GFX_MAMPFER); - case EL_ZOMBIE: return(GFX_ZOMBIE); - case EL_BETON: return(GFX_BETON); - case EL_DIAMANT: return(GFX_DIAMANT); - case EL_MORAST_LEER: return(GFX_MORAST_LEER); - case EL_MORAST_VOLL: return(GFX_MORAST_VOLL); - case EL_TROPFEN: return(GFX_TROPFEN); - case EL_BOMBE: return(GFX_BOMBE); - case EL_SIEB_LEER: return(GFX_SIEB_LEER); - case EL_SIEB_VOLL: return(GFX_SIEB_VOLL); - case EL_SIEB_TOT: return(GFX_SIEB_TOT); - case EL_SALZSAEURE: return(GFX_SALZSAEURE); - case EL_AMOEBE_TOT: return(GFX_AMOEBE_TOT); - case EL_AMOEBE_NASS: return(GFX_AMOEBE_NASS); - case EL_AMOEBE_NORM: return(GFX_AMOEBE_NORM); - case EL_AMOEBE_VOLL: return(GFX_AMOEBE_VOLL); - case EL_AMOEBA2DIAM: return(GFX_AMOEBA2DIAM); - case EL_KOKOSNUSS: return(GFX_KOKOSNUSS); - case EL_LIFE: return(GFX_LIFE); - case EL_LIFE_ASYNC: return(GFX_LIFE_ASYNC); - case EL_DYNAMIT: return(GFX_DYNAMIT); - case EL_BADEWANNE: return(GFX_BADEWANNE); - case EL_BADEWANNE1: return(GFX_BADEWANNE1); - case EL_BADEWANNE2: return(GFX_BADEWANNE2); - case EL_BADEWANNE3: return(GFX_BADEWANNE3); - case EL_BADEWANNE4: return(GFX_BADEWANNE4); - case EL_BADEWANNE5: return(GFX_BADEWANNE5); - case EL_ABLENK_AUS: return(GFX_ABLENK_AUS); - case EL_ABLENK_EIN: return(GFX_ABLENK_EIN); - case EL_SCHLUESSEL1: return(GFX_SCHLUESSEL1); - case EL_SCHLUESSEL2: return(GFX_SCHLUESSEL2); - case EL_SCHLUESSEL3: return(GFX_SCHLUESSEL3); - case EL_SCHLUESSEL4: return(GFX_SCHLUESSEL4); - case EL_PFORTE1: return(GFX_PFORTE1); - case EL_PFORTE2: return(GFX_PFORTE2); - case EL_PFORTE3: return(GFX_PFORTE3); - case EL_PFORTE4: return(GFX_PFORTE4); - case EL_PFORTE1X: return(GFX_PFORTE1X); - case EL_PFORTE2X: return(GFX_PFORTE2X); - case EL_PFORTE3X: return(GFX_PFORTE3X); - case EL_PFORTE4X: return(GFX_PFORTE4X); - case EL_DYNAMIT_AUS: return(GFX_DYNAMIT_AUS); - case EL_PACMAN: return(GFX_PACMAN); - case EL_PACMAN_R: return(GFX_PACMAN_R); - case EL_PACMAN_O: return(GFX_PACMAN_O); - case EL_PACMAN_L: return(GFX_PACMAN_L); - case EL_PACMAN_U: return(GFX_PACMAN_U); - case EL_UNSICHTBAR: return(GFX_UNSICHTBAR); - case EL_ERZ_EDEL: return(GFX_ERZ_EDEL); - case EL_ERZ_DIAM: return(GFX_ERZ_DIAM); - case EL_BIRNE_AUS: return(GFX_BIRNE_AUS); - case EL_BIRNE_EIN: return(GFX_BIRNE_EIN); - case EL_ZEIT_VOLL: return(GFX_ZEIT_VOLL); - case EL_ZEIT_LEER: return(GFX_ZEIT_LEER); + case EL_LEERRAUM: return -1; + case EL_ERDREICH: return GFX_ERDREICH; + case EL_MAUERWERK: return GFX_MAUERWERK; + case EL_FELSBODEN: return GFX_FELSBODEN; + case EL_FELSBROCKEN: return GFX_FELSBROCKEN; + case EL_SCHLUESSEL: return GFX_SCHLUESSEL; + case EL_EDELSTEIN: return GFX_EDELSTEIN; + case EL_AUSGANG_ZU: return GFX_AUSGANG_ZU; + case EL_AUSGANG_ACT: return GFX_AUSGANG_ACT; + case EL_AUSGANG_AUF: return GFX_AUSGANG_AUF; + case EL_SPIELFIGUR: return GFX_SPIELFIGUR; + case EL_SPIELER1: return GFX_SPIELER1; + case EL_SPIELER2: return GFX_SPIELER2; + case EL_SPIELER3: return GFX_SPIELER3; + case EL_SPIELER4: return GFX_SPIELER4; + case EL_KAEFER: return GFX_KAEFER; + case EL_KAEFER_R: return GFX_KAEFER_R; + case EL_KAEFER_O: return GFX_KAEFER_O; + case EL_KAEFER_L: return GFX_KAEFER_L; + case EL_KAEFER_U: return GFX_KAEFER_U; + case EL_FLIEGER: return GFX_FLIEGER; + case EL_FLIEGER_R: return GFX_FLIEGER_R; + case EL_FLIEGER_O: return GFX_FLIEGER_O; + case EL_FLIEGER_L: return GFX_FLIEGER_L; + case EL_FLIEGER_U: return GFX_FLIEGER_U; + case EL_BUTTERFLY: return GFX_BUTTERFLY; + case EL_BUTTERFLY_R: return GFX_BUTTERFLY_R; + case EL_BUTTERFLY_O: return GFX_BUTTERFLY_O; + case EL_BUTTERFLY_L: return GFX_BUTTERFLY_L; + case EL_BUTTERFLY_U: return GFX_BUTTERFLY_U; + case EL_FIREFLY: return GFX_FIREFLY; + case EL_FIREFLY_R: return GFX_FIREFLY_R; + case EL_FIREFLY_O: return GFX_FIREFLY_O; + case EL_FIREFLY_L: return GFX_FIREFLY_L; + case EL_FIREFLY_U: return GFX_FIREFLY_U; + case EL_MAMPFER: return GFX_MAMPFER; + case EL_ROBOT: return GFX_ROBOT; + case EL_BETON: return GFX_BETON; + case EL_DIAMANT: return GFX_DIAMANT; + case EL_MORAST_LEER: return GFX_MORAST_LEER; + case EL_MORAST_VOLL: return GFX_MORAST_VOLL; + case EL_TROPFEN: return GFX_TROPFEN; + case EL_BOMBE: return GFX_BOMBE; + case EL_SIEB_LEER: return GFX_SIEB_LEER; + case EL_SIEB_VOLL: return GFX_SIEB_VOLL; + case EL_SIEB_TOT: return GFX_SIEB_TOT; + case EL_SALZSAEURE: return GFX_SALZSAEURE; + case EL_AMOEBE_TOT: return GFX_AMOEBE_TOT; + case EL_AMOEBE_NASS: return GFX_AMOEBE_NASS; + case EL_AMOEBE_NORM: return GFX_AMOEBE_NORM; + case EL_AMOEBE_VOLL: return GFX_AMOEBE_VOLL; + case EL_AMOEBE_BD: return GFX_AMOEBE_BD; + case EL_AMOEBA2DIAM: return GFX_AMOEBA2DIAM; + case EL_KOKOSNUSS: return GFX_KOKOSNUSS; + case EL_LIFE: return GFX_LIFE; + case EL_LIFE_ASYNC: return GFX_LIFE_ASYNC; + case EL_DYNAMIT: return GFX_DYNAMIT; + case EL_BADEWANNE: return GFX_BADEWANNE; + case EL_BADEWANNE1: return GFX_BADEWANNE1; + case EL_BADEWANNE2: return GFX_BADEWANNE2; + case EL_BADEWANNE3: return GFX_BADEWANNE3; + case EL_BADEWANNE4: return GFX_BADEWANNE4; + case EL_BADEWANNE5: return GFX_BADEWANNE5; + case EL_ABLENK_AUS: return GFX_ABLENK_AUS; + case EL_ABLENK_EIN: return GFX_ABLENK_EIN; + case EL_SCHLUESSEL1: return GFX_SCHLUESSEL1; + case EL_SCHLUESSEL2: return GFX_SCHLUESSEL2; + case EL_SCHLUESSEL3: return GFX_SCHLUESSEL3; + case EL_SCHLUESSEL4: return GFX_SCHLUESSEL4; + case EL_PFORTE1: return GFX_PFORTE1; + case EL_PFORTE2: return GFX_PFORTE2; + case EL_PFORTE3: return GFX_PFORTE3; + case EL_PFORTE4: return GFX_PFORTE4; + case EL_PFORTE1X: return GFX_PFORTE1X; + case EL_PFORTE2X: return GFX_PFORTE2X; + case EL_PFORTE3X: return GFX_PFORTE3X; + case EL_PFORTE4X: return GFX_PFORTE4X; + case EL_DYNAMIT_AUS: return GFX_DYNAMIT_AUS; + case EL_PACMAN: return GFX_PACMAN; + case EL_PACMAN_R: return GFX_PACMAN_R; + case EL_PACMAN_O: return GFX_PACMAN_O; + case EL_PACMAN_L: return GFX_PACMAN_L; + case EL_PACMAN_U: return GFX_PACMAN_U; + case EL_UNSICHTBAR: return GFX_UNSICHTBAR; + case EL_ERZ_EDEL: return GFX_ERZ_EDEL; + case EL_ERZ_DIAM: return GFX_ERZ_DIAM; + case EL_BIRNE_AUS: return GFX_BIRNE_AUS; + case EL_BIRNE_EIN: return GFX_BIRNE_EIN; + case EL_ZEIT_VOLL: return GFX_ZEIT_VOLL; + case EL_ZEIT_LEER: return GFX_ZEIT_LEER; + case EL_MAUER_LEBT: return GFX_MAUER_LEBT; + case EL_MAUER_X: return GFX_MAUER_X; + case EL_MAUER_Y: return GFX_MAUER_Y; + case EL_MAUER_XY: return GFX_MAUER_XY; + case EL_EDELSTEIN_BD: return GFX_EDELSTEIN_BD; + case EL_EDELSTEIN_GELB: return GFX_EDELSTEIN_GELB; + case EL_EDELSTEIN_ROT: return GFX_EDELSTEIN_ROT; + case EL_EDELSTEIN_LILA: return GFX_EDELSTEIN_LILA; + case EL_ERZ_EDEL_BD: return GFX_ERZ_EDEL_BD; + case EL_ERZ_EDEL_GELB: return GFX_ERZ_EDEL_GELB; + case EL_ERZ_EDEL_ROT: return GFX_ERZ_EDEL_ROT; + case EL_ERZ_EDEL_LILA: return GFX_ERZ_EDEL_LILA; + case EL_MAMPFER2: return GFX_MAMPFER2; + case EL_SIEB2_LEER: return GFX_SIEB2_LEER; + case EL_SIEB2_VOLL: return GFX_SIEB2_VOLL; + case EL_SIEB2_TOT: return GFX_SIEB2_TOT; + case EL_DYNABOMB: return GFX_DYNABOMB; + case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR; + case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ; + case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL; + case EL_SOKOBAN_OBJEKT: return GFX_SOKOBAN_OBJEKT; + case EL_SOKOBAN_FELD_LEER: return GFX_SOKOBAN_FELD_LEER; + case EL_SOKOBAN_FELD_VOLL: return GFX_SOKOBAN_FELD_VOLL; + case EL_MAULWURF: return GFX_MAULWURF; + case EL_PINGUIN: return GFX_PINGUIN; + case EL_SCHWEIN: return GFX_SCHWEIN; + case EL_DRACHE: return GFX_DRACHE; + case EL_SONDE: return GFX_SONDE; + case EL_PFEIL_L: return GFX_PFEIL_L; + case EL_PFEIL_R: return GFX_PFEIL_R; + case EL_PFEIL_O: return GFX_PFEIL_O; + case EL_PFEIL_U: return GFX_PFEIL_U; default: { if (IS_CHAR(element)) - return(GFX_CHAR_START + (element-EL_CHAR_START)); + return GFX_CHAR_START + (element - EL_CHAR_START); else - return(-1); + return -1; } } } diff --git a/src/tools.h b/src/tools.h index bec22056..6d708520 100644 --- a/src/tools.h +++ b/src/tools.h @@ -1,13 +1,12 @@ /*********************************************************** * Rocks'n'Diamonds -- McDuffin Strikes Back! * *----------------------------------------------------------* -* ©1995 Artsoft Development * -* Holger Schemel * -* 33659 Bielefeld-Senne * -* Telefon: (0521) 493245 * -* eMail: aeglos@valinor.owl.de * -* aeglos@uni-paderborn.de * -* q99492@pbhrzx.uni-paderborn.de * +* (c) 1995-98 Artsoft Entertainment * +* Holger Schemel * +* Oststrasse 11a * +* 33604 Bielefeld * +* phone: ++49 +521 290471 * +* email: aeglos@valinor.owl.de * *----------------------------------------------------------* * tools.h * ***********************************************************/ @@ -15,53 +14,79 @@ #ifndef TOOLS_H #define TOOLS_H +#include #include "main.h" -#include +/* for SetDrawtoField */ +#define DRAW_DIRECT 0 +#define DRAW_BUFFERED 1 +#define DRAW_BACKBUFFER 2 + +/* for DrawElementShifted */ +#define NO_CUTTING 0 +#define CUT_ABOVE (1 << 0) +#define CUT_BELOW (1 << 1) +#define CUT_LEFT (1 << 2) +#define CUT_RIGHT (1 << 3) -/* für DrawElementShifted */ -#define CUT_NO_CUTTING 0 -#define CUT_ABOVE 1 -#define CUT_BELOW 2 -#define CUT_LEFT 4 -#define CUT_RIGHT 8 +/* for masking functions */ +#define NO_MASKING 0 +#define USE_MASKING 1 + +/* for MoveDoor */ +#define DOOR_OPEN_1 (1 << 0) +#define DOOR_OPEN_2 (1 << 1) +#define DOOR_CLOSE_1 (1 << 2) +#define DOOR_CLOSE_2 (1 << 3) +#define DOOR_OPEN_BOTH (DOOR_OPEN_1 | DOOR_OPEN_2) +#define DOOR_CLOSE_BOTH (DOOR_CLOSE_1 | DOOR_CLOSE_2) +#define DOOR_ACTION_1 (DOOR_OPEN_1 | DOOR_CLOSE_1) +#define DOOR_ACTION_2 (DOOR_OPEN_2 | DOOR_CLOSE_2) +#define DOOR_ACTION (DOOR_ACTION_1 | DOOR_ACTION_2) +#define DOOR_COPY_BACK (1 << 4) +#define DOOR_NO_DELAY (1 << 5) +#define DOOR_GET_STATE (1 << 6) -/* für MoveDoor */ -#define DOOR_OPEN_1 1 -#define DOOR_OPEN_2 2 -#define DOOR_CLOSE_1 4 -#define DOOR_CLOSE_2 8 -#define DOOR_OPEN_BOTH (DOOR_OPEN_1 | DOOR_OPEN_2) -#define DOOR_CLOSE_BOTH (DOOR_CLOSE_1 | DOOR_CLOSE_2) -#define DOOR_ACTION_1 (DOOR_OPEN_1 | DOOR_CLOSE_1) -#define DOOR_ACTION_2 (DOOR_OPEN_2 | DOOR_CLOSE_2) -#define DOOR_ACTION (DOOR_ACTION_1 | DOOR_ACTION_2) -#define DOOR_COPY_BACK 16 -#define DOOR_NO_DELAY 32 +/* for Request */ +#define REQ_ASK (1 << 0) +#define REQ_OPEN (1 << 1) +#define REQ_CLOSE (1 << 2) +#define REQ_CONFIRM (1 << 3) +#define REQ_STAY_CLOSED (1 << 4) +#define REQ_STAY_OPEN (1 << 5) +#define REQ_PLAYER (1 << 6) -/* für AreYouSure */ -#define AYS_ASK 1 -#define AYS_OPEN 2 -#define AYS_CLOSE 4 -#define AYS_CONFIRM 8 -#define AYS_STAY_CLOSED 16 -#define AYS_STAY_OPEN 32 +#define REQUEST_WAIT_FOR (REQ_ASK | REQ_CONFIRM | REQ_PLAYER) +void SetDrawtoField(int); void BackToFront(); void FadeToFront(); void ClearWindow(); +void DrawTextF(int, int, int, char *, ...); +void DrawTextFCentered(int, int, char *, ...); void DrawText(int, int, char *, int, int); void DrawTextExt(Drawable, GC, int, int, char *, int, int); +void DrawAllPlayers(void); +void DrawPlayerField(int, int); +void DrawPlayer(struct PlayerInfo *); +void DrawGraphicAnimationExt(int, int, int, int, int, int, int); +void DrawGraphicAnimation(int, int, int, int, int, int); +void DrawGraphicAnimationThruMask(int, int, int, int, int, int); void DrawGraphic(int, int, int); void DrawGraphicExt(Drawable, GC, int, int, int); -void DrawGraphicExtHiRes(Drawable, GC, int, int, int); void DrawGraphicThruMask(int, int, int); -void DrawElementThruMask(int, int, int); +void DrawGraphicThruMaskExt(Drawable, int, int, int); void DrawMiniGraphic(int, int, int); void DrawMiniGraphicExt(Drawable, GC, int, int, int); -void DrawMiniGraphicExtHiRes(Drawable, GC, int, int, int); -void DrawGraphicShifted(int, int, int, int, int, int); -void DrawElementShifted(int, int, int, int, int, int); +void DrawGraphicShifted(int, int, int, int, int, int, int); +void DrawGraphicShiftedThruMask(int, int, int, int, int, int); +void DrawScreenElementExt(int, int, int, int, int, int, int); +void DrawLevelElementExt(int, int, int, int, int, int, int); +void DrawScreenElementShifted(int, int, int, int, int, int); +void DrawLevelElementShifted(int, int, int, int, int, int); +void DrawScreenElementThruMask(int, int, int); +void DrawLevelElementThruMask(int, int, int); +void DrawLevelFieldThruMask(int, int); void ErdreichAnbroeckeln(int, int); void DrawScreenElement(int, int, int); void DrawLevelElement(int, int, int); @@ -73,15 +98,12 @@ void DrawMicroElement(int, int, int); void DrawLevel(void); void DrawMiniLevel(int, int); void DrawMicroLevel(int, int); -BOOL AreYouSure(char *, unsigned int); -void OpenDoor(unsigned int); -void CloseDoor(unsigned int); -void MoveDoor(unsigned int); +boolean Request(char *, unsigned int); +unsigned int OpenDoor(unsigned int); +unsigned int CloseDoor(unsigned int); +unsigned int GetDoorState(void); +unsigned int MoveDoor(unsigned int); int ReadPixel(Drawable, int, int); -void CheckJoystickData(void); -int JoystickPosition(int, int, int); -int Joystick(void); -int JoystickButton(void); int el2gfx(int); #endif